Mercurial > dwindows
comparison ios/dw.m @ 2372:df0a66945296
iOS: Initial commit of iOS source... based on MacOS code...
Doesn't build yet... but wanted to commit it so I can change locations.
author | bsmith@81767d24-ef19-dc11-ae90-00e081727c95 |
---|---|
date | Tue, 16 Mar 2021 22:52:53 +0000 |
parents | |
children | 8d6ab1f46a29 |
comparison
equal
deleted
inserted
replaced
2371:67f98f3e47f4 | 2372:df0a66945296 |
---|---|
1 /* | |
2 * Dynamic Windows: | |
3 * A GTK like implementation of the iOS GUI | |
4 * | |
5 * (C) 2011-2021 Brian Smith <brian@dbsoft.org> | |
6 * (C) 2011-2018 Mark Hessling <mark@rexx.org> | |
7 * | |
8 * Requires 10.0 or later. | |
9 * clang -g -o dwtest -D__IOS__ -I. dwtest.c ios/dw.m -framework UIKit -framework WebKit -framework Foundation -framework UserNotifications | |
10 */ | |
11 #import <Foundation/Foundation.h> | |
12 #import <UIKit/UIKit.h> | |
13 #import <WebKit/WebKit.h> | |
14 #import <UserNotifications/UserNotifications.h> | |
15 #include "dw.h" | |
16 #include <sys/utsname.h> | |
17 #include <sys/socket.h> | |
18 #include <sys/un.h> | |
19 #include <sys/mman.h> | |
20 #include <sys/time.h> | |
21 #include <sys/stat.h> | |
22 #include <math.h> | |
23 | |
24 /* Macros to encapsulate running functions on the main thread */ | |
25 #define DW_FUNCTION_INIT | |
26 #define DW_FUNCTION_DEFINITION(func, rettype, ...) void _##func(NSPointerArray *_args); \ | |
27 rettype API func(__VA_ARGS__) { \ | |
28 DW_LOCAL_POOL_IN; \ | |
29 NSPointerArray *_args = [[NSPointerArray alloc] initWithOptions:NSPointerFunctionsOpaqueMemory]; \ | |
30 [_args addPointer:(void *)_##func]; | |
31 #define DW_FUNCTION_ADD_PARAM1(param1) [_args addPointer:(void *)¶m1]; | |
32 #define DW_FUNCTION_ADD_PARAM2(param1, param2) [_args addPointer:(void *)¶m1]; \ | |
33 [_args addPointer:(void *)¶m2]; | |
34 #define DW_FUNCTION_ADD_PARAM3(param1, param2, param3) [_args addPointer:(void *)¶m1]; \ | |
35 [_args addPointer:(void *)¶m2]; \ | |
36 [_args addPointer:(void *)¶m3]; | |
37 #define DW_FUNCTION_ADD_PARAM4(param1, param2, param3, param4) [_args addPointer:(void *)¶m1]; \ | |
38 [_args addPointer:(void *)¶m2]; \ | |
39 [_args addPointer:(void *)¶m3]; \ | |
40 [_args addPointer:(void *)¶m4]; | |
41 #define DW_FUNCTION_ADD_PARAM5(param1, param2, param3, param4, param5) [_args addPointer:(void *)¶m1]; \ | |
42 [_args addPointer:(void *)¶m2]; \ | |
43 [_args addPointer:(void *)¶m3]; \ | |
44 [_args addPointer:(void *)¶m4]; \ | |
45 [_args addPointer:(void *)¶m5]; | |
46 #define DW_FUNCTION_ADD_PARAM6(param1, param2, param3, param4, param5, param6) \ | |
47 [_args addPointer:(void *)¶m1]; \ | |
48 [_args addPointer:(void *)¶m2]; \ | |
49 [_args addPointer:(void *)¶m3]; \ | |
50 [_args addPointer:(void *)¶m4]; \ | |
51 [_args addPointer:(void *)¶m5]; \ | |
52 [_args addPointer:(void *)¶m6]; | |
53 #define DW_FUNCTION_ADD_PARAM7(param1, param2, param3, param4, param5, param6, param7) \ | |
54 [_args addPointer:(void *)¶m1]; \ | |
55 [_args addPointer:(void *)¶m2]; \ | |
56 [_args addPointer:(void *)¶m3]; \ | |
57 [_args addPointer:(void *)¶m4]; \ | |
58 [_args addPointer:(void *)¶m5]; \ | |
59 [_args addPointer:(void *)¶m6]; \ | |
60 [_args addPointer:(void *)¶m7]; | |
61 #define DW_FUNCTION_ADD_PARAM8(param1, param2, param3, param4, param5, param6, param7, param8) \ | |
62 [_args addPointer:(void *)¶m1]; \ | |
63 [_args addPointer:(void *)¶m2]; \ | |
64 [_args addPointer:(void *)¶m3]; \ | |
65 [_args addPointer:(void *)¶m4]; \ | |
66 [_args addPointer:(void *)¶m5]; \ | |
67 [_args addPointer:(void *)¶m6]; \ | |
68 [_args addPointer:(void *)¶m7]; \ | |
69 [_args addPointer:(void *)¶m8]; | |
70 #define DW_FUNCTION_ADD_PARAM9(param1, param2, param3, param4, param5, param6, param7, param8, param9) \ | |
71 [_args addPointer:(void *)¶m1]; \ | |
72 [_args addPointer:(void *)¶m2]; \ | |
73 [_args addPointer:(void *)¶m3]; \ | |
74 [_args addPointer:(void *)¶m4]; \ | |
75 [_args addPointer:(void *)¶m5]; \ | |
76 [_args addPointer:(void *)¶m6]; \ | |
77 [_args addPointer:(void *)¶m7]; \ | |
78 [_args addPointer:(void *)¶m8]; \ | |
79 [_args addPointer:(void *)¶m9]; | |
80 #define DW_FUNCTION_RESTORE_PARAM1(param1, vartype1) vartype1 param1 = *((vartype1 *)[_args pointerAtIndex:1]); | |
81 #define DW_FUNCTION_RESTORE_PARAM2(param1, vartype1, param2, vartype2) \ | |
82 vartype1 param1 = *((vartype1 *)[_args pointerAtIndex:1]); \ | |
83 vartype2 param2 = *((vartype2 *)[_args pointerAtIndex:2]); | |
84 #define DW_FUNCTION_RESTORE_PARAM3(param1, vartype1, param2, vartype2, param3, vartype3) \ | |
85 vartype1 param1 = *((vartype1 *)[_args pointerAtIndex:1]); \ | |
86 vartype2 param2 = *((vartype2 *)[_args pointerAtIndex:2]); \ | |
87 vartype3 param3 = *((vartype3 *)[_args pointerAtIndex:3]); | |
88 #define DW_FUNCTION_RESTORE_PARAM4(param1, vartype1, param2, vartype2, param3, vartype3, param4, vartype4) \ | |
89 vartype1 param1 = *((vartype1 *)[_args pointerAtIndex:1]); \ | |
90 vartype2 param2 = *((vartype2 *)[_args pointerAtIndex:2]); \ | |
91 vartype3 param3 = *((vartype3 *)[_args pointerAtIndex:3]); \ | |
92 vartype4 param4 = *((vartype4 *)[_args pointerAtIndex:4]); | |
93 #define DW_FUNCTION_RESTORE_PARAM5(param1, vartype1, param2, vartype2, param3, vartype3, param4, vartype4, param5, vartype5) \ | |
94 vartype1 param1 = *((vartype1 *)[_args pointerAtIndex:1]); \ | |
95 vartype2 param2 = *((vartype2 *)[_args pointerAtIndex:2]); \ | |
96 vartype3 param3 = *((vartype3 *)[_args pointerAtIndex:3]); \ | |
97 vartype4 param4 = *((vartype4 *)[_args pointerAtIndex:4]); \ | |
98 vartype5 param5 = *((vartype5 *)[_args pointerAtIndex:5]); | |
99 #define DW_FUNCTION_RESTORE_PARAM6(param1, vartype1, param2, vartype2, param3, vartype3, param4, vartype4, param5, vartype5, param6, vartype6) \ | |
100 vartype1 param1 = *((vartype1 *)[_args pointerAtIndex:1]); \ | |
101 vartype2 param2 = *((vartype2 *)[_args pointerAtIndex:2]); \ | |
102 vartype3 param3 = *((vartype3 *)[_args pointerAtIndex:3]); \ | |
103 vartype4 param4 = *((vartype4 *)[_args pointerAtIndex:4]); \ | |
104 vartype5 param5 = *((vartype5 *)[_args pointerAtIndex:5]); \ | |
105 vartype6 param6 = *((vartype6 *)[_args pointerAtIndex:6]); | |
106 #define DW_FUNCTION_RESTORE_PARAM7(param1, vartype1, param2, vartype2, param3, vartype3, param4, vartype4, param5, vartype5, param6, vartype6, param7, vartype7) \ | |
107 vartype1 param1 = *((vartype1 *)[_args pointerAtIndex:1]); \ | |
108 vartype2 param2 = *((vartype2 *)[_args pointerAtIndex:2]); \ | |
109 vartype3 param3 = *((vartype3 *)[_args pointerAtIndex:3]); \ | |
110 vartype4 param4 = *((vartype4 *)[_args pointerAtIndex:4]); \ | |
111 vartype5 param5 = *((vartype5 *)[_args pointerAtIndex:5]); \ | |
112 vartype6 param6 = *((vartype6 *)[_args pointerAtIndex:6]); \ | |
113 vartype7 param7 = *((vartype7 *)[_args pointerAtIndex:7]); | |
114 #define DW_FUNCTION_RESTORE_PARAM8(param1, vartype1, param2, vartype2, param3, vartype3, param4, vartype4, param5, vartype5, param6, vartype6, param7, vartype7, param8, vartype8) \ | |
115 vartype1 param1 = *((vartype1 *)[_args pointerAtIndex:1]); \ | |
116 vartype2 param2 = *((vartype2 *)[_args pointerAtIndex:2]); \ | |
117 vartype3 param3 = *((vartype3 *)[_args pointerAtIndex:3]); \ | |
118 vartype4 param4 = *((vartype4 *)[_args pointerAtIndex:4]); \ | |
119 vartype5 param5 = *((vartype5 *)[_args pointerAtIndex:5]); \ | |
120 vartype6 param6 = *((vartype6 *)[_args pointerAtIndex:6]); \ | |
121 vartype7 param7 = *((vartype7 *)[_args pointerAtIndex:7]); \ | |
122 vartype8 param8 = *((vartype8 *)[_args pointerAtIndex:8]); | |
123 #define DW_FUNCTION_RESTORE_PARAM9(param1, vartype1, param2, vartype2, param3, vartype3, param4, vartype4, param5, vartype5, param6, vartype6, param7, vartype7, param8, vartype8, param9, vartype9) \ | |
124 vartype1 param1 = *((vartype1 *)[_args pointerAtIndex:1]); \ | |
125 vartype2 param2 = *((vartype2 *)[_args pointerAtIndex:2]); \ | |
126 vartype3 param3 = *((vartype3 *)[_args pointerAtIndex:3]); \ | |
127 vartype4 param4 = *((vartype4 *)[_args pointerAtIndex:4]); \ | |
128 vartype5 param5 = *((vartype5 *)[_args pointerAtIndex:5]); \ | |
129 vartype6 param6 = *((vartype6 *)[_args pointerAtIndex:6]); \ | |
130 vartype7 param7 = *((vartype7 *)[_args pointerAtIndex:7]); \ | |
131 vartype8 param8 = *((vartype8 *)[_args pointerAtIndex:8]); \ | |
132 vartype9 param9 = *((vartype9 *)[_args pointerAtIndex:9]); | |
133 #define DW_FUNCTION_END } | |
134 #define DW_FUNCTION_NO_RETURN(func) [DWObj safeCall:@selector(callBack:) withObject:_args]; \ | |
135 [_args release]; \ | |
136 DW_LOCAL_POOL_OUT; } \ | |
137 void _##func(NSPointerArray *_args) { | |
138 #define DW_FUNCTION_RETURN(func, rettype) [DWObj safeCall:@selector(callBack:) withObject:_args]; {\ | |
139 void *tmp = [_args pointerAtIndex:[_args count]-1]; \ | |
140 rettype myreturn = *((rettype *)tmp); \ | |
141 free(tmp); \ | |
142 return myreturn; } \ | |
143 [_args release]; \ | |
144 DW_LOCAL_POOL_OUT; } \ | |
145 void _##func(NSPointerArray *_args) { | |
146 #define DW_FUNCTION_RETURN_THIS(_retvar) { void *_myreturn = malloc(sizeof(_retvar)); \ | |
147 memcpy(_myreturn, (void *)&_retvar, sizeof(_retvar)); \ | |
148 [_args addPointer:_myreturn]; }} | |
149 #define DW_FUNCTION_RETURN_NOTHING } | |
150 | |
151 unsigned long _colors[] = | |
152 { | |
153 0x00000000, /* 0 black */ | |
154 0x000000bb, /* 1 red */ | |
155 0x0000bb00, /* 2 green */ | |
156 0x0000aaaa, /* 3 yellow */ | |
157 0x00cc0000, /* 4 blue */ | |
158 0x00bb00bb, /* 5 magenta */ | |
159 0x00bbbb00, /* 6 cyan */ | |
160 0x00bbbbbb, /* 7 white */ | |
161 0x00777777, /* 8 grey */ | |
162 0x000000ff, /* 9 bright red */ | |
163 0x0000ff00, /* 10 bright green */ | |
164 0x0000eeee, /* 11 bright yellow */ | |
165 0x00ff0000, /* 12 bright blue */ | |
166 0x00ff00ff, /* 13 bright magenta */ | |
167 0x00eeee00, /* 14 bright cyan */ | |
168 0x00ffffff, /* 15 bright white */ | |
169 0xff000000 /* 16 default color */ | |
170 }; | |
171 | |
172 /* | |
173 * List those icons that have transparency first | |
174 */ | |
175 #define NUM_EXTS 8 | |
176 char *image_exts[NUM_EXTS] = | |
177 { | |
178 ".png", | |
179 ".ico", | |
180 ".icns", | |
181 ".gif", | |
182 ".jpg", | |
183 ".jpeg", | |
184 ".tiff", | |
185 ".bmp" | |
186 }; | |
187 | |
188 char *_dw_get_image_extension(const char *filename) | |
189 { | |
190 char *file = alloca(strlen(filename) + 6); | |
191 int found_ext = 0,i; | |
192 | |
193 /* Try various extentions */ | |
194 for ( i = 0; i < NUM_EXTS; i++ ) | |
195 { | |
196 strcpy( file, filename ); | |
197 strcat( file, image_exts[i] ); | |
198 if ( access( file, R_OK ) == 0 ) | |
199 { | |
200 found_ext = 1; | |
201 break; | |
202 } | |
203 } | |
204 if ( found_ext == 1 ) | |
205 { | |
206 return image_exts[i]; | |
207 } | |
208 return NULL; | |
209 } | |
210 | |
211 /* Return the RGB color regardless if a predefined color was passed */ | |
212 unsigned long _get_color(unsigned long thiscolor) | |
213 { | |
214 if(thiscolor & DW_RGB_COLOR) | |
215 { | |
216 return thiscolor & ~DW_RGB_COLOR; | |
217 } | |
218 else if(thiscolor < 17) | |
219 { | |
220 return _colors[thiscolor]; | |
221 } | |
222 return 0; | |
223 } | |
224 | |
225 /* Thread specific storage */ | |
226 pthread_key_t _dw_pool_key; | |
227 pthread_key_t _dw_fg_color_key; | |
228 pthread_key_t _dw_bg_color_key; | |
229 int DWOSMajor, DWOSMinor, DWOSBuild; | |
230 static char _dw_bundle_path[PATH_MAX+1] = { 0 }; | |
231 static char _dw_app_id[_DW_APP_ID_SIZE+1]= {0}; | |
232 | |
233 /* Create a default colors for a thread */ | |
234 void _init_colors(void) | |
235 { | |
236 UIColor *fgcolor = [[UIColor grayColor] retain]; | |
237 pthread_setspecific(_dw_fg_color_key, fgcolor); | |
238 pthread_setspecific(_dw_bg_color_key, NULL); | |
239 } | |
240 | |
241 typedef struct _sighandler | |
242 { | |
243 struct _sighandler *next; | |
244 ULONG message; | |
245 HWND window; | |
246 int id; | |
247 void *signalfunction; | |
248 void *discfunction; | |
249 void *data; | |
250 | |
251 } SignalHandler; | |
252 | |
253 SignalHandler *Root = NULL; | |
254 | |
255 /* Some internal prototypes */ | |
256 static void _do_resize(Box *thisbox, int x, int y); | |
257 void _handle_resize_events(Box *thisbox); | |
258 int _remove_userdata(UserData **root, const char *varname, int all); | |
259 int _dw_main_iteration(NSDate *date); | |
260 CGContextRef _dw_draw_context(NSBitmapImageRep *image); | |
261 typedef id (*DWIMP)(id, SEL, ...); | |
262 | |
263 /* Internal function to queue a window redraw */ | |
264 void _dw_redraw(id window, int skip) | |
265 { | |
266 static id lastwindow = nil; | |
267 id redraw = lastwindow; | |
268 | |
269 if(skip && window == nil) | |
270 return; | |
271 | |
272 lastwindow = window; | |
273 if(redraw != lastwindow && redraw != nil) | |
274 { | |
275 dw_window_redraw(redraw); | |
276 } | |
277 } | |
278 | |
279 SignalHandler *_get_handler(HWND window, int messageid) | |
280 { | |
281 SignalHandler *tmp = Root; | |
282 | |
283 /* Find any callbacks for this function */ | |
284 while(tmp) | |
285 { | |
286 if(tmp->message == messageid && window == tmp->window) | |
287 { | |
288 return tmp; | |
289 } | |
290 tmp = tmp->next; | |
291 } | |
292 return NULL; | |
293 } | |
294 | |
295 typedef struct | |
296 { | |
297 ULONG message; | |
298 char name[30]; | |
299 | |
300 } SignalList; | |
301 | |
302 /* List of signals */ | |
303 #define SIGNALMAX 19 | |
304 | |
305 SignalList SignalTranslate[SIGNALMAX] = { | |
306 { 1, DW_SIGNAL_CONFIGURE }, | |
307 { 2, DW_SIGNAL_KEY_PRESS }, | |
308 { 3, DW_SIGNAL_BUTTON_PRESS }, | |
309 { 4, DW_SIGNAL_BUTTON_RELEASE }, | |
310 { 5, DW_SIGNAL_MOTION_NOTIFY }, | |
311 { 6, DW_SIGNAL_DELETE }, | |
312 { 7, DW_SIGNAL_EXPOSE }, | |
313 { 8, DW_SIGNAL_CLICKED }, | |
314 { 9, DW_SIGNAL_ITEM_ENTER }, | |
315 { 10, DW_SIGNAL_ITEM_CONTEXT }, | |
316 { 11, DW_SIGNAL_LIST_SELECT }, | |
317 { 12, DW_SIGNAL_ITEM_SELECT }, | |
318 { 13, DW_SIGNAL_SET_FOCUS }, | |
319 { 14, DW_SIGNAL_VALUE_CHANGED }, | |
320 { 15, DW_SIGNAL_SWITCH_PAGE }, | |
321 { 16, DW_SIGNAL_TREE_EXPAND }, | |
322 { 17, DW_SIGNAL_COLUMN_CLICK }, | |
323 { 18, DW_SIGNAL_HTML_RESULT }, | |
324 { 19, DW_SIGNAL_HTML_CHANGED } | |
325 }; | |
326 | |
327 int _event_handler1(id object, NSEvent *event, int message) | |
328 { | |
329 SignalHandler *handler = _get_handler(object, message); | |
330 /* NSLog(@"Event handler - type %d\n", message); */ | |
331 | |
332 if(handler) | |
333 { | |
334 switch(message) | |
335 { | |
336 /* Timer event */ | |
337 case 0: | |
338 { | |
339 int (* API timerfunc)(void *) = (int (* API)(void *))handler->signalfunction; | |
340 | |
341 if(!timerfunc(handler->data)) | |
342 dw_timer_disconnect(handler->id); | |
343 return 0; | |
344 } | |
345 /* Configure/Resize event */ | |
346 case 1: | |
347 { | |
348 int (*sizefunc)(HWND, int, int, void *) = handler->signalfunction; | |
349 NSSize size; | |
350 | |
351 if([object isKindOfClass:[UIWindow class]]) | |
352 { | |
353 UIWindow *window = object; | |
354 size = [[window contentView] frame].size; | |
355 } | |
356 else | |
357 { | |
358 UIView *view = object; | |
359 size = [view frame].size; | |
360 } | |
361 | |
362 if(size.width > 0 && size.height > 0) | |
363 { | |
364 return sizefunc(object, size.width, size.height, handler->data); | |
365 } | |
366 return 0; | |
367 } | |
368 case 2: | |
369 { | |
370 int (*keypressfunc)(HWND, char, int, int, void *, char *) = handler->signalfunction; | |
371 NSString *nchar = [event charactersIgnoringModifiers]; | |
372 int special = (int)[event modifierFlags]; | |
373 unichar vk = [nchar characterAtIndex:0]; | |
374 char *utf8 = NULL, ch = '\0'; | |
375 | |
376 /* Handle a valid key */ | |
377 if([nchar length] == 1) | |
378 { | |
379 char *tmp = (char *)[nchar UTF8String]; | |
380 if(tmp && strlen(tmp) == 1) | |
381 { | |
382 ch = tmp[0]; | |
383 } | |
384 utf8 = tmp; | |
385 } | |
386 | |
387 return keypressfunc(handler->window, ch, (int)vk, special, handler->data, utf8); | |
388 } | |
389 /* Button press and release event */ | |
390 case 3: | |
391 case 4: | |
392 { | |
393 int (* API buttonfunc)(HWND, int, int, int, void *) = (int (* API)(HWND, int, int, int, void *))handler->signalfunction; | |
394 NSPoint p = [NSEvent mouseLocation]; | |
395 int button = 1; | |
396 | |
397 if([event isMemberOfClass:[NSEvent class]]) | |
398 { | |
399 id view = [[[event window] contentView] superview]; | |
400 NSEventType type = [event type]; | |
401 | |
402 p = [view convertPoint:[event locationInWindow] toView:object]; | |
403 | |
404 if(type == DWEventTypeRightMouseDown || type == DWEventTypeRightMouseUp) | |
405 { | |
406 button = 2; | |
407 } | |
408 else if(type == DWEventTypeOtherMouseDown || type == DWEventTypeOtherMouseUp) | |
409 { | |
410 button = 3; | |
411 } | |
412 else if([event modifierFlags] & DWEventModifierFlagControl) | |
413 { | |
414 button = 2; | |
415 } | |
416 } | |
417 | |
418 return buttonfunc(object, (int)p.x, (int)p.y, button, handler->data); | |
419 } | |
420 /* Motion notify event */ | |
421 case 5: | |
422 { | |
423 int (* API motionfunc)(HWND, int, int, int, void *) = (int (* API)(HWND, int, int, int, void *))handler->signalfunction; | |
424 id view = [[[event window] contentView] superview]; | |
425 NSPoint p = [view convertPoint:[event locationInWindow] toView:object]; | |
426 SEL spmb = NSSelectorFromString(@"pressedMouseButtons"); | |
427 DWIMP ipmb = [[NSEvent class] respondsToSelector:spmb] ? (DWIMP)[[NSEvent class] methodForSelector:spmb] : 0; | |
428 NSUInteger buttonmask = ipmb ? (NSUInteger)ipmb([NSEvent class], spmb) : (1 << [event buttonNumber]); | |
429 | |
430 return motionfunc(object, (int)p.x, (int)p.y, (int)buttonmask, handler->data); | |
431 } | |
432 /* Window close event */ | |
433 case 6: | |
434 { | |
435 int (* API closefunc)(HWND, void *) = (int (* API)(HWND, void *))handler->signalfunction; | |
436 return closefunc(object, handler->data); | |
437 } | |
438 /* Window expose/draw event */ | |
439 case 7: | |
440 { | |
441 DWExpose exp; | |
442 int (* API exposefunc)(HWND, DWExpose *, void *) = (int (* API)(HWND, DWExpose *, void *))handler->signalfunction; | |
443 NSRect rect = [object frame]; | |
444 | |
445 exp.x = rect.origin.x; | |
446 exp.y = rect.origin.y; | |
447 exp.width = rect.size.width; | |
448 exp.height = rect.size.height; | |
449 int result = exposefunc(object, &exp, handler->data); | |
450 return result; | |
451 } | |
452 /* Clicked event for buttons and menu items */ | |
453 case 8: | |
454 { | |
455 int (* API clickfunc)(HWND, void *) = (int (* API)(HWND, void *))handler->signalfunction; | |
456 | |
457 return clickfunc(object, handler->data); | |
458 } | |
459 /* Container class selection event */ | |
460 case 9: | |
461 { | |
462 int (*containerselectfunc)(HWND, char *, void *, void *) = handler->signalfunction; | |
463 void **params = (void **)event; | |
464 | |
465 return containerselectfunc(handler->window, params[0], handler->data, params[1]); | |
466 } | |
467 /* Container context menu event */ | |
468 case 10: | |
469 { | |
470 int (* API containercontextfunc)(HWND, char *, int, int, void *, void *) = (int (* API)(HWND, char *, int, int, void *, void *))handler->signalfunction; | |
471 char *text = (char *)event; | |
472 void *user = NULL; | |
473 LONG x,y; | |
474 | |
475 /* Fill in both items for the tree */ | |
476 if([object isKindOfClass:[NSOutlineView class]]) | |
477 { | |
478 id item = event; | |
479 NSString *nstr = [item objectAtIndex:1]; | |
480 text = (char *)[nstr UTF8String]; | |
481 NSValue *value = [item objectAtIndex:2]; | |
482 if(value && [value isKindOfClass:[NSValue class]]) | |
483 { | |
484 user = [value pointerValue]; | |
485 } | |
486 } | |
487 | |
488 dw_pointer_query_pos(&x, &y); | |
489 | |
490 return containercontextfunc(handler->window, text, (int)x, (int)y, handler->data, user); | |
491 } | |
492 /* Generic selection changed event for several classes */ | |
493 case 11: | |
494 case 14: | |
495 { | |
496 int (* API valuechangedfunc)(HWND, int, void *) = (int (* API)(HWND, int, void *))handler->signalfunction; | |
497 int selected = DW_POINTER_TO_INT(event); | |
498 | |
499 return valuechangedfunc(handler->window, selected, handler->data);; | |
500 } | |
501 /* Tree class selection event */ | |
502 case 12: | |
503 { | |
504 int (* API treeselectfunc)(HWND, HTREEITEM, char *, void *, void *) = (int (* API)(HWND, HTREEITEM, char *, void *, void *))handler->signalfunction; | |
505 char *text = NULL; | |
506 void *user = NULL; | |
507 id item = nil; | |
508 | |
509 if([object isKindOfClass:[NSOutlineView class]]) | |
510 { | |
511 item = (id)event; | |
512 NSString *nstr = [item objectAtIndex:1]; | |
513 | |
514 if(nstr) | |
515 { | |
516 text = strdup([nstr UTF8String]); | |
517 } | |
518 | |
519 NSValue *value = [item objectAtIndex:2]; | |
520 if(value && [value isKindOfClass:[NSValue class]]) | |
521 { | |
522 user = [value pointerValue]; | |
523 } | |
524 int result = treeselectfunc(handler->window, item, text, handler->data, user); | |
525 if(text) | |
526 { | |
527 free(text); | |
528 } | |
529 return result; | |
530 } | |
531 else if(event) | |
532 { | |
533 void **params = (void **)event; | |
534 | |
535 text = params[0]; | |
536 user = params[1]; | |
537 } | |
538 | |
539 return treeselectfunc(handler->window, item, text, handler->data, user); | |
540 } | |
541 /* Set Focus event */ | |
542 case 13: | |
543 { | |
544 int (* API setfocusfunc)(HWND, void *) = (int (* API)(HWND, void *))handler->signalfunction; | |
545 | |
546 return setfocusfunc(handler->window, handler->data); | |
547 } | |
548 /* Notebook page change event */ | |
549 case 15: | |
550 { | |
551 int (* API switchpagefunc)(HWND, unsigned long, void *) = (int (* API)(HWND, unsigned long, void *))handler->signalfunction; | |
552 int pageid = DW_POINTER_TO_INT(event); | |
553 | |
554 return switchpagefunc(handler->window, pageid, handler->data); | |
555 } | |
556 /* Tree expand event */ | |
557 case 16: | |
558 { | |
559 int (* API treeexpandfunc)(HWND, HTREEITEM, void *) = (int (* API)(HWND, HTREEITEM, void *))handler->signalfunction; | |
560 | |
561 return treeexpandfunc(handler->window, (HTREEITEM)event, handler->data); | |
562 } | |
563 /* Column click event */ | |
564 case 17: | |
565 { | |
566 int (* API clickcolumnfunc)(HWND, int, void *) = handler->signalfunction; | |
567 int column_num = DW_POINTER_TO_INT(event); | |
568 | |
569 return clickcolumnfunc(handler->window, column_num, handler->data); | |
570 } | |
571 /* HTML result event */ | |
572 case 18: | |
573 { | |
574 int (* API htmlresultfunc)(HWND, int, char *, void *, void *) = handler->signalfunction; | |
575 void **params = (void **)event; | |
576 NSString *result = params[0]; | |
577 | |
578 return htmlresultfunc(handler->window, [result length] ? DW_ERROR_NONE : DW_ERROR_UNKNOWN, [result length] ? (char *)[result UTF8String] : NULL, params[1], handler->data); | |
579 } | |
580 /* HTML changed event */ | |
581 case 19: | |
582 { | |
583 int (* API htmlchangedfunc)(HWND, int, char *, void *) = handler->signalfunction; | |
584 void **params = (void **)event; | |
585 NSString *uri = params[1]; | |
586 | |
587 return htmlchangedfunc(handler->window, DW_POINTER_TO_INT(params[0]), (char *)[uri UTF8String], handler->data); | |
588 } | |
589 } | |
590 } | |
591 return -1; | |
592 } | |
593 | |
594 /* Sub function to handle redraws */ | |
595 int _event_handler(id object, NSEvent *event, int message) | |
596 { | |
597 int ret = _event_handler1(object, event, message); | |
598 if(ret != -1) | |
599 _dw_redraw(nil, FALSE); | |
600 return ret; | |
601 } | |
602 | |
603 /* Subclass for the Timer type */ | |
604 @interface DWTimerHandler : NSObject { } | |
605 -(void)runTimer:(id)sender; | |
606 @end | |
607 | |
608 @implementation DWTimerHandler | |
609 -(void)runTimer:(id)sender { _event_handler(sender, nil, 0); } | |
610 @end | |
611 | |
612 NSApplication *DWApp = nil; | |
613 UIFontManager *DWFontManager = nil; | |
614 UIFont *DWDefaultFont; | |
615 DWTimerHandler *DWHandler; | |
616 NSAutoreleasePool *pool; | |
617 NSMutableArray *_DWDirtyDrawables; | |
618 DWTID DWThread = (DWTID)-1; | |
619 | |
620 /* Send fake event to make sure the loop isn't stuck */ | |
621 void _dw_wakeup_app() | |
622 { | |
623 [DWApp postEvent:[NSEvent otherEventWithType:DWEventTypeApplicationDefined | |
624 location:NSMakePoint(0, 0) | |
625 modifierFlags:0 | |
626 timestamp:0 | |
627 windowNumber:0 | |
628 context:NULL | |
629 subtype:0 | |
630 data1:0 | |
631 data2:0] | |
632 atStart:NO]; | |
633 } | |
634 | |
635 /* Used for doing bitblts from the main thread */ | |
636 typedef struct _bitbltinfo | |
637 { | |
638 id src; | |
639 id dest; | |
640 int xdest; | |
641 int ydest; | |
642 int width; | |
643 int height; | |
644 int xsrc; | |
645 int ysrc; | |
646 int srcwidth; | |
647 int srcheight; | |
648 } DWBitBlt; | |
649 | |
650 /* Subclass for a test object type */ | |
651 @interface DWObject : NSObject {} | |
652 -(void)uselessThread:(id)sender; | |
653 -(void)menuHandler:(id)param; | |
654 -(void)doBitBlt:(id)param; | |
655 -(void)doFlush:(id)param; | |
656 @end | |
657 | |
658 @interface DWMenuItem : NSMenuItem | |
659 { | |
660 int check; | |
661 } | |
662 -(void)setCheck:(int)input; | |
663 -(int)check; | |
664 -(void)dealloc; | |
665 @end | |
666 | |
667 /* So basically to implement our event handlers... | |
668 * it looks like we are going to have to subclass | |
669 * basically everything. Was hoping to add methods | |
670 * to the superclasses but it looks like you can | |
671 * only add methods and no variables, which isn't | |
672 * going to work. -Brian | |
673 */ | |
674 | |
675 /* Subclass for a box type */ | |
676 @interface DWBox : UIView | |
677 { | |
678 Box *box; | |
679 void *userdata; | |
680 UIColor *bgcolor; | |
681 } | |
682 -(id)init; | |
683 -(void)dealloc; | |
684 -(Box *)box; | |
685 -(id)contentView; | |
686 -(void *)userdata; | |
687 -(void)setUserdata:(void *)input; | |
688 -(void)drawRect:(NSRect)rect; | |
689 -(BOOL)isFlipped; | |
690 -(void)mouseDown:(NSEvent *)theEvent; | |
691 -(void)mouseUp:(NSEvent *)theEvent; | |
692 -(NSMenu *)menuForEvent:(NSEvent *)theEvent; | |
693 -(void)rightMouseUp:(NSEvent *)theEvent; | |
694 -(void)otherMouseDown:(NSEvent *)theEvent; | |
695 -(void)otherMouseUp:(NSEvent *)theEvent; | |
696 -(void)keyDown:(NSEvent *)theEvent; | |
697 -(void)setColor:(unsigned long)input; | |
698 @end | |
699 | |
700 @implementation DWBox | |
701 -(id)init | |
702 { | |
703 self = [super init]; | |
704 | |
705 if (self) | |
706 { | |
707 box = calloc(1, sizeof(Box)); | |
708 box->type = DW_VERT; | |
709 box->vsize = box->hsize = SIZEEXPAND; | |
710 box->width = box->height = 1; | |
711 } | |
712 return self; | |
713 } | |
714 -(void)dealloc | |
715 { | |
716 UserData *root = userdata; | |
717 if(box->items) | |
718 free(box->items); | |
719 free(box); | |
720 _remove_userdata(&root, NULL, TRUE); | |
721 dw_signal_disconnect_by_window(self); | |
722 [super dealloc]; | |
723 } | |
724 -(Box *)box { return box; } | |
725 -(id)contentView { return self; } | |
726 -(void *)userdata { return userdata; } | |
727 -(void)setUserdata:(void *)input { userdata = input; } | |
728 -(void)drawRect:(NSRect)rect | |
729 { | |
730 if(bgcolor) | |
731 { | |
732 [bgcolor set]; | |
733 NSRectFill([self bounds]); | |
734 } | |
735 } | |
736 -(BOOL)isFlipped { return YES; } | |
737 -(void)mouseDown:(NSEvent *)theEvent { _event_handler(self, (void *)1, 3); } | |
738 -(void)mouseUp:(NSEvent *)theEvent { _event_handler(self, (void *)1, 4); } | |
739 -(NSMenu *)menuForEvent:(NSEvent *)theEvent { _event_handler(self, (void *)2, 3); return nil; } | |
740 -(void)rightMouseUp:(NSEvent *)theEvent { _event_handler(self, (void *)2, 4); } | |
741 -(void)otherMouseDown:(NSEvent *)theEvent { _event_handler(self, (void *)3, 3); } | |
742 -(void)otherMouseUp:(NSEvent *)theEvent { _event_handler(self, (void *)3, 4); } | |
743 -(void)keyDown:(NSEvent *)theEvent { _event_handler(self, theEvent, 2); } | |
744 -(void)setColor:(unsigned long)input | |
745 { | |
746 id orig = bgcolor; | |
747 | |
748 if(input == _colors[DW_CLR_DEFAULT]) | |
749 { | |
750 bgcolor = nil; | |
751 } | |
752 else | |
753 { | |
754 bgcolor = [[UIColor colorWithDeviceRed: DW_RED_VALUE(input)/255.0 green: DW_GREEN_VALUE(input)/255.0 blue: DW_BLUE_VALUE(input)/255.0 alpha: 1] retain]; | |
755 if(UIGraphicsGetCurrentContext()) | |
756 { | |
757 [bgcolor set]; | |
758 NSRectFill([self bounds]); | |
759 } | |
760 } | |
761 [self setNeedsDisplay:YES]; | |
762 [orig release]; | |
763 } | |
764 @end | |
765 | |
766 /* Subclass for a group box type */ | |
767 @interface DWGroupBox : UIView | |
768 { | |
769 void *userdata; | |
770 UIColor *bgcolor; | |
771 NSSize borderSize; | |
772 NSString *title; | |
773 } | |
774 -(Box *)box; | |
775 -(void *)userdata; | |
776 -(void)setUserdata:(void *)input; | |
777 -(void)setTitle:(NSString *)newtitle; | |
778 @end | |
779 | |
780 @implementation DWGroupBox | |
781 -(Box *)box { return [[self contentView] box]; } | |
782 -(void *)userdata { return userdata; } | |
783 -(NSSize)borderSize { return borderSize; } | |
784 -(NSSize)initBorder | |
785 { | |
786 NSSize frameSize = [self frame].size; | |
787 | |
788 if(frameSize.height < 20 || frameSize.width < 20) | |
789 { | |
790 frameSize.width = frameSize.height = 100; | |
791 [self setFrameSize:frameSize]; | |
792 } | |
793 NSSize contentSize = [[self contentView] frame].size; | |
794 NSSize titleSize = [self titleRect].size; | |
795 | |
796 borderSize.width = 100-contentSize.width; | |
797 borderSize.height = (100-contentSize.height)-titleSize.height; | |
798 return borderSize; | |
799 } | |
800 -(void)setUserdata:(void *)input { userdata = input; } | |
801 -(void)setTitle:(NSString *)newtitle { [title release]; title = newtitle; [title retain]; } | |
802 @end | |
803 | |
804 @interface DWWindow : UIWindow | |
805 { | |
806 int redraw; | |
807 int shown; | |
808 } | |
809 -(void)sendEvent:(NSEvent *)theEvent; | |
810 -(void)keyDown:(NSEvent *)theEvent; | |
811 -(void)mouseDragged:(NSEvent *)theEvent; | |
812 -(int)redraw; | |
813 -(void)setRedraw:(int)val; | |
814 -(int)shown; | |
815 -(void)setShown:(int)val; | |
816 @end | |
817 | |
818 @implementation DWWindow | |
819 -(void)sendEvent:(NSEvent *)theEvent | |
820 { | |
821 int rcode = -1; | |
822 if([theEvent type] == DWEventTypeKeyDown) | |
823 { | |
824 rcode = _event_handler(self, theEvent, 2); | |
825 } | |
826 if ( rcode != TRUE ) | |
827 [super sendEvent:theEvent]; | |
828 } | |
829 -(void)keyDown:(NSEvent *)theEvent { } | |
830 -(void)mouseDragged:(NSEvent *)theEvent { _event_handler(self, theEvent, 5); } | |
831 -(int)redraw { return redraw; } | |
832 -(void)setRedraw:(int)val { redraw = val; } | |
833 -(int)shown { return shown; } | |
834 -(void)setShown:(int)val { shown = val; } | |
835 -(void)dealloc { dw_signal_disconnect_by_window(self); [super dealloc]; } | |
836 @end | |
837 | |
838 /* Subclass for a render area type */ | |
839 @interface DWRender : UIControl | |
840 { | |
841 void *userdata; | |
842 UIFont *font; | |
843 NSSize size; | |
844 NSBitmapImageRep *cachedDrawingRep; | |
845 } | |
846 -(void *)userdata; | |
847 -(void)setUserdata:(void *)input; | |
848 -(void)setFont:(UIFont *)input; | |
849 -(UIFont *)font; | |
850 -(void)setSize:(NSSize)input; | |
851 -(NSSize)size; | |
852 -(NSBitmapImageRep *)cachedDrawingRep; | |
853 -(void)mouseDown:(NSEvent *)theEvent; | |
854 -(void)mouseUp:(NSEvent *)theEvent; | |
855 -(NSMenu *)menuForEvent:(NSEvent *)theEvent; | |
856 -(void)rightMouseUp:(NSEvent *)theEvent; | |
857 -(void)otherMouseDown:(NSEvent *)theEvent; | |
858 -(void)otherMouseUp:(NSEvent *)theEvent; | |
859 -(void)drawRect:(NSRect)rect; | |
860 -(void)keyDown:(NSEvent *)theEvent; | |
861 -(BOOL)isFlipped; | |
862 @end | |
863 | |
864 @implementation DWRender | |
865 -(void *)userdata { return userdata; } | |
866 -(void)setUserdata:(void *)input { userdata = input; } | |
867 -(void)setFont:(UIFont *)input { [font release]; font = input; [font retain]; } | |
868 -(UIFont *)font { return font; } | |
869 -(void)setSize:(NSSize)input { | |
870 size = input; | |
871 if(cachedDrawingRep) | |
872 { | |
873 NSBitmapImageRep *oldrep = cachedDrawingRep; | |
874 cachedDrawingRep = [self bitmapImageRepForCachingDisplayInRect:self.bounds]; | |
875 [cachedDrawingRep retain]; | |
876 [oldrep release]; | |
877 } | |
878 } | |
879 -(NSSize)size { return size; } | |
880 -(NSBitmapImageRep *)cachedDrawingRep { | |
881 if(!cachedDrawingRep) | |
882 { | |
883 cachedDrawingRep = [self bitmapImageRepForCachingDisplayInRect:self.bounds]; | |
884 [cachedDrawingRep retain]; | |
885 } | |
886 /* Mark this render dirty if something is requesting it to draw */ | |
887 if(![_DWDirtyDrawables containsObject:self]) | |
888 [_DWDirtyDrawables addObject:self]; | |
889 return cachedDrawingRep; | |
890 } | |
891 -(void)mouseDown:(NSEvent *)theEvent | |
892 { | |
893 if(![theEvent isMemberOfClass:[NSEvent class]] || !([theEvent modifierFlags] & DWEventModifierFlagControl)) | |
894 _event_handler(self, theEvent, 3); | |
895 } | |
896 -(void)mouseUp:(NSEvent *)theEvent { _event_handler(self, theEvent, 4); } | |
897 -(NSMenu *)menuForEvent:(NSEvent *)theEvent { _event_handler(self, theEvent, 3); return nil; } | |
898 -(void)rightMouseUp:(NSEvent *)theEvent { _event_handler(self, theEvent, 4); } | |
899 -(void)otherMouseDown:(NSEvent *)theEvent { _event_handler(self, theEvent, 3); } | |
900 -(void)otherMouseUp:(NSEvent *)theEvent { _event_handler(self, theEvent, 4); } | |
901 -(void)mouseDragged:(NSEvent *)theEvent { _event_handler(self, theEvent, 5); } | |
902 -(void)delayedNeedsDisplay { [self setNeedsDisplay:YES]; } | |
903 -(void)drawRect:(NSRect)rect { | |
904 _event_handler(self, nil, 7); | |
905 if (cachedDrawingRep) | |
906 { | |
907 [cachedDrawingRep drawInRect:self.bounds]; | |
908 [_DWDirtyDrawables removeObject:self]; | |
909 /* Work around a bug in Mojave 10.14 by delaying the setNeedsDisplay */ | |
910 if(DWOSMinor != 14) | |
911 [self setNeedsDisplay:YES]; | |
912 else | |
913 [self performSelector:@selector(delayedNeedsDisplay) withObject:nil afterDelay:0]; | |
914 } | |
915 } | |
916 -(void)keyDown:(NSEvent *)theEvent { _event_handler(self, theEvent, 2); } | |
917 -(BOOL)isFlipped { return YES; } | |
918 -(void)dealloc { | |
919 UserData *root = userdata; | |
920 _remove_userdata(&root, NULL, TRUE); | |
921 [font release]; | |
922 dw_signal_disconnect_by_window(self); | |
923 [cachedDrawingRep release]; | |
924 [_DWDirtyDrawables removeObject:self]; | |
925 [super dealloc]; | |
926 } | |
927 -(BOOL)acceptsFirstResponder { return YES; } | |
928 @end | |
929 | |
930 @implementation DWObject | |
931 -(void)uselessThread:(id)sender { /* Thread only to initialize threading */ } | |
932 -(void)menuHandler:(id)param | |
933 { | |
934 DWMenuItem *item = param; | |
935 if([item check]) | |
936 { | |
937 if([item state] == DWControlStateValueOn) | |
938 [item setState:DWControlStateValueOff]; | |
939 else | |
940 [item setState:DWControlStateValueOn]; | |
941 } | |
942 _event_handler(param, nil, 8); | |
943 } | |
944 -(void)callBack:(NSPointerArray *)params | |
945 { | |
946 void (*mycallback)(NSPointerArray *) = [params pointerAtIndex:0]; | |
947 if(mycallback) | |
948 mycallback(params); | |
949 } | |
950 -(void)messageBox:(NSMutableArray *)params | |
951 { | |
952 NSInteger iResponse; | |
953 NSAlert *alert = [[NSAlert alloc] init]; | |
954 [alert setMessageText:[params objectAtIndex:0]]; | |
955 [alert setInformativeText:[params objectAtIndex:1]]; | |
956 [alert addButtonWithTitle:[params objectAtIndex:3]]; | |
957 if([params count] > 4) | |
958 [alert addButtonWithTitle:[params objectAtIndex:4]]; | |
959 if([params count] > 5) | |
960 [alert addButtonWithTitle:[params objectAtIndex:5]]; | |
961 [alert setAlertStyle:[[params objectAtIndex:2] integerValue]]; | |
962 iResponse = [alert runModal]; | |
963 [alert release]; | |
964 [params addObject:[NSNumber numberWithInteger:iResponse]]; | |
965 } | |
966 -(void)safeCall:(SEL)sel withObject:(id)param | |
967 { | |
968 if([self respondsToSelector:sel]) | |
969 { | |
970 DWTID curr = pthread_self(); | |
971 | |
972 if(DWThread == (DWTID)-1 || DWThread == curr) | |
973 { | |
974 DWIMP imp = (DWIMP)[self methodForSelector:sel]; | |
975 | |
976 if(imp) | |
977 imp(self, sel, param); | |
978 } | |
979 else | |
980 [self performSelectorOnMainThread:sel withObject:param waitUntilDone:YES]; | |
981 } | |
982 } | |
983 -(void)doBitBlt:(id)param | |
984 { | |
985 NSValue *bi = (NSValue *)param; | |
986 DWBitBlt *bltinfo = (DWBitBlt *)[bi pointerValue]; | |
987 id bltdest = bltinfo->dest; | |
988 id bltsrc = bltinfo->src; | |
989 | |
990 if([bltdest isMemberOfClass:[DWRender class]]) | |
991 { | |
992 DWRender *render = bltdest; | |
993 | |
994 bltdest = [render cachedDrawingRep]; | |
995 } | |
996 if([bltdest isMemberOfClass:[NSBitmapImageRep class]]) | |
997 { | |
998 UIGraphicsPushContext(_dw_draw_context(bltdest)); | |
999 [[[NSDictionary alloc] initWithObjectsAndKeys:bltdest, NSGraphicsContextDestinationAttributeName, nil] autorelease]; | |
1000 } | |
1001 if(bltdest && [bltsrc isMemberOfClass:[NSBitmapImageRep class]]) | |
1002 { | |
1003 NSBitmapImageRep *rep = bltsrc; | |
1004 UIImage *image = [UIImage alloc]; | |
1005 SEL siwc = NSSelectorFromString(@"initWithCGImage"); | |
1006 NSCompositingOperation op = DWCompositingOperationSourceOver; | |
1007 | |
1008 if([image respondsToSelector:siwc]) | |
1009 { | |
1010 DWIMP iiwc = (DWIMP)[image methodForSelector:siwc]; | |
1011 image = iiwc(image, siwc, [rep CGImage], NSZeroSize); | |
1012 } | |
1013 else | |
1014 { | |
1015 image = [image initWithSize:[rep size]]; | |
1016 [image addRepresentation:rep]; | |
1017 } | |
1018 if(bltinfo->srcwidth != -1) | |
1019 { | |
1020 [image drawInRect:NSMakeRect(bltinfo->xdest, bltinfo->ydest, bltinfo->width, bltinfo->height) | |
1021 fromRect:NSMakeRect(bltinfo->xsrc, bltinfo->ysrc, bltinfo->srcwidth, bltinfo->srcheight) | |
1022 operation:op fraction:1.0]; | |
1023 } | |
1024 else | |
1025 { | |
1026 [image drawAtPoint:NSMakePoint(bltinfo->xdest, bltinfo->ydest) | |
1027 fromRect:NSMakeRect(bltinfo->xsrc, bltinfo->ysrc, bltinfo->width, bltinfo->height) | |
1028 operation:op fraction:1.0]; | |
1029 } | |
1030 [bltsrc release]; | |
1031 [image release]; | |
1032 } | |
1033 if([bltdest isMemberOfClass:[NSBitmapImageRep class]]) | |
1034 { | |
1035 UIGraphicsPopContext(); | |
1036 } | |
1037 free(bltinfo); | |
1038 } | |
1039 -(void)doFlush:(id)param | |
1040 { | |
1041 NSEnumerator *enumerator = [_DWDirtyDrawables objectEnumerator]; | |
1042 DWRender *rend; | |
1043 | |
1044 while (rend = [enumerator nextObject]) | |
1045 [rend setNeedsDisplay:YES]; | |
1046 [_DWDirtyDrawables removeAllObjects]; | |
1047 } | |
1048 -(void)doWindowFunc:(id)param | |
1049 { | |
1050 NSValue *v = (NSValue *)param; | |
1051 void **params = (void **)[v pointerValue]; | |
1052 void (* windowfunc)(void *); | |
1053 | |
1054 if(params) | |
1055 { | |
1056 windowfunc = params[0]; | |
1057 if(windowfunc) | |
1058 { | |
1059 windowfunc(params[1]); | |
1060 } | |
1061 } | |
1062 } | |
1063 @end | |
1064 | |
1065 DWObject *DWObj; | |
1066 | |
1067 /* Subclass for the application class */ | |
1068 @interface DWAppDel : NSObject <NSApplicationDelegate> | |
1069 { | |
1070 } | |
1071 -(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; | |
1072 @end | |
1073 | |
1074 @interface DWWebView : WKWebView <WKNavigationDelegate> | |
1075 { | |
1076 void *userdata; | |
1077 } | |
1078 -(void *)userdata; | |
1079 -(void)setUserdata:(void *)input; | |
1080 -(void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation; | |
1081 -(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation; | |
1082 -(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation; | |
1083 -(void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation; | |
1084 @end | |
1085 | |
1086 @implementation DWWebView : WKWebView | |
1087 -(void *)userdata { return userdata; } | |
1088 -(void)setUserdata:(void *)input { userdata = input; } | |
1089 -(void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation | |
1090 { | |
1091 void *params[2] = { DW_INT_TO_POINTER(DW_HTML_CHANGE_STARTED), [[self URL] absoluteString] }; | |
1092 _event_handler(self, (NSEvent *)params, 19); | |
1093 } | |
1094 -(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation | |
1095 { | |
1096 void *params[2] = { DW_INT_TO_POINTER(DW_HTML_CHANGE_COMPLETE), [[self URL] absoluteString] }; | |
1097 _event_handler(self, (NSEvent *)params, 19); | |
1098 } | |
1099 -(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation | |
1100 { | |
1101 void *params[2] = { DW_INT_TO_POINTER(DW_HTML_CHANGE_LOADING), [[self URL] absoluteString] }; | |
1102 _event_handler(self, (NSEvent *)params, 19); | |
1103 } | |
1104 -(void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation | |
1105 { | |
1106 void *params[2] = { DW_INT_TO_POINTER(DW_HTML_CHANGE_REDIRECT), [[self URL] absoluteString] }; | |
1107 _event_handler(self, (NSEvent *)params, 19); | |
1108 } | |
1109 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
1110 @end | |
1111 | |
1112 @implementation DWAppDel | |
1113 -(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender | |
1114 { | |
1115 if(_event_handler(sender, nil, 6) > 0) | |
1116 return NSTerminateCancel; | |
1117 return NSTerminateNow; | |
1118 } | |
1119 @end | |
1120 | |
1121 /* Subclass for a top-level window */ | |
1122 @interface DWView : DWBox <UIWindowDelegate> | |
1123 { | |
1124 NSMenu *windowmenu; | |
1125 NSSize oldsize; | |
1126 } | |
1127 -(BOOL)windowShouldClose:(id)sender; | |
1128 -(void)setMenu:(NSMenu *)input; | |
1129 -(void)windowDidBecomeMain:(id)sender; | |
1130 -(void)menuHandler:(id)sender; | |
1131 -(void)mouseDragged:(NSEvent *)theEvent; | |
1132 @end | |
1133 | |
1134 @implementation DWView | |
1135 -(BOOL)windowShouldClose:(id)sender | |
1136 { | |
1137 if(_event_handler(sender, nil, 6) > 0) | |
1138 return NO; | |
1139 return YES; | |
1140 } | |
1141 -(void)viewDidMoveToWindow | |
1142 { | |
1143 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowResized:) name:UIWindowDidResizeNotification object:[self window]]; | |
1144 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidBecomeMain:) name:UIWindowDidBecomeMainNotification object:[self window]]; | |
1145 } | |
1146 -(void)dealloc | |
1147 { | |
1148 if(windowmenu) | |
1149 { | |
1150 [windowmenu release]; | |
1151 } | |
1152 [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
1153 dw_signal_disconnect_by_window(self); | |
1154 [super dealloc]; | |
1155 } | |
1156 -(void)windowResized:(NSNotification *)notification; | |
1157 { | |
1158 NSSize size = [self frame].size; | |
1159 | |
1160 if(oldsize.width != size.width || oldsize.height != size.height) | |
1161 { | |
1162 _do_resize(box, size.width, size.height); | |
1163 _event_handler([self window], nil, 1); | |
1164 oldsize.width = size.width; | |
1165 oldsize.height = size.height; | |
1166 _handle_resize_events(box); | |
1167 } | |
1168 } | |
1169 -(void)showWindow | |
1170 { | |
1171 NSSize size = [self frame].size; | |
1172 | |
1173 if(oldsize.width == size.width && oldsize.height == size.height) | |
1174 { | |
1175 _do_resize(box, size.width, size.height); | |
1176 _handle_resize_events(box); | |
1177 } | |
1178 | |
1179 } | |
1180 -(void)windowDidBecomeMain:(id)sender | |
1181 { | |
1182 if(windowmenu) | |
1183 { | |
1184 [DWApp setMainMenu:windowmenu]; | |
1185 } | |
1186 else | |
1187 { | |
1188 [DWApp setMainMenu:DWMainMenu]; | |
1189 } | |
1190 _event_handler([self window], nil, 13); | |
1191 } | |
1192 -(void)setMenu:(NSMenu *)input { windowmenu = input; [windowmenu retain]; } | |
1193 -(void)menuHandler:(id)sender | |
1194 { | |
1195 id menu = [sender menu]; | |
1196 | |
1197 /* Find the highest menu for this item */ | |
1198 while([menu supermenu]) | |
1199 { | |
1200 menu = [menu supermenu]; | |
1201 } | |
1202 | |
1203 /* Only perform the delay if this item is a child of the main menu */ | |
1204 if([DWApp mainMenu] == menu) | |
1205 [DWObj performSelector:@selector(menuHandler:) withObject:sender afterDelay:0]; | |
1206 else | |
1207 [DWObj menuHandler:sender]; | |
1208 _dw_wakeup_app(); | |
1209 } | |
1210 -(void)mouseDragged:(NSEvent *)theEvent { _event_handler(self, theEvent, 5); } | |
1211 -(void)mouseMoved:(NSEvent *)theEvent | |
1212 { | |
1213 id hit = [self hitTest:[theEvent locationInWindow]]; | |
1214 | |
1215 if([hit isMemberOfClass:[DWRender class]]) | |
1216 { | |
1217 _event_handler(hit, theEvent, 5); | |
1218 } | |
1219 } | |
1220 @end | |
1221 | |
1222 /* Subclass for a button type */ | |
1223 @interface DWButton : UIButton | |
1224 { | |
1225 void *userdata; | |
1226 UIButtonType buttonType; | |
1227 DWBox *parent; | |
1228 } | |
1229 -(void *)userdata; | |
1230 -(void)setUserdata:(void *)input; | |
1231 -(void)buttonClicked:(id)sender; | |
1232 -(void)setButtonType:(UIButtonType)input; | |
1233 -(UIButtonType)buttonType; | |
1234 -(void)setParent:(DWBox *)input; | |
1235 -(DWBox *)parent; | |
1236 -(UIColor *)textColor; | |
1237 -(void)setTextColor:(UIColor *)textColor; | |
1238 @end | |
1239 | |
1240 @implementation DWButton | |
1241 -(void *)userdata { return userdata; } | |
1242 -(void)setUserdata:(void *)input { userdata = input; } | |
1243 -(void)buttonClicked:(id)sender | |
1244 { | |
1245 _event_handler(self, nil, 8); | |
1246 if([self buttonType] == DWButtonTypeRadio) | |
1247 { | |
1248 DWBox *viewbox = [self parent]; | |
1249 Box *thisbox = [viewbox box]; | |
1250 int z; | |
1251 | |
1252 for(z=0;z<thisbox->count;z++) | |
1253 { | |
1254 if(thisbox->items[z].type != TYPEBOX) | |
1255 { | |
1256 id object = thisbox->items[z].hwnd; | |
1257 | |
1258 if([object isMemberOfClass:[DWButton class]]) | |
1259 { | |
1260 DWButton *button = object; | |
1261 | |
1262 if(button != self && [button buttonType] == DWButtonTypeRadio) | |
1263 { | |
1264 [button setState:DWControlStateValueOff]; | |
1265 } | |
1266 } | |
1267 } | |
1268 } | |
1269 } | |
1270 } | |
1271 -(void)setButtonType:(UIButtonType)input { buttonType = input; [super setButtonType:input]; } | |
1272 -(UIButtonType)buttonType { return buttonType; } | |
1273 -(void)setParent:(DWBox *)input { parent = input; } | |
1274 -(DWBox *)parent { return parent; } | |
1275 -(UIColor *)textColor | |
1276 { | |
1277 NSAttributedString *attrTitle = [self attributedTitle]; | |
1278 NSUInteger len = [attrTitle length]; | |
1279 NSRange range = NSMakeRange(0, MIN(len, 1)); | |
1280 NSDictionary *attrs = [attrTitle fontAttributesInRange:range]; | |
1281 UIColor *textColor = [UIColor controlTextColor]; | |
1282 if (attrs) { | |
1283 textColor = [attrs objectForKey:NSForegroundColorAttributeName]; | |
1284 } | |
1285 return textColor; | |
1286 } | |
1287 -(void)setTextColor:(UIColor *)textColor | |
1288 { | |
1289 NSMutableAttributedString *attrTitle = [[NSMutableAttributedString alloc] | |
1290 initWithAttributedString:[self attributedTitle]]; | |
1291 NSUInteger len = [attrTitle length]; | |
1292 NSRange range = NSMakeRange(0, len); | |
1293 [attrTitle addAttribute:NSForegroundColorAttributeName | |
1294 value:textColor | |
1295 range:range]; | |
1296 [attrTitle fixAttributesInRange:range]; | |
1297 [self setAttributedTitle:attrTitle]; | |
1298 [attrTitle release]; | |
1299 } | |
1300 -(void)keyDown:(NSEvent *)theEvent | |
1301 { | |
1302 unichar vk = [[theEvent charactersIgnoringModifiers] characterAtIndex:0]; | |
1303 if(vk == VK_RETURN || vk == VK_SPACE) | |
1304 { | |
1305 if(buttonType == DWButtonTypeSwitch) | |
1306 [self setState:([self state] ? DWControlStateValueOff : DWControlStateValueOn)]; | |
1307 else if(buttonType == DWButtonTypeRadio) | |
1308 [self setState:DWControlStateValueOn]; | |
1309 [self buttonClicked:self]; | |
1310 } | |
1311 else | |
1312 { | |
1313 [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; | |
1314 [super keyDown:theEvent]; | |
1315 } | |
1316 } | |
1317 -(void)insertTab:(id)sender { if([[self window] firstResponder] == self) [[self window] selectNextKeyView:self]; } | |
1318 -(void)insertBacktab:(id)sender { if([[self window] firstResponder] == self) [[self window] selectPreviousKeyView:self]; } | |
1319 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
1320 @end | |
1321 | |
1322 /* Subclass for a progress type */ | |
1323 @interface DWPercent : NSProgressIndicator | |
1324 { | |
1325 void *userdata; | |
1326 } | |
1327 -(void *)userdata; | |
1328 -(void)setUserdata:(void *)input; | |
1329 @end | |
1330 | |
1331 @implementation DWPercent | |
1332 -(void *)userdata { return userdata; } | |
1333 -(void)setUserdata:(void *)input { userdata = input; } | |
1334 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
1335 @end | |
1336 | |
1337 /* Subclass for a menu item type */ | |
1338 @implementation DWMenuItem | |
1339 -(void)setCheck:(int)input { check = input; } | |
1340 -(int)check { return check; } | |
1341 -(void)dealloc { dw_signal_disconnect_by_window(self); [super dealloc]; } | |
1342 @end | |
1343 | |
1344 /* Subclass for a scrollbox type */ | |
1345 @interface DWScrollBox : UIScrollView | |
1346 { | |
1347 void *userdata; | |
1348 id box; | |
1349 } | |
1350 -(void *)userdata; | |
1351 -(void)setUserdata:(void *)input; | |
1352 -(void)setBox:(void *)input; | |
1353 -(id)box; | |
1354 @end | |
1355 | |
1356 @implementation DWScrollBox | |
1357 -(void *)userdata { return userdata; } | |
1358 -(void)setUserdata:(void *)input { userdata = input; } | |
1359 -(void)setBox:(void *)input { box = input; } | |
1360 -(id)box { return box; } | |
1361 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
1362 @end | |
1363 | |
1364 /* Subclass for a textfield that supports vertical centering */ | |
1365 @interface DWTextFieldCell : UITextFieldCell | |
1366 { | |
1367 BOOL vcenter; | |
1368 } | |
1369 -(NSRect)drawingRectForBounds:(NSRect)theRect; | |
1370 -(void)setVCenter:(BOOL)input; | |
1371 @end | |
1372 | |
1373 @implementation DWTextFieldCell | |
1374 -(NSRect)drawingRectForBounds:(NSRect)theRect | |
1375 { | |
1376 /* Get the parent's idea of where we should draw */ | |
1377 NSRect newRect = [super drawingRectForBounds:theRect]; | |
1378 | |
1379 /* If we are being vertically centered */ | |
1380 if(vcenter) | |
1381 { | |
1382 /* Get our ideal size for current text */ | |
1383 NSSize textSize = [self cellSizeForBounds:theRect]; | |
1384 | |
1385 /* Center that in the proposed rect */ | |
1386 float heightDelta = newRect.size.height - textSize.height; | |
1387 if (heightDelta > 0) | |
1388 { | |
1389 newRect.size.height -= heightDelta; | |
1390 newRect.origin.y += (heightDelta / 2); | |
1391 } | |
1392 } | |
1393 | |
1394 return newRect; | |
1395 } | |
1396 -(void)setVCenter:(BOOL)input { vcenter = input; } | |
1397 @end | |
1398 | |
1399 @interface DWEntryFieldFormatter : NSFormatter | |
1400 { | |
1401 int maxLength; | |
1402 } | |
1403 - (void)setMaximumLength:(int)len; | |
1404 - (int)maximumLength; | |
1405 @end | |
1406 | |
1407 /* This formatter subclass will allow us to limit | |
1408 * the text length in an entryfield. | |
1409 */ | |
1410 @implementation DWEntryFieldFormatter | |
1411 -(id)init | |
1412 { | |
1413 self = [super init]; | |
1414 maxLength = INT_MAX; | |
1415 return self; | |
1416 } | |
1417 -(void)setMaximumLength:(int)len { maxLength = len; } | |
1418 -(int)maximumLength { return maxLength; } | |
1419 -(NSString *)stringForObjectValue:(id)object { return (NSString *)object; } | |
1420 -(BOOL)getObjectValue:(id *)object forString:(NSString *)string errorDescription:(NSString **)error { *object = string; return YES; } | |
1421 -(BOOL)isPartialStringValid:(NSString **)partialStringPtr | |
1422 proposedSelectedRange:(NSRangePointer)proposedSelRangePtr | |
1423 originalString:(NSString *)origString | |
1424 originalSelectedRange:(NSRange)origSelRange | |
1425 errorDescription:(NSString **)error | |
1426 { | |
1427 if([*partialStringPtr length] > maxLength) | |
1428 { | |
1429 return NO; | |
1430 } | |
1431 return YES; | |
1432 } | |
1433 -(NSAttributedString *)attributedStringForObjectValue:(id)anObject withDefaultAttributes:(NSDictionary *)attributes { return nil; } | |
1434 @end | |
1435 | |
1436 /* Subclass for a entryfield type */ | |
1437 @interface DWEntryField : UITextField | |
1438 { | |
1439 void *userdata; | |
1440 id clickDefault; | |
1441 } | |
1442 -(void *)userdata; | |
1443 -(void)setUserdata:(void *)input; | |
1444 -(void)setClickDefault:(id)input; | |
1445 @end | |
1446 | |
1447 @implementation DWEntryField | |
1448 -(void *)userdata { return userdata; } | |
1449 -(void)setUserdata:(void *)input { userdata = input; } | |
1450 -(void)setClickDefault:(id)input { clickDefault = input; } | |
1451 -(void)keyUp:(NSEvent *)theEvent | |
1452 { | |
1453 unichar vk = [[theEvent charactersIgnoringModifiers] characterAtIndex:0]; | |
1454 if(clickDefault && vk == VK_RETURN) | |
1455 { | |
1456 if([clickDefault isKindOfClass:[UIButton class]]) | |
1457 [clickDefault buttonClicked:self]; | |
1458 else | |
1459 [[self window] makeFirstResponder:clickDefault]; | |
1460 } else | |
1461 { | |
1462 [super keyUp:theEvent]; | |
1463 } | |
1464 } | |
1465 -(BOOL)performKeyEquivalent:(NSEvent *)theEvent | |
1466 { | |
1467 if(([theEvent modifierFlags] & DWEventModifierFlagDeviceIndependentFlagsMask) == DWEventModifierFlagCommand) | |
1468 { | |
1469 if ([[theEvent charactersIgnoringModifiers] isEqualToString:@"x"]) | |
1470 return [NSApp sendAction:@selector(cut:) to:[[self window] firstResponder] from:self]; | |
1471 else if ([[theEvent charactersIgnoringModifiers] isEqualToString:@"c"]) | |
1472 return [NSApp sendAction:@selector(copy:) to:[[self window] firstResponder] from:self]; | |
1473 else if ([[theEvent charactersIgnoringModifiers] isEqualToString:@"v"]) | |
1474 return [NSApp sendAction:@selector(paste:) to:[[self window] firstResponder] from:self]; | |
1475 else if ([[theEvent charactersIgnoringModifiers] isEqualToString:@"a"]) | |
1476 return [NSApp sendAction:@selector(selectAll:) to:[[self window] firstResponder] from:self]; | |
1477 } | |
1478 return [super performKeyEquivalent:theEvent]; | |
1479 } | |
1480 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
1481 @end | |
1482 | |
1483 /* Subclass for a text and status text type */ | |
1484 @interface DWText : UITextField | |
1485 { | |
1486 void *userdata; | |
1487 id clickDefault; | |
1488 } | |
1489 -(void *)userdata; | |
1490 -(void)setUserdata:(void *)input; | |
1491 @end | |
1492 | |
1493 @implementation DWText | |
1494 -(void *)userdata { return userdata; } | |
1495 -(void)setUserdata:(void *)input { userdata = input; } | |
1496 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); [super dealloc]; } | |
1497 @end | |
1498 | |
1499 | |
1500 /* Subclass for a entryfield password type */ | |
1501 @interface DWEntryFieldPassword : NSSecureTextField | |
1502 { | |
1503 void *userdata; | |
1504 id clickDefault; | |
1505 } | |
1506 -(void *)userdata; | |
1507 -(void)setUserdata:(void *)input; | |
1508 -(void)setClickDefault:(id)input; | |
1509 @end | |
1510 | |
1511 @implementation DWEntryFieldPassword | |
1512 -(void *)userdata { return userdata; } | |
1513 -(void)setUserdata:(void *)input { userdata = input; } | |
1514 -(void)setClickDefault:(id)input { clickDefault = input; } | |
1515 -(void)keyUp:(NSEvent *)theEvent | |
1516 { | |
1517 if(clickDefault && [[theEvent charactersIgnoringModifiers] characterAtIndex:0] == VK_RETURN) | |
1518 { | |
1519 if([clickDefault isKindOfClass:[UIButton class]]) | |
1520 [clickDefault buttonClicked:self]; | |
1521 else | |
1522 [[self window] makeFirstResponder:clickDefault]; | |
1523 } | |
1524 else | |
1525 { | |
1526 [super keyUp:theEvent]; | |
1527 } | |
1528 } | |
1529 -(BOOL)performKeyEquivalent:(NSEvent *)theEvent | |
1530 { | |
1531 if(([theEvent modifierFlags] & DWEventModifierFlagDeviceIndependentFlagsMask) == DWEventModifierFlagCommand) | |
1532 { | |
1533 if ([[theEvent charactersIgnoringModifiers] isEqualToString:@"x"]) | |
1534 return [NSApp sendAction:@selector(cut:) to:[[self window] firstResponder] from:self]; | |
1535 else if ([[theEvent charactersIgnoringModifiers] isEqualToString:@"c"]) | |
1536 return [NSApp sendAction:@selector(copy:) to:[[self window] firstResponder] from:self]; | |
1537 else if ([[theEvent charactersIgnoringModifiers] isEqualToString:@"v"]) | |
1538 return [NSApp sendAction:@selector(paste:) to:[[self window] firstResponder] from:self]; | |
1539 else if ([[theEvent charactersIgnoringModifiers] isEqualToString:@"a"]) | |
1540 return [NSApp sendAction:@selector(selectAll:) to:[[self window] firstResponder] from:self]; | |
1541 } | |
1542 return [super performKeyEquivalent:theEvent]; | |
1543 } | |
1544 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
1545 @end | |
1546 | |
1547 /* Subclass for a Notebook control type */ | |
1548 @interface DWNotebook : NSTabView <NSTabViewDelegate> | |
1549 { | |
1550 void *userdata; | |
1551 int pageid; | |
1552 } | |
1553 -(void *)userdata; | |
1554 -(void)setUserdata:(void *)input; | |
1555 -(int)pageid; | |
1556 -(void)setPageid:(int)input; | |
1557 -(void)tabView:(NSTabView *)notebook didSelectTabViewItem:(NSTabViewItem *)notepage; | |
1558 @end | |
1559 | |
1560 /* Subclass for a Notebook page type */ | |
1561 @interface DWNotebookPage : NSTabViewItem | |
1562 { | |
1563 void *userdata; | |
1564 int pageid; | |
1565 } | |
1566 -(void *)userdata; | |
1567 -(void)setUserdata:(void *)input; | |
1568 -(int)pageid; | |
1569 -(void)setPageid:(int)input; | |
1570 @end | |
1571 | |
1572 @implementation DWNotebook | |
1573 -(void *)userdata { return userdata; } | |
1574 -(void)setUserdata:(void *)input { userdata = input; } | |
1575 -(int)pageid { return pageid; } | |
1576 -(void)setPageid:(int)input { pageid = input; } | |
1577 -(void)tabView:(NSTabView *)notebook didSelectTabViewItem:(NSTabViewItem *)notepage | |
1578 { | |
1579 id object = [notepage view]; | |
1580 DWNotebookPage *page = (DWNotebookPage *)notepage; | |
1581 | |
1582 if([object isMemberOfClass:[DWBox class]]) | |
1583 { | |
1584 DWBox *view = object; | |
1585 Box *box = [view box]; | |
1586 NSSize size = [view frame].size; | |
1587 _do_resize(box, size.width, size.height); | |
1588 _handle_resize_events(box); | |
1589 } | |
1590 _event_handler(self, DW_INT_TO_POINTER([page pageid]), 15); | |
1591 } | |
1592 -(void)keyDown:(NSEvent *)theEvent | |
1593 { | |
1594 unichar vk = [[theEvent charactersIgnoringModifiers] characterAtIndex:0]; | |
1595 | |
1596 if(vk == NSTabCharacter || vk == NSBackTabCharacter) | |
1597 [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; | |
1598 else if(vk == NSLeftArrowFunctionKey) | |
1599 { | |
1600 NSArray *pages = [self tabViewItems]; | |
1601 DWNotebookPage *page = (DWNotebookPage *)[self selectedTabViewItem]; | |
1602 NSUInteger index = [pages indexOfObject:page]; | |
1603 | |
1604 if(index != NSNotFound) | |
1605 { | |
1606 if(index > 0) | |
1607 [self selectTabViewItem:[pages objectAtIndex:(index-1)]]; | |
1608 else | |
1609 [self selectTabViewItem:[pages objectAtIndex:0]]; | |
1610 | |
1611 } | |
1612 } | |
1613 else if(vk == NSRightArrowFunctionKey) | |
1614 { | |
1615 NSArray *pages = [self tabViewItems]; | |
1616 DWNotebookPage *page = (DWNotebookPage *)[self selectedTabViewItem]; | |
1617 NSUInteger index = [pages indexOfObject:page]; | |
1618 NSUInteger count = [pages count]; | |
1619 | |
1620 if(index != NSNotFound) | |
1621 { | |
1622 if(index + 1 < count) | |
1623 [self selectTabViewItem:[pages objectAtIndex:(index+1)]]; | |
1624 else | |
1625 [self selectTabViewItem:[pages objectAtIndex:(count-1)]]; | |
1626 | |
1627 } | |
1628 } | |
1629 [super keyDown:theEvent]; | |
1630 } | |
1631 -(void)insertTab:(id)sender { if([[self window] firstResponder] == self) [[self window] selectNextKeyView:self]; } | |
1632 -(void)insertBacktab:(id)sender { if([[self window] firstResponder] == self) [[self window] selectPreviousKeyView:self]; } | |
1633 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
1634 @end | |
1635 | |
1636 @implementation DWNotebookPage | |
1637 -(void *)userdata { return userdata; } | |
1638 -(void)setUserdata:(void *)input { userdata = input; } | |
1639 -(int)pageid { return pageid; } | |
1640 -(void)setPageid:(int)input { pageid = input; } | |
1641 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
1642 @end | |
1643 | |
1644 /* Subclass for a color chooser type */ | |
1645 @interface DWColorChoose : UIColorPanel | |
1646 { | |
1647 DWDialog *dialog; | |
1648 UIColor *pickedcolor; | |
1649 } | |
1650 -(void)changeColor:(id)sender; | |
1651 -(void)setDialog:(DWDialog *)input; | |
1652 -(DWDialog *)dialog; | |
1653 @end | |
1654 | |
1655 @implementation DWColorChoose | |
1656 -(void)changeColor:(id)sender | |
1657 { | |
1658 if(!dialog) | |
1659 [self close]; | |
1660 else | |
1661 pickedcolor = [self color]; | |
1662 } | |
1663 -(BOOL)windowShouldClose:(id)window | |
1664 { | |
1665 if(dialog) | |
1666 { | |
1667 DWDialog *d = dialog; | |
1668 dialog = nil; | |
1669 dw_dialog_dismiss(d, pickedcolor); | |
1670 } | |
1671 [self close]; | |
1672 return NO; | |
1673 } | |
1674 -(void)setDialog:(DWDialog *)input { dialog = input; } | |
1675 -(DWDialog *)dialog { return dialog; } | |
1676 @end | |
1677 | |
1678 /* Subclass for a font chooser type */ | |
1679 @interface DWFontChoose : UIFontPanel | |
1680 { | |
1681 DWDialog *dialog; | |
1682 } | |
1683 -(void)setDialog:(DWDialog *)input; | |
1684 -(DWDialog *)dialog; | |
1685 @end | |
1686 | |
1687 @implementation DWFontChoose | |
1688 -(BOOL)windowShouldClose:(id)window | |
1689 { | |
1690 DWDialog *d = dialog; dialog = nil; | |
1691 UIFont *pickedfont = [DWFontManager selectedFont]; | |
1692 dw_dialog_dismiss(d, pickedfont); | |
1693 [window orderOut:nil]; | |
1694 return NO; | |
1695 } | |
1696 -(void)setDialog:(DWDialog *)input { dialog = input; } | |
1697 -(DWDialog *)dialog { return dialog; } | |
1698 @end | |
1699 | |
1700 /* Subclass for a splitbar type */ | |
1701 @interface DWSplitBar : NSSplitView <NSSplitViewDelegate> | |
1702 { | |
1703 void *userdata; | |
1704 float percent; | |
1705 NSInteger Tag; | |
1706 } | |
1707 -(void)splitViewDidResizeSubviews:(NSNotification *)aNotification; | |
1708 -(void)setTag:(NSInteger)tag; | |
1709 -(void *)userdata; | |
1710 -(void)setUserdata:(void *)input; | |
1711 -(float)percent; | |
1712 -(void)setPercent:(float)input; | |
1713 @end | |
1714 | |
1715 @implementation DWSplitBar | |
1716 -(void)splitViewDidResizeSubviews:(NSNotification *)aNotification | |
1717 { | |
1718 NSArray *views = [self subviews]; | |
1719 id object; | |
1720 | |
1721 for(object in views) | |
1722 { | |
1723 if([object isMemberOfClass:[DWBox class]]) | |
1724 { | |
1725 DWBox *view = object; | |
1726 Box *box = [view box]; | |
1727 NSSize size = [view frame].size; | |
1728 _do_resize(box, size.width, size.height); | |
1729 _handle_resize_events(box); | |
1730 } | |
1731 } | |
1732 } | |
1733 -(void)setTag:(NSInteger)tag { Tag = tag; } | |
1734 -(void *)userdata { return userdata; } | |
1735 -(void)setUserdata:(void *)input { userdata = input; } | |
1736 -(float)percent { return percent; } | |
1737 -(void)setPercent:(float)input { percent = input; } | |
1738 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
1739 @end | |
1740 | |
1741 /* Subclass for a slider type */ | |
1742 @interface DWSlider : UISlider | |
1743 { | |
1744 void *userdata; | |
1745 } | |
1746 -(void *)userdata; | |
1747 -(void)setUserdata:(void *)input; | |
1748 -(void)sliderChanged:(id)sender; | |
1749 @end | |
1750 | |
1751 @implementation DWSlider | |
1752 -(void *)userdata { return userdata; } | |
1753 -(void)setUserdata:(void *)input { userdata = input; } | |
1754 -(void)sliderChanged:(id)sender { _event_handler(self, (void *)[self integerValue], 14); } | |
1755 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
1756 @end | |
1757 | |
1758 /* Subclass for a slider type */ | |
1759 @interface DWScrollbar : NSScroller | |
1760 { | |
1761 void *userdata; | |
1762 double range; | |
1763 double visible; | |
1764 int vertical; | |
1765 } | |
1766 -(void *)userdata; | |
1767 -(void)setUserdata:(void *)input; | |
1768 -(float)range; | |
1769 -(float)visible; | |
1770 -(int)vertical; | |
1771 -(void)setVertical:(int)value; | |
1772 -(void)setRange:(double)input1 andVisible:(double)input2; | |
1773 -(void)scrollerChanged:(id)sender; | |
1774 @end | |
1775 | |
1776 @implementation DWScrollbar | |
1777 -(void *)userdata { return userdata; } | |
1778 -(void)setUserdata:(void *)input { userdata = input; } | |
1779 -(float)range { return range; } | |
1780 -(float)visible { return visible; } | |
1781 -(int)vertical { return vertical; } | |
1782 -(void)setVertical:(int)value { vertical = value; } | |
1783 -(void)setRange:(double)input1 andVisible:(double)input2 { range = input1; visible = input2; } | |
1784 -(void)scrollerChanged:(id)sender | |
1785 { | |
1786 double max = (range - visible); | |
1787 double result = ([self doubleValue] * max); | |
1788 double newpos = result; | |
1789 | |
1790 switch ([sender hitPart]) | |
1791 { | |
1792 case NSScrollerDecrementPage: | |
1793 newpos -= visible; | |
1794 if(newpos < 0) | |
1795 { | |
1796 newpos = 0; | |
1797 } | |
1798 break; | |
1799 | |
1800 case NSScrollerIncrementPage: | |
1801 newpos += visible; | |
1802 if(newpos > max) | |
1803 { | |
1804 newpos = max; | |
1805 } | |
1806 break; | |
1807 | |
1808 default: | |
1809 ; /* do nothing */ | |
1810 } | |
1811 int newposi = (int)newpos; | |
1812 newpos = (newpos - (double)newposi) > 0.5 ? (double)(newposi + 1) : (double)newposi; | |
1813 if(newpos != result) | |
1814 { | |
1815 [self setDoubleValue:(newpos/max)]; | |
1816 } | |
1817 _event_handler(self, DW_INT_TO_POINTER((int)newpos), 14); | |
1818 } | |
1819 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
1820 @end | |
1821 | |
1822 /* Subclass for a MLE type */ | |
1823 @interface DWMLE : UITextView | |
1824 { | |
1825 void *userdata; | |
1826 id scrollview; | |
1827 } | |
1828 -(void *)userdata; | |
1829 -(void)setUserdata:(void *)input; | |
1830 -(id)scrollview; | |
1831 -(void)setScrollview:(id)input; | |
1832 @end | |
1833 | |
1834 @implementation DWMLE | |
1835 -(void *)userdata { return userdata; } | |
1836 -(void)setUserdata:(void *)input { userdata = input; } | |
1837 -(id)scrollview { return scrollview; } | |
1838 -(void)setScrollview:(id)input { scrollview = input; } | |
1839 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
1840 @end | |
1841 | |
1842 NSTableCellView *_dw_table_cell_view_new(UIImage *icon, NSString *text) | |
1843 { | |
1844 NSTableCellView *browsercell = [[[NSTableCellView alloc] init] autorelease]; | |
1845 [browsercell setAutoresizesSubviews:YES]; | |
1846 if(icon) | |
1847 { | |
1848 UIImageView *iv = [[[UIImageView alloc] init] autorelease]; | |
1849 [iv setAutoresizingMask:UIViewHeightSizable|(text ? 0 :UIViewWidthSizable)]; | |
1850 [iv setImage:icon]; | |
1851 [browsercell setImageView:iv]; | |
1852 [browsercell addSubview:iv]; | |
1853 } | |
1854 if(text) | |
1855 { | |
1856 UITextField *tf = [[[UITextField alloc] init] autorelease]; | |
1857 [tf setAutoresizingMask:UIViewHeightSizable|UIViewWidthSizable]; | |
1858 [tf setStringValue:text]; | |
1859 [tf setEditable:NO]; | |
1860 [tf setBezeled:NO]; | |
1861 [tf setBordered:NO]; | |
1862 [tf setDrawsBackground:NO]; | |
1863 [[tf cell] setVCenter:YES]; | |
1864 [browsercell setTextField:tf]; | |
1865 [browsercell addSubview:tf]; | |
1866 } | |
1867 return browsercell; | |
1868 } | |
1869 | |
1870 void _dw_table_cell_view_layout(NSTableCellView *result) | |
1871 { | |
1872 /* Adjust the frames of the textField and imageView when both are present */ | |
1873 if([result imageView] && [result textField]) | |
1874 { | |
1875 UIImageView *iv = [result imageView]; | |
1876 UIImage *icon = [iv image]; | |
1877 UITextField *tf = [result textField]; | |
1878 NSRect rect = result.frame; | |
1879 int width =[icon size].width; | |
1880 | |
1881 [iv setFrame:NSMakeRect(0,0,width,rect.size.height)]; | |
1882 | |
1883 /* Adjust the rect to allow space for the image */ | |
1884 rect.origin.x += width; | |
1885 rect.size.width -= width; | |
1886 [tf setFrame:rect]; | |
1887 } | |
1888 } | |
1889 | |
1890 @interface DWFocusRingScrollView : UIScrollView | |
1891 { | |
1892 BOOL shouldDrawFocusRing; | |
1893 NSResponder* lastResp; | |
1894 } | |
1895 @end | |
1896 | |
1897 @implementation DWFocusRingScrollView | |
1898 -(BOOL)needsDisplay; | |
1899 { | |
1900 NSResponder* resp = nil; | |
1901 | |
1902 if([[self window] isKeyWindow]) | |
1903 { | |
1904 resp = [[self window] firstResponder]; | |
1905 if (resp == lastResp) | |
1906 return [super needsDisplay]; | |
1907 } | |
1908 else if (lastResp == nil) | |
1909 { | |
1910 return [super needsDisplay]; | |
1911 } | |
1912 shouldDrawFocusRing = (resp != nil && [resp isKindOfClass:[UIView class]] && [(UIView*)resp isDescendantOf:self]); | |
1913 lastResp = resp; | |
1914 [self setKeyboardFocusRingNeedsDisplayInRect:[self bounds]]; | |
1915 return YES; | |
1916 } | |
1917 -(void)drawRect:(NSRect)rect | |
1918 { | |
1919 [super drawRect:rect]; | |
1920 | |
1921 if(shouldDrawFocusRing) | |
1922 { | |
1923 NSSetFocusRingStyle(NSFocusRingOnly); | |
1924 NSRectFill(rect); | |
1925 } | |
1926 } | |
1927 @end | |
1928 | |
1929 /* Subclass for a Container/List type */ | |
1930 @interface DWContainer : NSTableView <NSTableViewDataSource,NSTableViewDelegate> | |
1931 { | |
1932 void *userdata; | |
1933 NSMutableArray *tvcols; | |
1934 NSMutableArray *data; | |
1935 NSMutableArray *types; | |
1936 NSPointerArray *titles; | |
1937 NSPointerArray *rowdatas; | |
1938 UIColor *fgcolor, *oddcolor, *evencolor; | |
1939 unsigned long dw_oddcolor, dw_evencolor; | |
1940 unsigned long _DW_COLOR_ROW_ODD, _DW_COLOR_ROW_EVEN; | |
1941 int lastAddPoint, lastQueryPoint; | |
1942 id scrollview; | |
1943 int filesystem; | |
1944 } | |
1945 -(NSInteger)numberOfRowsInTableView:(NSTableView *)aTable; | |
1946 -(id)tableView:(NSTableView *)aTable objectValueForTableColumn:(NSTableColumn *)aCol row:(NSInteger)aRow; | |
1947 -(BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex; | |
1948 -(void *)userdata; | |
1949 -(void)setUserdata:(void *)input; | |
1950 -(void)setFilesystem:(int)input; | |
1951 -(int)filesystem; | |
1952 -(id)scrollview; | |
1953 -(void)setScrollview:(id)input; | |
1954 -(void)addColumn:(NSTableColumn *)input andType:(int)type; | |
1955 -(NSTableColumn *)getColumn:(int)col; | |
1956 -(int)addRow:(NSArray *)input; | |
1957 -(int)addRows:(int)number; | |
1958 -(void)editCell:(id)input at:(int)row and:(int)col; | |
1959 -(void)removeRow:(int)row; | |
1960 -(void)setRow:(int)row title:(const char *)input; | |
1961 -(void *)getRowTitle:(int)row; | |
1962 -(id)getRow:(int)row and:(int)col; | |
1963 -(int)cellType:(int)col; | |
1964 -(int)lastAddPoint; | |
1965 -(int)lastQueryPoint; | |
1966 -(void)setLastQueryPoint:(int)input; | |
1967 -(void)clear; | |
1968 -(void)setup; | |
1969 -(void)optimize; | |
1970 -(NSSize)getsize; | |
1971 -(void)setForegroundColor:(UIColor *)input; | |
1972 -(void)doubleClicked:(id)sender; | |
1973 -(void)keyUp:(NSEvent *)theEvent; | |
1974 -(void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn; | |
1975 -(void)selectionChanged:(id)sender; | |
1976 -(NSMenu *)menuForEvent:(NSEvent *)event; | |
1977 -(void)tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row; | |
1978 -(UIView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row; | |
1979 @end | |
1980 | |
1981 @implementation DWContainer | |
1982 -(NSInteger)numberOfRowsInTableView:(NSTableView *)aTable | |
1983 { | |
1984 if(tvcols && data) | |
1985 { | |
1986 int cols = (int)[tvcols count]; | |
1987 int total = (int)[data count]; | |
1988 if(cols && total) | |
1989 { | |
1990 return total / cols; | |
1991 } | |
1992 } | |
1993 return 0; | |
1994 } | |
1995 -(id)tableView:(NSTableView *)aTable objectValueForTableColumn:(NSTableColumn *)aCol row:(NSInteger)aRow | |
1996 { | |
1997 if(tvcols && data) | |
1998 { | |
1999 int z, col = -1; | |
2000 int count = (int)[tvcols count]; | |
2001 | |
2002 for(z=0;z<count;z++) | |
2003 { | |
2004 if([tvcols objectAtIndex:z] == aCol) | |
2005 { | |
2006 col = z; | |
2007 break; | |
2008 } | |
2009 } | |
2010 if(col != -1) | |
2011 { | |
2012 int index = (int)(aRow * count) + col; | |
2013 if(index < [data count]) | |
2014 { | |
2015 id this = [data objectAtIndex:index]; | |
2016 return ([this isKindOfClass:[NSNull class]]) ? nil : this; | |
2017 } | |
2018 } | |
2019 } | |
2020 return nil; | |
2021 } | |
2022 -(BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex { return NO; } | |
2023 -(void *)userdata { return userdata; } | |
2024 -(void)setUserdata:(void *)input { userdata = input; } | |
2025 -(void)setFilesystem:(int)input { filesystem = input; } | |
2026 -(int)filesystem { return filesystem; } | |
2027 -(id)scrollview { return scrollview; } | |
2028 -(void)setScrollview:(id)input { scrollview = input; } | |
2029 -(void)addColumn:(NSTableColumn *)input andType:(int)type { if(tvcols) { [tvcols addObject:input]; [types addObject:[NSNumber numberWithInt:type]]; } } | |
2030 -(NSTableColumn *)getColumn:(int)col { if(tvcols) { return [tvcols objectAtIndex:col]; } return nil; } | |
2031 -(void)refreshColors | |
2032 { | |
2033 UIColor *oldodd = oddcolor; | |
2034 UIColor *oldeven = evencolor; | |
2035 unsigned long thisodd = dw_oddcolor == DW_CLR_DEFAULT ? _DW_COLOR_ROW_ODD : dw_oddcolor; | |
2036 unsigned long _odd = _get_color(thisodd); | |
2037 unsigned long thiseven = dw_evencolor == DW_CLR_DEFAULT ? _DW_COLOR_ROW_EVEN : dw_evencolor; | |
2038 unsigned long _even = _get_color(thiseven); | |
2039 | |
2040 /* Get the UIColor for non-default colors */ | |
2041 if(thisodd != DW_RGB_TRANSPARENT) | |
2042 oddcolor = [[UIColor colorWithDeviceRed: DW_RED_VALUE(_odd)/255.0 green: DW_GREEN_VALUE(_odd)/255.0 blue: DW_BLUE_VALUE(_odd)/255.0 alpha: 1] retain]; | |
2043 else | |
2044 oddcolor = NULL; | |
2045 if(thiseven != DW_RGB_TRANSPARENT) | |
2046 evencolor = [[UIColor colorWithDeviceRed: DW_RED_VALUE(_even)/255.0 green: DW_GREEN_VALUE(_even)/255.0 blue: DW_BLUE_VALUE(_even)/255.0 alpha: 1] retain]; | |
2047 else | |
2048 evencolor = NULL; | |
2049 [oldodd release]; | |
2050 [oldeven release]; | |
2051 } | |
2052 -(void)setRowBgOdd:(unsigned long)oddcol andEven:(unsigned long)evencol | |
2053 { | |
2054 /* Save the set colors in case we get a theme change */ | |
2055 dw_oddcolor = oddcol; | |
2056 dw_evencolor = evencol; | |
2057 [self refreshColors]; | |
2058 } | |
2059 -(void)checkDark | |
2060 { | |
2061 /* Update any system colors based on the Dark Mode */ | |
2062 _DW_COLOR_ROW_EVEN = DW_RGB_TRANSPARENT; | |
2063 if(_is_dark(self)) | |
2064 _DW_COLOR_ROW_ODD = DW_RGB(100, 100, 100); | |
2065 else | |
2066 _DW_COLOR_ROW_ODD = DW_RGB(230, 230, 230); | |
2067 /* Only refresh if we've been setup already */ | |
2068 if(titles) | |
2069 [self refreshColors]; | |
2070 } | |
2071 -(void)viewDidChangeEffectiveAppearance { [self checkDark]; } | |
2072 -(int)insertRow:(NSArray *)input at:(int)index | |
2073 { | |
2074 if(data) | |
2075 { | |
2076 unsigned long start = [tvcols count] * index; | |
2077 NSIndexSet *set = [[NSIndexSet alloc] initWithIndexesInRange:NSMakeRange(start, start + [tvcols count])]; | |
2078 if(index < lastAddPoint) | |
2079 { | |
2080 lastAddPoint++; | |
2081 } | |
2082 [data insertObjects:input atIndexes:set]; | |
2083 [titles insertPointer:NULL atIndex:index]; | |
2084 [rowdatas insertPointer:NULL atIndex:index]; | |
2085 [set release]; | |
2086 return (int)[titles count]; | |
2087 } | |
2088 return 0; | |
2089 } | |
2090 -(int)addRow:(NSArray *)input | |
2091 { | |
2092 if(data) | |
2093 { | |
2094 lastAddPoint = (int)[titles count]; | |
2095 [data addObjectsFromArray:input]; | |
2096 [titles addPointer:NULL]; | |
2097 [rowdatas addPointer:NULL]; | |
2098 return (int)[titles count]; | |
2099 } | |
2100 return 0; | |
2101 } | |
2102 -(int)addRows:(int)number | |
2103 { | |
2104 if(tvcols) | |
2105 { | |
2106 int count = (int)(number * [tvcols count]); | |
2107 int z; | |
2108 | |
2109 lastAddPoint = (int)[titles count]; | |
2110 | |
2111 for(z=0;z<count;z++) | |
2112 { | |
2113 [data addObject:[NSNull null]]; | |
2114 } | |
2115 for(z=0;z<number;z++) | |
2116 { | |
2117 [titles addPointer:NULL]; | |
2118 [rowdatas addPointer:NULL]; | |
2119 } | |
2120 return (int)[titles count]; | |
2121 } | |
2122 return 0; | |
2123 } | |
2124 -(void)tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row | |
2125 { | |
2126 /* Handle drawing alternating row colors if enabled */ | |
2127 if ((row % 2) == 0) | |
2128 { | |
2129 if(evencolor) | |
2130 [rowView setBackgroundColor:evencolor]; | |
2131 } | |
2132 else | |
2133 { | |
2134 if(oddcolor) | |
2135 [rowView setBackgroundColor:oddcolor]; | |
2136 } | |
2137 } | |
2138 -(UIView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row; | |
2139 { | |
2140 /* Not reusing cell views, so get the cell from our array */ | |
2141 int index = (int)(row * [tvcols count]) + (int)[tvcols indexOfObject:tableColumn]; | |
2142 id celldata = [data objectAtIndex:index]; | |
2143 | |
2144 /* The data is already a NSTableCellView so just return that */ | |
2145 if([celldata isMemberOfClass:[NSTableCellView class]]) | |
2146 { | |
2147 NSTableCellView *result = celldata; | |
2148 NSTextAlignment align = [[tableColumn headerCell] alignment]; | |
2149 | |
2150 _dw_table_cell_view_layout(result); | |
2151 | |
2152 /* Copy the alignment setting from the column, | |
2153 * and set the text color from the container. | |
2154 */ | |
2155 if([result textField]) | |
2156 { | |
2157 UITextField *tf = [result textField]; | |
2158 | |
2159 [tf setAlignment:align]; | |
2160 if(fgcolor) | |
2161 [tf setTextColor:fgcolor]; | |
2162 } | |
2163 | |
2164 /* Return the result */ | |
2165 return result; | |
2166 } | |
2167 return nil; | |
2168 } | |
2169 -(void)editCell:(id)input at:(int)row and:(int)col | |
2170 { | |
2171 if(tvcols) | |
2172 { | |
2173 int index = (int)(row * [tvcols count]) + col; | |
2174 if(index < [data count]) | |
2175 { | |
2176 if(!input) | |
2177 input = [NSNull null]; | |
2178 [data replaceObjectAtIndex:index withObject:input]; | |
2179 } | |
2180 } | |
2181 } | |
2182 -(void)removeRow:(int)row | |
2183 { | |
2184 if(tvcols) | |
2185 { | |
2186 int z, start, end; | |
2187 int count = (int)[tvcols count]; | |
2188 void *oldtitle; | |
2189 | |
2190 start = (count * row); | |
2191 end = start + count; | |
2192 | |
2193 for(z=start;z<end;z++) | |
2194 { | |
2195 [data removeObjectAtIndex:start]; | |
2196 } | |
2197 oldtitle = [titles pointerAtIndex:row]; | |
2198 [titles removePointerAtIndex:row]; | |
2199 [rowdatas removePointerAtIndex:row]; | |
2200 if(lastAddPoint > 0 && lastAddPoint > row) | |
2201 { | |
2202 lastAddPoint--; | |
2203 } | |
2204 if(oldtitle) | |
2205 free(oldtitle); | |
2206 } | |
2207 } | |
2208 -(void)setRow:(int)row title:(const char *)input | |
2209 { | |
2210 if(titles && input) | |
2211 { | |
2212 void *oldtitle = [titles pointerAtIndex:row]; | |
2213 void *newtitle = input ? (void *)strdup(input) : NULL; | |
2214 [titles replacePointerAtIndex:row withPointer:newtitle]; | |
2215 if(oldtitle) | |
2216 free(oldtitle); | |
2217 } | |
2218 } | |
2219 -(void)setRowData:(int)row title:(void *)input { if(rowdatas && input) { [rowdatas replacePointerAtIndex:row withPointer:input]; } } | |
2220 -(void *)getRowTitle:(int)row { if(titles && row > -1) { return [titles pointerAtIndex:row]; } return NULL; } | |
2221 -(void *)getRowData:(int)row { if(rowdatas && row > -1) { return [rowdatas pointerAtIndex:row]; } return NULL; } | |
2222 -(id)getRow:(int)row and:(int)col { if(data) { int index = (int)(row * [tvcols count]) + col; return [data objectAtIndex:index]; } return nil; } | |
2223 -(int)cellType:(int)col { return [[types objectAtIndex:col] intValue]; } | |
2224 -(int)lastAddPoint { return lastAddPoint; } | |
2225 -(int)lastQueryPoint { return lastQueryPoint; } | |
2226 -(void)setLastQueryPoint:(int)input { lastQueryPoint = input; } | |
2227 -(void)clear | |
2228 { | |
2229 if(data) | |
2230 { | |
2231 [data removeAllObjects]; | |
2232 while([titles count]) | |
2233 { | |
2234 void *oldtitle = [titles pointerAtIndex:0]; | |
2235 [titles removePointerAtIndex:0]; | |
2236 [rowdatas removePointerAtIndex:0]; | |
2237 if(oldtitle) | |
2238 free(oldtitle); | |
2239 } | |
2240 } | |
2241 lastAddPoint = 0; | |
2242 } | |
2243 -(void)setup | |
2244 { | |
2245 SEL swopa = NSSelectorFromString(@"pointerArrayWithWeakObjects"); | |
2246 | |
2247 if(![[NSPointerArray class] respondsToSelector:swopa]) | |
2248 swopa = NSSelectorFromString(@"weakObjectsPointerArray"); | |
2249 if(![[NSPointerArray class] respondsToSelector:swopa]) | |
2250 return; | |
2251 | |
2252 DWIMP iwopa = (DWIMP)[[NSPointerArray class] methodForSelector:swopa]; | |
2253 | |
2254 titles = iwopa([NSPointerArray class], swopa); | |
2255 [titles retain]; | |
2256 rowdatas = iwopa([NSPointerArray class], swopa); | |
2257 [rowdatas retain]; | |
2258 tvcols = [[[NSMutableArray alloc] init] retain]; | |
2259 data = [[[NSMutableArray alloc] init] retain]; | |
2260 types = [[[NSMutableArray alloc] init] retain]; | |
2261 if(!dw_oddcolor && !dw_evencolor) | |
2262 dw_oddcolor = dw_evencolor = DW_CLR_DEFAULT; | |
2263 [self checkDark]; | |
2264 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(selectionChanged:) name:NSTableViewSelectionDidChangeNotification object:self]; | |
2265 } | |
2266 -(NSSize)getsize | |
2267 { | |
2268 int cwidth = 0, cheight = 0; | |
2269 | |
2270 if(tvcols) | |
2271 { | |
2272 int z; | |
2273 int colcount = (int)[tvcols count]; | |
2274 int rowcount = (int)[self numberOfRowsInTableView:self]; | |
2275 | |
2276 for(z=0;z<colcount;z++) | |
2277 { | |
2278 NSTableColumn *column = [tvcols objectAtIndex:z]; | |
2279 int width = [column width]; | |
2280 | |
2281 if(rowcount > 0) | |
2282 { | |
2283 int x; | |
2284 | |
2285 for(x=0;x<rowcount;x++) | |
2286 { | |
2287 NSTableCellView *cell = [self viewAtColumn:z row:x makeIfNecessary:YES]; | |
2288 int thiswidth = 4, thisheight = 0; | |
2289 | |
2290 if([cell imageView]) | |
2291 { | |
2292 thiswidth += [[cell imageView] image].size.width; | |
2293 thisheight = [[cell imageView] image].size.height; | |
2294 } | |
2295 if([cell textField]) | |
2296 { | |
2297 int textheight = [[cell textField] intrinsicContentSize].width; | |
2298 thiswidth += [[cell textField] intrinsicContentSize].width; | |
2299 if(textheight > thisheight) | |
2300 thisheight = textheight; | |
2301 } | |
2302 | |
2303 /* If on the first column... add up the heights */ | |
2304 if(z == 0) | |
2305 cheight += thisheight; | |
2306 | |
2307 if(thiswidth > width) | |
2308 { | |
2309 width = thiswidth; | |
2310 } | |
2311 } | |
2312 /* If the image is missing default the optimized width to 16. */ | |
2313 if(!width && [[types objectAtIndex:z] intValue] & DW_CFA_BITMAPORICON) | |
2314 { | |
2315 width = 16; | |
2316 } | |
2317 } | |
2318 if(width) | |
2319 cwidth += width; | |
2320 } | |
2321 } | |
2322 cwidth += 16; | |
2323 cheight += 16; | |
2324 return NSMakeSize(cwidth, cheight); | |
2325 } | |
2326 -(void)optimize | |
2327 { | |
2328 if(tvcols) | |
2329 { | |
2330 int z; | |
2331 int colcount = (int)[tvcols count]; | |
2332 int rowcount = (int)[self numberOfRowsInTableView:self]; | |
2333 | |
2334 for(z=0;z<colcount;z++) | |
2335 { | |
2336 NSTableColumn *column = [tvcols objectAtIndex:z]; | |
2337 if([column resizingMask] != NSTableColumnNoResizing) | |
2338 { | |
2339 if(rowcount > 0) | |
2340 { | |
2341 int x; | |
2342 NSCell *colcell = [column headerCell]; | |
2343 int width = [colcell cellSize].width; | |
2344 | |
2345 for(x=0;x<rowcount;x++) | |
2346 { | |
2347 NSTableCellView *cell = [self viewAtColumn:z row:x makeIfNecessary:YES]; | |
2348 int thiswidth = 4; | |
2349 | |
2350 if([cell imageView]) | |
2351 thiswidth += [[cell imageView] image].size.width; | |
2352 if([cell textField]) | |
2353 thiswidth += [[cell textField] intrinsicContentSize].width; | |
2354 | |
2355 if(thiswidth > width) | |
2356 { | |
2357 width = thiswidth; | |
2358 } | |
2359 } | |
2360 /* If the image is missing default the optimized width to 16. */ | |
2361 if(!width && [[types objectAtIndex:z] intValue] & DW_CFA_BITMAPORICON) | |
2362 { | |
2363 width = 16; | |
2364 } | |
2365 /* Sanity check... don't set the width to 0 */ | |
2366 if(width) | |
2367 { | |
2368 [column setWidth:width+1]; | |
2369 } | |
2370 } | |
2371 else | |
2372 { | |
2373 if(self.headerView) | |
2374 [column sizeToFit]; | |
2375 } | |
2376 } | |
2377 } | |
2378 } | |
2379 } | |
2380 -(void)setForegroundColor:(UIColor *)input | |
2381 { | |
2382 int z, count = (int)[tvcols count]; | |
2383 | |
2384 fgcolor = input; | |
2385 [fgcolor retain]; | |
2386 | |
2387 for(z=0;z<count;z++) | |
2388 { | |
2389 NSTableColumn *tableColumn = [tvcols objectAtIndex:z]; | |
2390 UITextFieldCell *cell = [tableColumn dataCell]; | |
2391 [cell setTextColor:fgcolor]; | |
2392 } | |
2393 } | |
2394 -(void)doubleClicked:(id)sender | |
2395 { | |
2396 void *params[2]; | |
2397 | |
2398 params[0] = (void *)[self getRowTitle:(int)[self selectedRow]]; | |
2399 params[1] = (void *)[self getRowData:(int)[self selectedRow]]; | |
2400 | |
2401 /* Handler for container class */ | |
2402 _event_handler(self, (NSEvent *)params, 9); | |
2403 } | |
2404 -(void)keyUp:(NSEvent *)theEvent | |
2405 { | |
2406 if([[theEvent charactersIgnoringModifiers] characterAtIndex:0] == VK_RETURN) | |
2407 { | |
2408 void *params[2]; | |
2409 | |
2410 params[0] = (void *)[self getRowTitle:(int)[self selectedRow]]; | |
2411 params[1] = (void *)[self getRowData:(int)[self selectedRow]]; | |
2412 | |
2413 _event_handler(self, (NSEvent *)params, 9); | |
2414 } | |
2415 [super keyUp:theEvent]; | |
2416 } | |
2417 | |
2418 -(void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn | |
2419 { | |
2420 NSUInteger index = [tvcols indexOfObject:tableColumn]; | |
2421 | |
2422 /* Handler for column click class */ | |
2423 _event_handler(self, (NSEvent *)index, 17); | |
2424 } | |
2425 -(void)selectionChanged:(id)sender | |
2426 { | |
2427 void *params[2]; | |
2428 | |
2429 params[0] = (void *)[self getRowTitle:(int)[self selectedRow]]; | |
2430 params[1] = (void *)[self getRowData:(int)[self selectedRow]]; | |
2431 | |
2432 /* Handler for container class */ | |
2433 _event_handler(self, (NSEvent *)params, 12); | |
2434 /* Handler for listbox class */ | |
2435 _event_handler(self, DW_INT_TO_POINTER((int)[self selectedRow]), 11); | |
2436 } | |
2437 -(NSMenu *)menuForEvent:(NSEvent *)event | |
2438 { | |
2439 int row; | |
2440 NSPoint where = [self convertPoint:[event locationInWindow] fromView:nil]; | |
2441 row = (int)[self rowAtPoint:where]; | |
2442 _event_handler(self, (NSEvent *)[self getRowTitle:row], 10); | |
2443 return nil; | |
2444 } | |
2445 -(void)keyDown:(NSEvent *)theEvent | |
2446 { | |
2447 unichar vk = [[theEvent charactersIgnoringModifiers] characterAtIndex:0]; | |
2448 | |
2449 if(vk == NSTabCharacter || vk == NSBackTabCharacter) | |
2450 [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; | |
2451 [super keyDown:theEvent]; | |
2452 } | |
2453 -(void)insertTab:(id)sender { if([[self window] firstResponder] == self) [[self window] selectNextKeyView:self]; } | |
2454 -(void)insertBacktab:(id)sender { if([[self window] firstResponder] == self) [[self window] selectPreviousKeyView:self]; } | |
2455 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
2456 @end | |
2457 | |
2458 /* Dive into the tree freeing all desired child nodes */ | |
2459 void _free_tree_recurse(NSMutableArray *node, NSMutableArray *item) | |
2460 { | |
2461 if(node && ([node isKindOfClass:[NSArray class]])) | |
2462 { | |
2463 int count = (int)[node count]; | |
2464 NSInteger index = -1; | |
2465 int z; | |
2466 | |
2467 if(item) | |
2468 index = [node indexOfObject:item]; | |
2469 | |
2470 for(z=0;z<count;z++) | |
2471 { | |
2472 NSMutableArray *pnt = [node objectAtIndex:z]; | |
2473 NSMutableArray *children = nil; | |
2474 | |
2475 if(pnt && [pnt isKindOfClass:[NSArray class]]) | |
2476 { | |
2477 children = (NSMutableArray *)[pnt objectAtIndex:3]; | |
2478 } | |
2479 | |
2480 if(z == index) | |
2481 { | |
2482 _free_tree_recurse(children, NULL); | |
2483 [node removeObjectAtIndex:z]; | |
2484 count = (int)[node count]; | |
2485 index = -1; | |
2486 z--; | |
2487 } | |
2488 else if(item == NULL) | |
2489 { | |
2490 NSString *oldstr = [pnt objectAtIndex:1]; | |
2491 [oldstr release]; | |
2492 _free_tree_recurse(children, item); | |
2493 } | |
2494 else | |
2495 _free_tree_recurse(children, item); | |
2496 } | |
2497 } | |
2498 if(!item) | |
2499 { | |
2500 [node release]; | |
2501 } | |
2502 } | |
2503 | |
2504 /* Subclass for a Tree type */ | |
2505 @interface DWTree : NSOutlineView <NSOutlineViewDataSource,NSOutlineViewDelegate> | |
2506 { | |
2507 void *userdata; | |
2508 NSTableColumn *treecol; | |
2509 NSMutableArray *data; | |
2510 /* Each data item consists of a linked lists of tree item data. | |
2511 * UIImage *, NSString *, Item Data *, NSMutableArray * of Children | |
2512 */ | |
2513 id scrollview; | |
2514 UIColor *fgcolor; | |
2515 } | |
2516 -(id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item; | |
2517 -(BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item; | |
2518 -(int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item; | |
2519 -(UIView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item; | |
2520 -(BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item; | |
2521 -(void)addTree:(NSMutableArray *)item and:(NSMutableArray *)parent after:(NSMutableArray *)after; | |
2522 -(void *)userdata; | |
2523 -(void)setUserdata:(void *)input; | |
2524 -(void)treeSelectionChanged:(id)sender; | |
2525 -(void)treeItemExpanded:(NSNotification *)notification; | |
2526 -(UIScrollView *)scrollview; | |
2527 -(void)setScrollview:(UIScrollView *)input; | |
2528 -(void)deleteNode:(NSMutableArray *)item; | |
2529 -(void)setForegroundColor:(UIColor *)input; | |
2530 -(void)clear; | |
2531 @end | |
2532 | |
2533 @implementation DWTree | |
2534 -(id)init | |
2535 { | |
2536 self = [super init]; | |
2537 | |
2538 if (self) | |
2539 { | |
2540 treecol = [[NSTableColumn alloc] initWithIdentifier:@"_DWTreeColumn"]; | |
2541 [self addTableColumn:treecol]; | |
2542 [self setOutlineTableColumn:treecol]; | |
2543 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(treeSelectionChanged:) name:NSOutlineViewSelectionDidChangeNotification object:self]; | |
2544 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(treeItemExpanded:) name:NSOutlineViewItemDidExpandNotification object:self]; | |
2545 } | |
2546 return self; | |
2547 } | |
2548 -(id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item | |
2549 { | |
2550 if(item) | |
2551 { | |
2552 NSMutableArray *array = [item objectAtIndex:3]; | |
2553 return ([array isKindOfClass:[NSNull class]]) ? nil : [array objectAtIndex:index]; | |
2554 } | |
2555 else | |
2556 { | |
2557 return [data objectAtIndex:index]; | |
2558 } | |
2559 } | |
2560 -(BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item | |
2561 { | |
2562 return [self outlineView:outlineView numberOfChildrenOfItem:item] != 0; | |
2563 } | |
2564 -(int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item | |
2565 { | |
2566 if(item) | |
2567 { | |
2568 if([item isKindOfClass:[NSMutableArray class]]) | |
2569 { | |
2570 NSMutableArray *array = [item objectAtIndex:3]; | |
2571 return ([array isKindOfClass:[NSNull class]]) ? 0 : (int)[array count]; | |
2572 } | |
2573 else | |
2574 { | |
2575 return 0; | |
2576 } | |
2577 } | |
2578 else | |
2579 { | |
2580 return data ? (int)[data count] : 0; | |
2581 } | |
2582 } | |
2583 -(UIView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item | |
2584 { | |
2585 NSTableCellView *view = [outlineView makeViewWithIdentifier:[tableColumn identifier] owner:self]; | |
2586 | |
2587 if([item isKindOfClass:[NSMutableArray class]]) | |
2588 { | |
2589 NSMutableArray *this = (NSMutableArray *)item; | |
2590 UIImage *icon = [this objectAtIndex:0]; | |
2591 NSString *text = [this objectAtIndex:1]; | |
2592 if(![icon isKindOfClass:[UIImage class]]) | |
2593 icon = nil; | |
2594 if(view) | |
2595 { | |
2596 UITextField *tf = [view textField]; | |
2597 UIImageView *iv = [view imageView]; | |
2598 | |
2599 if(tf) | |
2600 { | |
2601 [tf setStringValue: text]; | |
2602 if(fgcolor) | |
2603 [tf setTextColor:fgcolor]; | |
2604 } | |
2605 if(iv) | |
2606 [iv setImage:icon]; | |
2607 } | |
2608 else | |
2609 view = _dw_table_cell_view_new(icon, text); | |
2610 } | |
2611 _dw_table_cell_view_layout(view); | |
2612 return view; | |
2613 } | |
2614 -(BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item { return NO; } | |
2615 -(void)addTree:(NSMutableArray *)item and:(NSMutableArray *)parent after:(NSMutableArray *)after | |
2616 { | |
2617 NSMutableArray *children = data; | |
2618 if(parent) | |
2619 { | |
2620 children = [parent objectAtIndex:3]; | |
2621 if([children isKindOfClass:[NSNull class]]) | |
2622 { | |
2623 children = [[[NSMutableArray alloc] init] retain]; | |
2624 [parent replaceObjectAtIndex:3 withObject:children]; | |
2625 } | |
2626 } | |
2627 else | |
2628 { | |
2629 if(!data) | |
2630 { | |
2631 children = data = [[[NSMutableArray alloc] init] retain]; | |
2632 } | |
2633 } | |
2634 if(after) | |
2635 { | |
2636 NSInteger index = [children indexOfObject:after]; | |
2637 int count = (int)[children count]; | |
2638 if(index != NSNotFound && (index+1) < count) | |
2639 [children insertObject:item atIndex:(index+1)]; | |
2640 else | |
2641 [children addObject:item]; | |
2642 } | |
2643 else | |
2644 { | |
2645 [children addObject:item]; | |
2646 } | |
2647 } | |
2648 -(void *)userdata { return userdata; } | |
2649 -(void)setUserdata:(void *)input { userdata = input; } | |
2650 -(void)treeSelectionChanged:(id)sender | |
2651 { | |
2652 /* Handler for tree class */ | |
2653 id item = [self itemAtRow:[self selectedRow]]; | |
2654 | |
2655 if(item) | |
2656 { | |
2657 _event_handler(self, (void *)item, 12); | |
2658 } | |
2659 } | |
2660 -(void)treeItemExpanded:(NSNotification *)notification | |
2661 { | |
2662 id item = [[notification userInfo ] objectForKey: @"NSObject"]; | |
2663 | |
2664 if(item) | |
2665 { | |
2666 _event_handler(self, (void *)item, 16); | |
2667 } | |
2668 } | |
2669 -(NSMenu *)menuForEvent:(NSEvent *)event | |
2670 { | |
2671 int row; | |
2672 NSPoint where = [self convertPoint:[event locationInWindow] fromView:nil]; | |
2673 row = (int)[self rowAtPoint:where]; | |
2674 id item = [self itemAtRow:row]; | |
2675 _event_handler(self, (NSEvent *)item, 10); | |
2676 return nil; | |
2677 } | |
2678 -(UIScrollView *)scrollview { return scrollview; } | |
2679 -(void)setScrollview:(UIScrollView *)input { scrollview = input; } | |
2680 -(void)deleteNode:(NSMutableArray *)item { _free_tree_recurse(data, item); } | |
2681 -(void)setForegroundColor:(UIColor *)input | |
2682 { | |
2683 UITextFieldCell *cell = [treecol dataCell]; | |
2684 fgcolor = input; | |
2685 [fgcolor retain]; | |
2686 [cell setTextColor:fgcolor]; | |
2687 } | |
2688 -(void)clear { NSMutableArray *toclear = data; data = nil; _free_tree_recurse(toclear, NULL); [self reloadData]; } | |
2689 -(void)keyDown:(NSEvent *)theEvent | |
2690 { | |
2691 unichar vk = [[theEvent charactersIgnoringModifiers] characterAtIndex:0]; | |
2692 | |
2693 if(vk == NSTabCharacter || vk == NSBackTabCharacter) | |
2694 [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; | |
2695 [super keyDown:theEvent]; | |
2696 } | |
2697 -(void)insertTab:(id)sender { if([[self window] firstResponder] == self) [[self window] selectNextKeyView:self]; } | |
2698 -(void)insertBacktab:(id)sender { if([[self window] firstResponder] == self) [[self window] selectPreviousKeyView:self]; } | |
2699 -(void)dealloc | |
2700 { | |
2701 UserData *root = userdata; | |
2702 _remove_userdata(&root, NULL, TRUE); | |
2703 _free_tree_recurse(data, NULL); | |
2704 [treecol release]; | |
2705 dw_signal_disconnect_by_window(self); | |
2706 [super dealloc]; | |
2707 } | |
2708 @end | |
2709 | |
2710 /* Subclass for a Calendar type */ | |
2711 @interface DWCalendar : UIDatePicker | |
2712 { | |
2713 void *userdata; | |
2714 } | |
2715 -(void *)userdata; | |
2716 -(void)setUserdata:(void *)input; | |
2717 @end | |
2718 | |
2719 @implementation DWCalendar | |
2720 -(void *)userdata { return userdata; } | |
2721 -(void)setUserdata:(void *)input { userdata = input; } | |
2722 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
2723 @end | |
2724 | |
2725 /* Subclass for a Combobox type */ | |
2726 @interface DWComboBox : NSComboBox <NSComboBoxDelegate> | |
2727 { | |
2728 void *userdata; | |
2729 id clickDefault; | |
2730 } | |
2731 -(void *)userdata; | |
2732 -(void)setUserdata:(void *)input; | |
2733 -(void)comboBoxSelectionDidChange:(NSNotification *)not; | |
2734 -(void)setClickDefault:(id)input; | |
2735 @end | |
2736 | |
2737 @implementation DWComboBox | |
2738 -(void *)userdata { return userdata; } | |
2739 -(void)setUserdata:(void *)input { userdata = input; } | |
2740 -(void)comboBoxSelectionDidChange:(NSNotification *)not { _event_handler(self, (void *)[self indexOfSelectedItem], 11); } | |
2741 -(void)setClickDefault:(id)input { clickDefault = input; } | |
2742 -(void)keyUp:(NSEvent *)theEvent | |
2743 { | |
2744 if(clickDefault && [[theEvent charactersIgnoringModifiers] characterAtIndex:0] == VK_RETURN) | |
2745 { | |
2746 [[self window] makeFirstResponder:clickDefault]; | |
2747 } else | |
2748 { | |
2749 [super keyUp:theEvent]; | |
2750 } | |
2751 } | |
2752 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
2753 @end | |
2754 | |
2755 /* Subclass for a stepper component of the spinbutton type */ | |
2756 /* This is a bad way of doing this... but I can't get the other methods to work */ | |
2757 @interface DWStepper : UIStepper | |
2758 { | |
2759 id textfield; | |
2760 id parent; | |
2761 } | |
2762 -(void)setTextfield:(id)input; | |
2763 -(id)textfield; | |
2764 -(void)setParent:(id)input; | |
2765 -(id)parent; | |
2766 -(void)mouseDown:(NSEvent *)event; | |
2767 -(void)mouseUp:(NSEvent *)event; | |
2768 @end | |
2769 | |
2770 @implementation DWStepper | |
2771 -(void)setTextfield:(id)input { textfield = input; } | |
2772 -(id)textfield { return textfield; } | |
2773 -(void)setParent:(id)input { parent = input; } | |
2774 -(id)parent { return parent; } | |
2775 -(void)mouseDown:(NSEvent *)event | |
2776 { | |
2777 [super mouseDown:event]; | |
2778 if([[NSApp currentEvent] type] == DWEventTypeLeftMouseUp) | |
2779 [self mouseUp:event]; | |
2780 } | |
2781 -(void)mouseUp:(NSEvent *)event | |
2782 { | |
2783 [textfield takeIntValueFrom:self]; | |
2784 _event_handler(parent, (void *)[self integerValue], 14); | |
2785 } | |
2786 -(void)keyDown:(NSEvent *)theEvent | |
2787 { | |
2788 unichar vk = [[theEvent charactersIgnoringModifiers] characterAtIndex:0]; | |
2789 if(vk == VK_UP || vk == VK_DOWN) | |
2790 { | |
2791 if(vk == VK_UP) | |
2792 [self setIntegerValue:([self integerValue]+[self increment])]; | |
2793 else | |
2794 [self setIntegerValue:([self integerValue]-[self increment])]; | |
2795 [self mouseUp:theEvent]; | |
2796 } | |
2797 else | |
2798 { | |
2799 [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; | |
2800 [super keyDown:theEvent]; | |
2801 } | |
2802 } | |
2803 -(void)insertTab:(id)sender { if([[self window] firstResponder] == self) [[self window] selectNextKeyView:self]; } | |
2804 -(void)insertBacktab:(id)sender { if([[self window] firstResponder] == self) [[self window] selectPreviousKeyView:self]; } | |
2805 @end | |
2806 | |
2807 /* Subclass for a Spinbutton type */ | |
2808 @interface DWSpinButton : UIView <UITextFieldDelegate> | |
2809 { | |
2810 void *userdata; | |
2811 UITextField *textfield; | |
2812 DWStepper *stepper; | |
2813 id clickDefault; | |
2814 } | |
2815 -(id)init; | |
2816 -(void *)userdata; | |
2817 -(void)setUserdata:(void *)input; | |
2818 -(UITextField *)textfield; | |
2819 -(UIStepper *)stepper; | |
2820 -(void)controlTextDidChange:(NSNotification *)aNotification; | |
2821 -(void)setClickDefault:(id)input; | |
2822 @end | |
2823 | |
2824 @implementation DWSpinButton | |
2825 -(id)init | |
2826 { | |
2827 self = [super init]; | |
2828 | |
2829 if(self) | |
2830 { | |
2831 textfield = [[[UITextField alloc] init] autorelease]; | |
2832 /* Workaround for infinite loop in Snow Leopard 10.6 */ | |
2833 if(DWOSMajor == 10 && DWOSMinor < 7) | |
2834 [textfield setFrameSize:NSMakeSize(10,10)]; | |
2835 [self addSubview:textfield]; | |
2836 stepper = [[[DWStepper alloc] init] autorelease]; | |
2837 [self addSubview:stepper]; | |
2838 [stepper setParent:self]; | |
2839 [stepper setTextfield:textfield]; | |
2840 [textfield takeIntValueFrom:stepper]; | |
2841 [textfield setDelegate:self]; | |
2842 } | |
2843 return self; | |
2844 } | |
2845 -(void *)userdata { return userdata; } | |
2846 -(void)setUserdata:(void *)input { userdata = input; } | |
2847 -(UITextField *)textfield { return textfield; } | |
2848 -(UIStepper *)stepper { return stepper; } | |
2849 -(void)controlTextDidChange:(NSNotification *)aNotification | |
2850 { | |
2851 [stepper takeIntValueFrom:textfield]; | |
2852 [textfield takeIntValueFrom:stepper]; | |
2853 _event_handler(self, (void *)[stepper integerValue], 14); | |
2854 } | |
2855 -(void)setClickDefault:(id)input { clickDefault = input; } | |
2856 -(void)keyUp:(NSEvent *)theEvent | |
2857 { | |
2858 if(clickDefault && [[theEvent charactersIgnoringModifiers] characterAtIndex:0] == VK_RETURN) | |
2859 { | |
2860 [[self window] makeFirstResponder:clickDefault]; | |
2861 } | |
2862 else | |
2863 { | |
2864 [super keyUp:theEvent]; | |
2865 } | |
2866 } | |
2867 -(void)performClick:(id)sender { [textfield performClick:sender]; } | |
2868 -(void)dealloc { UserData *root = userdata; _remove_userdata(&root, NULL, TRUE); dw_signal_disconnect_by_window(self); [super dealloc]; } | |
2869 @end | |
2870 | |
2871 API_AVAILABLE(ios(10.0)) | |
2872 @interface DWUserNotificationCenterDelegate : NSObject <UNUserNotificationCenterDelegate> | |
2873 @end | |
2874 | |
2875 @implementation DWUserNotificationCenterDelegate | |
2876 /* Called when a notification is delivered to a foreground app. */ | |
2877 -(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler API_AVAILABLE(macos(10.14)) | |
2878 { | |
2879 completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge); | |
2880 } | |
2881 /* Called to let your app know which action was selected by the user for a given notification. */ | |
2882 -(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler API_AVAILABLE(macos(10.14)) | |
2883 { | |
2884 NSScanner *objScanner = [NSScanner scannerWithString:response.notification.request.identifier]; | |
2885 unsigned long long handle; | |
2886 HWND notification; | |
2887 | |
2888 /* Skip the dw-notification- prefix */ | |
2889 [objScanner scanString:@"dw-notification-" intoString:nil]; | |
2890 [objScanner scanUnsignedLongLong:&handle]; | |
2891 notification = DW_UINT_TO_POINTER(handle); | |
2892 | |
2893 if ([response.actionIdentifier isEqualToString:UNNotificationDismissActionIdentifier]) | |
2894 { | |
2895 /* The user dismissed the notification without taking action. */ | |
2896 dw_signal_disconnect_by_window(notification); | |
2897 } | |
2898 else if ([response.actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier]) | |
2899 { | |
2900 /* The user launched the app. */ | |
2901 _event_handler(notification, nil, 8); | |
2902 dw_signal_disconnect_by_window(notification); | |
2903 } | |
2904 completionHandler(); | |
2905 } | |
2906 @end | |
2907 | |
2908 /* Subclass for a MDI type | |
2909 * This is just a box for display purposes... but it is a | |
2910 * unique class so it can be identified when creating windows. | |
2911 */ | |
2912 @interface DWMDI : DWBox {} | |
2913 @end | |
2914 | |
2915 @implementation DWMDI | |
2916 @end | |
2917 | |
2918 /* This function adds a signal handler callback into the linked list. | |
2919 */ | |
2920 void _new_signal(ULONG message, HWND window, int msgid, void *signalfunction, void *discfunc, void *data) | |
2921 { | |
2922 SignalHandler *new = malloc(sizeof(SignalHandler)); | |
2923 | |
2924 new->message = message; | |
2925 new->window = window; | |
2926 new->id = msgid; | |
2927 new->signalfunction = signalfunction; | |
2928 new->discfunction = discfunc; | |
2929 new->data = data; | |
2930 new->next = NULL; | |
2931 | |
2932 if (!Root) | |
2933 Root = new; | |
2934 else | |
2935 { | |
2936 SignalHandler *prev = NULL, *tmp = Root; | |
2937 while(tmp) | |
2938 { | |
2939 if(tmp->message == message && | |
2940 tmp->window == window && | |
2941 tmp->id == msgid && | |
2942 tmp->signalfunction == signalfunction) | |
2943 { | |
2944 tmp->data = data; | |
2945 free(new); | |
2946 return; | |
2947 } | |
2948 prev = tmp; | |
2949 tmp = tmp->next; | |
2950 } | |
2951 if(prev) | |
2952 prev->next = new; | |
2953 else | |
2954 Root = new; | |
2955 } | |
2956 } | |
2957 | |
2958 /* Finds the message number for a given signal name */ | |
2959 ULONG _findsigmessage(const char *signame) | |
2960 { | |
2961 int z; | |
2962 | |
2963 for(z=0;z<SIGNALMAX;z++) | |
2964 { | |
2965 if(strcasecmp(signame, SignalTranslate[z].name) == 0) | |
2966 return SignalTranslate[z].message; | |
2967 } | |
2968 return 0L; | |
2969 } | |
2970 | |
2971 unsigned long _foreground = 0xAAAAAA, _background = 0; | |
2972 | |
2973 void _handle_resize_events(Box *thisbox) | |
2974 { | |
2975 int z; | |
2976 | |
2977 for(z=0;z<thisbox->count;z++) | |
2978 { | |
2979 id handle = thisbox->items[z].hwnd; | |
2980 | |
2981 if(thisbox->items[z].type == TYPEBOX) | |
2982 { | |
2983 Box *tmp = (Box *)[handle box]; | |
2984 | |
2985 if(tmp) | |
2986 { | |
2987 _handle_resize_events(tmp); | |
2988 } | |
2989 } | |
2990 else | |
2991 { | |
2992 if([handle isMemberOfClass:[DWRender class]]) | |
2993 { | |
2994 DWRender *render = (DWRender *)handle; | |
2995 NSSize oldsize = [render size]; | |
2996 NSSize newsize = [render frame].size; | |
2997 | |
2998 /* Eliminate duplicate configure requests */ | |
2999 if(oldsize.width != newsize.width || oldsize.height != newsize.height) | |
3000 { | |
3001 if(newsize.width > 0 && newsize.height > 0) | |
3002 { | |
3003 [render setSize:newsize]; | |
3004 _event_handler(handle, nil, 1); | |
3005 } | |
3006 } | |
3007 } | |
3008 /* Special handling for notebook controls */ | |
3009 else if([handle isMemberOfClass:[DWNotebook class]]) | |
3010 { | |
3011 DWNotebook *notebook = (DWNotebook *)handle; | |
3012 DWNotebookPage *notepage = (DWNotebookPage *)[notebook selectedTabViewItem]; | |
3013 id view = [notepage view]; | |
3014 | |
3015 if([view isMemberOfClass:[DWBox class]]) | |
3016 { | |
3017 Box *box = (Box *)[view box]; | |
3018 _handle_resize_events(box); | |
3019 } | |
3020 } | |
3021 /* Handle laying out scrollviews... if required space is less | |
3022 * than available space, then expand. Otherwise use required space. | |
3023 */ | |
3024 else if([handle isMemberOfClass:[DWScrollBox class]]) | |
3025 { | |
3026 DWScrollBox *scrollbox = (DWScrollBox *)handle; | |
3027 DWBox *contentbox = [scrollbox documentView]; | |
3028 Box *thisbox = [contentbox box]; | |
3029 | |
3030 /* Get the required space for the box */ | |
3031 _handle_resize_events(thisbox); | |
3032 } | |
3033 } | |
3034 } | |
3035 } | |
3036 | |
3037 /* This function calculates how much space the widgets and boxes require | |
3038 * and does expansion as necessary. | |
3039 */ | |
3040 static void _resize_box(Box *thisbox, int *depth, int x, int y, int pass) | |
3041 { | |
3042 /* Current item position */ | |
3043 int z, currentx = thisbox->pad, currenty = thisbox->pad; | |
3044 /* Used x, y and padding maximum values... | |
3045 * These will be used to find the widest or | |
3046 * tallest items in a box. | |
3047 */ | |
3048 int uymax = 0, uxmax = 0; | |
3049 int upymax = 0, upxmax = 0; | |
3050 | |
3051 /* Reset the box sizes */ | |
3052 thisbox->minwidth = thisbox->minheight = thisbox->usedpadx = thisbox->usedpady = thisbox->pad * 2; | |
3053 | |
3054 /* Handle special groupbox case */ | |
3055 if(thisbox->grouphwnd) | |
3056 { | |
3057 /* Only calculate the size on the first pass... | |
3058 * use the cached values on second. | |
3059 */ | |
3060 if(pass == 1) | |
3061 { | |
3062 DWGroupBox *groupbox = thisbox->grouphwnd; | |
3063 NSSize borderSize = [groupbox borderSize]; | |
3064 NSRect titleRect; | |
3065 | |
3066 if(borderSize.width == 0 || borderSize.height == 0) | |
3067 { | |
3068 borderSize = [groupbox initBorder]; | |
3069 } | |
3070 /* Get the title size for a more accurate groupbox padding size */ | |
3071 titleRect = [groupbox titleRect]; | |
3072 | |
3073 thisbox->grouppadx = borderSize.width; | |
3074 thisbox->grouppady = borderSize.height + titleRect.size.height; | |
3075 } | |
3076 | |
3077 thisbox->minwidth += thisbox->grouppadx; | |
3078 thisbox->usedpadx += thisbox->grouppadx; | |
3079 thisbox->minheight += thisbox->grouppady; | |
3080 thisbox->usedpady += thisbox->grouppady; | |
3081 } | |
3082 | |
3083 /* Count up all the space for all items in the box */ | |
3084 for(z=0;z<thisbox->count;z++) | |
3085 { | |
3086 int itempad, itemwidth, itemheight; | |
3087 | |
3088 if(thisbox->items[z].type == TYPEBOX) | |
3089 { | |
3090 id box = thisbox->items[z].hwnd; | |
3091 Box *tmp = (Box *)[box box]; | |
3092 | |
3093 if(tmp) | |
3094 { | |
3095 /* On the first pass calculate the box contents */ | |
3096 if(pass == 1) | |
3097 { | |
3098 (*depth)++; | |
3099 | |
3100 /* Save the newly calculated values on the box */ | |
3101 _resize_box(tmp, depth, x, y, pass); | |
3102 | |
3103 /* Duplicate the values in the item list for use below */ | |
3104 thisbox->items[z].width = tmp->minwidth; | |
3105 thisbox->items[z].height = tmp->minheight; | |
3106 | |
3107 /* If the box has no contents but is expandable... default the size to 1 */ | |
3108 if(!thisbox->items[z].width && thisbox->items[z].hsize) | |
3109 thisbox->items[z].width = 1; | |
3110 if(!thisbox->items[z].height && thisbox->items[z].vsize) | |
3111 thisbox->items[z].height = 1; | |
3112 | |
3113 (*depth)--; | |
3114 } | |
3115 } | |
3116 } | |
3117 | |
3118 /* Precalculate these values, since they will | |
3119 * be used used repeatedly in the next section. | |
3120 */ | |
3121 itempad = thisbox->items[z].pad * 2; | |
3122 itemwidth = thisbox->items[z].width + itempad; | |
3123 itemheight = thisbox->items[z].height + itempad; | |
3124 | |
3125 /* Calculate the totals and maximums */ | |
3126 if(thisbox->type == DW_VERT) | |
3127 { | |
3128 if(itemwidth > uxmax) | |
3129 uxmax = itemwidth; | |
3130 | |
3131 if(thisbox->items[z].hsize != SIZEEXPAND) | |
3132 { | |
3133 if(itemwidth > upxmax) | |
3134 upxmax = itemwidth; | |
3135 } | |
3136 else | |
3137 { | |
3138 if(itempad > upxmax) | |
3139 upxmax = itempad; | |
3140 } | |
3141 thisbox->minheight += itemheight; | |
3142 if(thisbox->items[z].vsize != SIZEEXPAND) | |
3143 thisbox->usedpady += itemheight; | |
3144 else | |
3145 thisbox->usedpady += itempad; | |
3146 } | |
3147 else | |
3148 { | |
3149 if(itemheight > uymax) | |
3150 uymax = itemheight; | |
3151 if(thisbox->items[z].vsize != SIZEEXPAND) | |
3152 { | |
3153 if(itemheight > upymax) | |
3154 upymax = itemheight; | |
3155 } | |
3156 else | |
3157 { | |
3158 if(itempad > upymax) | |
3159 upymax = itempad; | |
3160 } | |
3161 thisbox->minwidth += itemwidth; | |
3162 if(thisbox->items[z].hsize != SIZEEXPAND) | |
3163 thisbox->usedpadx += itemwidth; | |
3164 else | |
3165 thisbox->usedpadx += itempad; | |
3166 } | |
3167 } | |
3168 | |
3169 /* Add the maximums which were calculated in the previous loop */ | |
3170 thisbox->minwidth += uxmax; | |
3171 thisbox->minheight += uymax; | |
3172 thisbox->usedpadx += upxmax; | |
3173 thisbox->usedpady += upymax; | |
3174 | |
3175 /* The second pass is for actual placement. */ | |
3176 if(pass > 1) | |
3177 { | |
3178 for(z=0;z<(thisbox->count);z++) | |
3179 { | |
3180 int height = thisbox->items[z].height; | |
3181 int width = thisbox->items[z].width; | |
3182 int itempad = thisbox->items[z].pad * 2; | |
3183 int thispad = thisbox->pad * 2; | |
3184 | |
3185 /* Calculate the new sizes */ | |
3186 if(thisbox->items[z].hsize == SIZEEXPAND) | |
3187 { | |
3188 if(thisbox->type == DW_HORZ) | |
3189 { | |
3190 int expandablex = thisbox->minwidth - thisbox->usedpadx; | |
3191 | |
3192 if(expandablex) | |
3193 width = (int)(((float)width / (float)expandablex) * (float)(x - thisbox->usedpadx)); | |
3194 } | |
3195 else | |
3196 width = x - (itempad + thispad + thisbox->grouppadx); | |
3197 } | |
3198 if(thisbox->items[z].vsize == SIZEEXPAND) | |
3199 { | |
3200 if(thisbox->type == DW_VERT) | |
3201 { | |
3202 int expandabley = thisbox->minheight - thisbox->usedpady; | |
3203 | |
3204 if(expandabley) | |
3205 height = (int)(((float)height / (float)expandabley) * (float)(y - thisbox->usedpady)); | |
3206 } | |
3207 else | |
3208 height = y - (itempad + thispad + thisbox->grouppady); | |
3209 } | |
3210 | |
3211 /* If the calculated size is valid... */ | |
3212 if(height > 0 && width > 0) | |
3213 { | |
3214 int pad = thisbox->items[z].pad; | |
3215 UIView *handle = thisbox->items[z].hwnd; | |
3216 NSPoint point; | |
3217 NSSize size; | |
3218 | |
3219 point.x = currentx + pad; | |
3220 point.y = currenty + pad; | |
3221 size.width = width; | |
3222 size.height = height; | |
3223 [handle setFrameOrigin:point]; | |
3224 [handle setFrameSize:size]; | |
3225 | |
3226 /* After placing a box... place its components */ | |
3227 if(thisbox->items[z].type == TYPEBOX) | |
3228 { | |
3229 id box = thisbox->items[z].hwnd; | |
3230 Box *tmp = (Box *)[box box]; | |
3231 | |
3232 if(tmp) | |
3233 { | |
3234 (*depth)++; | |
3235 _resize_box(tmp, depth, width, height, pass); | |
3236 (*depth)--; | |
3237 } | |
3238 } | |
3239 | |
3240 /* Special handling for notebook controls */ | |
3241 if([handle isMemberOfClass:[DWNotebook class]]) | |
3242 { | |
3243 DWNotebook *notebook = (DWNotebook *)handle; | |
3244 DWNotebookPage *notepage = (DWNotebookPage *)[notebook selectedTabViewItem]; | |
3245 id view = [notepage view]; | |
3246 | |
3247 if([view isMemberOfClass:[DWBox class]]) | |
3248 { | |
3249 Box *box = (Box *)[view box]; | |
3250 NSSize size = [view frame].size; | |
3251 _do_resize(box, size.width, size.height); | |
3252 _handle_resize_events(box); | |
3253 } | |
3254 } | |
3255 /* Handle laying out scrollviews... if required space is less | |
3256 * than available space, then expand. Otherwise use required space. | |
3257 */ | |
3258 else if([handle isMemberOfClass:[DWScrollBox class]]) | |
3259 { | |
3260 int depth = 0; | |
3261 DWScrollBox *scrollbox = (DWScrollBox *)handle; | |
3262 DWBox *contentbox = [scrollbox documentView]; | |
3263 Box *thisbox = [contentbox box]; | |
3264 NSSize contentsize = [scrollbox contentSize]; | |
3265 | |
3266 /* Get the required space for the box */ | |
3267 _resize_box(thisbox, &depth, x, y, 1); | |
3268 | |
3269 if(contentsize.width < thisbox->minwidth) | |
3270 { | |
3271 contentsize.width = thisbox->minwidth; | |
3272 } | |
3273 if(contentsize.height < thisbox->minheight) | |
3274 { | |
3275 contentsize.height = thisbox->minheight; | |
3276 } | |
3277 [contentbox setFrameSize:contentsize]; | |
3278 | |
3279 /* Layout the content of the scrollbox */ | |
3280 _do_resize(thisbox, contentsize.width, contentsize.height); | |
3281 _handle_resize_events(thisbox); | |
3282 } | |
3283 /* Special handling for spinbutton controls */ | |
3284 else if([handle isMemberOfClass:[DWSpinButton class]]) | |
3285 { | |
3286 DWSpinButton *spinbutton = (DWSpinButton *)handle; | |
3287 UITextField *textfield = [spinbutton textfield]; | |
3288 UIStepper *stepper = [spinbutton stepper]; | |
3289 [textfield setFrameOrigin:NSMakePoint(0,0)]; | |
3290 [textfield setFrameSize:NSMakeSize(size.width-20,size.height)]; | |
3291 [stepper setFrameOrigin:NSMakePoint(size.width-20,0)]; | |
3292 [stepper setFrameSize:NSMakeSize(20,size.height)]; | |
3293 } | |
3294 else if([handle isMemberOfClass:[DWSplitBar class]]) | |
3295 { | |
3296 DWSplitBar *split = (DWSplitBar *)handle; | |
3297 DWWindow *window = (DWWindow *)[split window]; | |
3298 float percent = [split percent]; | |
3299 | |
3300 if(percent > 0 && size.width > 20 && size.height > 20) | |
3301 { | |
3302 dw_splitbar_set(handle, percent); | |
3303 [split setPercent:0]; | |
3304 } | |
3305 else if([window redraw]) | |
3306 { | |
3307 [split splitViewDidResizeSubviews:nil]; | |
3308 } | |
3309 } | |
3310 | |
3311 /* Advance the current position in the box */ | |
3312 if(thisbox->type == DW_HORZ) | |
3313 currentx += width + (pad * 2); | |
3314 if(thisbox->type == DW_VERT) | |
3315 currenty += height + (pad * 2); | |
3316 } | |
3317 } | |
3318 } | |
3319 } | |
3320 | |
3321 static void _do_resize(Box *thisbox, int x, int y) | |
3322 { | |
3323 if(x > 0 && y > 0) | |
3324 { | |
3325 if(thisbox) | |
3326 { | |
3327 int depth = 0; | |
3328 | |
3329 /* Calculate space requirements */ | |
3330 _resize_box(thisbox, &depth, x, y, 1); | |
3331 | |
3332 /* Finally place all the boxes and controls */ | |
3333 _resize_box(thisbox, &depth, x, y, 2); | |
3334 } | |
3335 } | |
3336 } | |
3337 | |
3338 NSMenu *_generate_main_menu() | |
3339 { | |
3340 NSString *applicationName = nil; | |
3341 | |
3342 applicationName = [[NSRunningApplication currentApplication] localizedName]; | |
3343 if(applicationName == nil) | |
3344 { | |
3345 applicationName = [[NSProcessInfo processInfo] processName]; | |
3346 } | |
3347 | |
3348 /* Create the main menu */ | |
3349 NSMenu * mainMenu = [[[NSMenu alloc] initWithTitle:@"MainMenu"] autorelease]; | |
3350 | |
3351 NSMenuItem * mitem = [mainMenu addItemWithTitle:@"Apple" action:NULL keyEquivalent:@""]; | |
3352 NSMenu * menu = [[[NSMenu alloc] initWithTitle:@"Apple"] autorelease]; | |
3353 | |
3354 [DWApp performSelector:@selector(setAppleMenu:) withObject:menu]; | |
3355 | |
3356 /* Setup the Application menu */ | |
3357 NSMenuItem * item = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"About", nil), applicationName] | |
3358 action:@selector(orderFrontStandardAboutPanel:) | |
3359 keyEquivalent:@""]; | |
3360 [item setTarget:DWApp]; | |
3361 | |
3362 [menu addItem:[NSMenuItem separatorItem]]; | |
3363 | |
3364 item = [menu addItemWithTitle:NSLocalizedString(@"Services", nil) | |
3365 action:NULL | |
3366 keyEquivalent:@""]; | |
3367 NSMenu * servicesMenu = [[[NSMenu alloc] initWithTitle:@"Services"] autorelease]; | |
3368 [menu setSubmenu:servicesMenu forItem:item]; | |
3369 [DWApp setServicesMenu:servicesMenu]; | |
3370 | |
3371 [menu addItem:[NSMenuItem separatorItem]]; | |
3372 | |
3373 item = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"Hide", nil), applicationName] | |
3374 action:@selector(hide:) | |
3375 keyEquivalent:@"h"]; | |
3376 [item setTarget:DWApp]; | |
3377 | |
3378 item = [menu addItemWithTitle:NSLocalizedString(@"Hide Others", nil) | |
3379 action:@selector(hideOtherApplications:) | |
3380 keyEquivalent:@"h"]; | |
3381 [item setKeyEquivalentModifierMask:DWEventModifierFlagCommand | DWEventModifierFlagOption]; | |
3382 [item setTarget:DWApp]; | |
3383 | |
3384 item = [menu addItemWithTitle:NSLocalizedString(@"Show All", nil) | |
3385 action:@selector(unhideAllApplications:) | |
3386 keyEquivalent:@""]; | |
3387 [item setTarget:DWApp]; | |
3388 | |
3389 [menu addItem:[NSMenuItem separatorItem]]; | |
3390 | |
3391 item = [menu addItemWithTitle:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"Quit", nil), applicationName] | |
3392 action:@selector(terminate:) | |
3393 keyEquivalent:@"q"]; | |
3394 [item setTarget:DWApp]; | |
3395 | |
3396 [mainMenu setSubmenu:menu forItem:mitem]; | |
3397 | |
3398 return mainMenu; | |
3399 } | |
3400 | |
3401 /* | |
3402 * Runs a message loop for Dynamic Windows. | |
3403 */ | |
3404 void API dw_main(void) | |
3405 { | |
3406 DWThread = dw_thread_id(); | |
3407 /* Make sure any queued redraws are handled */ | |
3408 _dw_redraw(0, FALSE); | |
3409 [DWApp run]; | |
3410 DWThread = (DWTID)-1; | |
3411 } | |
3412 | |
3413 /* | |
3414 * Causes running dw_main() to return. | |
3415 */ | |
3416 void API dw_main_quit(void) | |
3417 { | |
3418 [DWApp stop:nil]; | |
3419 _dw_wakeup_app(); | |
3420 } | |
3421 | |
3422 /* | |
3423 * Runs a message loop for Dynamic Windows, for a period of milliseconds. | |
3424 * Parameters: | |
3425 * milliseconds: Number of milliseconds to run the loop for. | |
3426 */ | |
3427 void API dw_main_sleep(int milliseconds) | |
3428 { | |
3429 DWTID curr = pthread_self(); | |
3430 | |
3431 if(DWThread == (DWTID)-1 || DWThread == curr) | |
3432 { | |
3433 DWTID orig = DWThread; | |
3434 NSDate *until = [NSDate dateWithTimeIntervalSinceNow:(milliseconds/1000.0)]; | |
3435 | |
3436 if(orig == (DWTID)-1) | |
3437 { | |
3438 DWThread = curr; | |
3439 } | |
3440 /* Process any pending events */ | |
3441 while(_dw_main_iteration(until)) | |
3442 { | |
3443 /* Just loop */ | |
3444 } | |
3445 if(orig == (DWTID)-1) | |
3446 { | |
3447 DWThread = orig; | |
3448 } | |
3449 } | |
3450 else | |
3451 { | |
3452 usleep(milliseconds * 1000); | |
3453 } | |
3454 } | |
3455 | |
3456 /* Internal version that doesn't lock the run mutex */ | |
3457 int _dw_main_iteration(NSDate *date) | |
3458 { | |
3459 NSEvent *event = [DWApp nextEventMatchingMask:DWEventMaskAny | |
3460 untilDate:date | |
3461 inMode:NSDefaultRunLoopMode | |
3462 dequeue:YES]; | |
3463 if(event) | |
3464 { | |
3465 [DWApp sendEvent:event]; | |
3466 [DWApp updateWindows]; | |
3467 return 1; | |
3468 } | |
3469 return 0; | |
3470 } | |
3471 | |
3472 /* | |
3473 * Processes a single message iteration and returns. | |
3474 */ | |
3475 void API dw_main_iteration(void) | |
3476 { | |
3477 DWTID curr = pthread_self(); | |
3478 | |
3479 if(DWThread == (DWTID)-1) | |
3480 { | |
3481 DWThread = curr; | |
3482 _dw_main_iteration([NSDate distantPast]); | |
3483 DWThread = (DWTID)-1; | |
3484 } | |
3485 else if(DWThread == curr) | |
3486 { | |
3487 _dw_main_iteration([NSDate distantPast]); | |
3488 } | |
3489 } | |
3490 | |
3491 /* | |
3492 * Cleanly terminates a DW session, should be signal handler safe. | |
3493 */ | |
3494 void API dw_shutdown(void) | |
3495 { | |
3496 pool = pthread_getspecific(_dw_pool_key); | |
3497 [pool drain]; | |
3498 } | |
3499 | |
3500 /* | |
3501 * Cleanly terminates a DW session, should be signal handler safe. | |
3502 * Parameters: | |
3503 * exitcode: Exit code reported to the operating system. | |
3504 */ | |
3505 void API dw_exit(int exitcode) | |
3506 { | |
3507 dw_shutdown(); | |
3508 exit(exitcode); | |
3509 } | |
3510 | |
3511 /* | |
3512 * Free's memory allocated by dynamic windows. | |
3513 * Parameters: | |
3514 * ptr: Pointer to dynamic windows allocated | |
3515 * memory to be free()'d. | |
3516 */ | |
3517 void API dw_free(void *ptr) | |
3518 { | |
3519 free(ptr); | |
3520 } | |
3521 | |
3522 /* | |
3523 * Returns a pointer to a static buffer which containes the | |
3524 * current user directory. Or the root directory (C:\ on | |
3525 * OS/2 and Windows). | |
3526 */ | |
3527 char *dw_user_dir(void) | |
3528 { | |
3529 static char _user_dir[PATH_MAX+1] = { 0 }; | |
3530 | |
3531 if(!_user_dir[0]) | |
3532 { | |
3533 char *home = getenv("HOME"); | |
3534 | |
3535 if(home) | |
3536 strncpy(_user_dir, home, PATH_MAX); | |
3537 else | |
3538 strcpy(_user_dir, "/"); | |
3539 } | |
3540 return _user_dir; | |
3541 } | |
3542 | |
3543 /* | |
3544 * Returns a pointer to a static buffer which containes the | |
3545 * private application data directory. | |
3546 */ | |
3547 char * API dw_app_dir(void) | |
3548 { | |
3549 return _dw_bundle_path; | |
3550 } | |
3551 | |
3552 /* | |
3553 * Sets the application ID used by this Dynamic Windows application instance. | |
3554 * Parameters: | |
3555 * appid: A string typically in the form: com.company.division.application | |
3556 * appname: The application name used on Windows or NULL. | |
3557 * Returns: | |
3558 * DW_ERROR_NONE after successfully setting the application ID. | |
3559 * DW_ERROR_UNKNOWN if unsupported on this system. | |
3560 * DW_ERROR_GENERAL if the application ID is not allowed. | |
3561 * Remarks: | |
3562 * This must be called before dw_init(). If dw_init() is called first | |
3563 * it will create a unique ID in the form: org.dbsoft.dwindows.application | |
3564 * or if the application name cannot be detected: org.dbsoft.dwindows.pid.# | |
3565 * The appname is only required on Windows. If NULL is passed the detected | |
3566 * application name will be used, but a prettier name may be desired. | |
3567 */ | |
3568 int dw_app_id_set(const char *appid, const char *appname) | |
3569 { | |
3570 strncpy(_dw_app_id, appid, _DW_APP_ID_SIZE); | |
3571 return DW_ERROR_NONE; | |
3572 } | |
3573 | |
3574 /* | |
3575 * Displays a debug message on the console... | |
3576 * Parameters: | |
3577 * format: printf style format string. | |
3578 * ...: Additional variables for use in the format. | |
3579 */ | |
3580 void API dw_debug(const char *format, ...) | |
3581 { | |
3582 va_list args; | |
3583 char outbuf[1025] = {0}; | |
3584 | |
3585 va_start(args, format); | |
3586 vsnprintf(outbuf, 1024, format, args); | |
3587 va_end(args); | |
3588 | |
3589 NSLog(@"%s", outbuf); | |
3590 } | |
3591 | |
3592 /* | |
3593 * Displays a Message Box with given text and title.. | |
3594 * Parameters: | |
3595 * title: The title of the message box. | |
3596 * flags: flags to indicate buttons and icon | |
3597 * format: printf style format string. | |
3598 * ...: Additional variables for use in the format. | |
3599 */ | |
3600 int API dw_messagebox(const char *title, int flags, const char *format, ...) | |
3601 { | |
3602 NSInteger iResponse; | |
3603 NSString *button1 = @"OK"; | |
3604 NSString *button2 = nil; | |
3605 NSString *button3 = nil; | |
3606 NSString *mtitle = [NSString stringWithUTF8String:title]; | |
3607 NSString *mtext; | |
3608 NSAlertStyle mstyle = DWAlertStyleWarning; | |
3609 NSArray *params; | |
3610 va_list args; | |
3611 | |
3612 if(flags & DW_MB_OKCANCEL) | |
3613 { | |
3614 button2 = @"Cancel"; | |
3615 } | |
3616 else if(flags & DW_MB_YESNO) | |
3617 { | |
3618 button1 = @"Yes"; | |
3619 button2 = @"No"; | |
3620 } | |
3621 else if(flags & DW_MB_YESNOCANCEL) | |
3622 { | |
3623 button1 = @"Yes"; | |
3624 button2 = @"No"; | |
3625 button3 = @"Cancel"; | |
3626 } | |
3627 | |
3628 va_start(args, format); | |
3629 mtext = [[[NSString alloc] initWithFormat:[NSString stringWithUTF8String:format] arguments:args] autorelease]; | |
3630 va_end(args); | |
3631 | |
3632 if(flags & DW_MB_ERROR) | |
3633 mstyle = DWAlertStyleCritical; | |
3634 else if(flags & DW_MB_INFORMATION) | |
3635 mstyle = DWAlertStyleInformational; | |
3636 | |
3637 params = [NSMutableArray arrayWithObjects:mtitle, mtext, [NSNumber numberWithInteger:mstyle], button1, button2, button3, nil]; | |
3638 [DWObj safeCall:@selector(messageBox:) withObject:params]; | |
3639 iResponse = [[params lastObject] integerValue]; | |
3640 | |
3641 switch(iResponse) | |
3642 { | |
3643 case NSAlertFirstButtonReturn: /* user pressed OK */ | |
3644 if(flags & DW_MB_YESNO || flags & DW_MB_YESNOCANCEL) | |
3645 { | |
3646 return DW_MB_RETURN_YES; | |
3647 } | |
3648 return DW_MB_RETURN_OK; | |
3649 case NSAlertSecondButtonReturn: /* user pressed Cancel */ | |
3650 if(flags & DW_MB_OKCANCEL) | |
3651 { | |
3652 return DW_MB_RETURN_CANCEL; | |
3653 } | |
3654 return DW_MB_RETURN_NO; | |
3655 case NSAlertThirdButtonReturn: /* user pressed the third button */ | |
3656 return DW_MB_RETURN_CANCEL; | |
3657 } | |
3658 return 0; | |
3659 } | |
3660 | |
3661 /* | |
3662 * Opens a file dialog and queries user selection. | |
3663 * Parameters: | |
3664 * title: Title bar text for dialog. | |
3665 * defpath: The default path of the open dialog. | |
3666 * ext: Default file extention. | |
3667 * flags: DW_FILE_OPEN or DW_FILE_SAVE. | |
3668 * Returns: | |
3669 * NULL on error. A malloced buffer containing | |
3670 * the file path on success. | |
3671 * | |
3672 */ | |
3673 char * API dw_file_browse(const char *title, const char *defpath, const char *ext, int flags) | |
3674 { | |
3675 char temp[PATH_MAX+1]; | |
3676 char *file = NULL, *path = NULL; | |
3677 DW_LOCAL_POOL_IN; | |
3678 | |
3679 /* Figure out path information... | |
3680 * These functions are only support in Snow Leopard and later... | |
3681 */ | |
3682 if(defpath && *defpath && (DWOSMinor > 5 || DWOSMajor > 10)) | |
3683 { | |
3684 struct stat buf; | |
3685 | |
3686 /* Get an absolute path */ | |
3687 if(!realpath(defpath, temp)) | |
3688 strcpy(temp, defpath); | |
3689 | |
3690 /* Check if the defpath exists */ | |
3691 if(stat(temp, &buf) == 0) | |
3692 { | |
3693 /* Can be a directory or file */ | |
3694 if(buf.st_mode & S_IFDIR) | |
3695 path = temp; | |
3696 else | |
3697 file = temp; | |
3698 } | |
3699 /* If it wasn't a directory... check if there is a path */ | |
3700 if(!path && strchr(temp, '/')) | |
3701 { | |
3702 unsigned long x = strlen(temp) - 1; | |
3703 | |
3704 /* Trim off the filename */ | |
3705 while(x > 0 && temp[x] != '/') | |
3706 { | |
3707 x--; | |
3708 } | |
3709 if(temp[x] == '/') | |
3710 { | |
3711 temp[x] = 0; | |
3712 /* Check to make sure the trimmed piece is a directory */ | |
3713 if(stat(temp, &buf) == 0) | |
3714 { | |
3715 if(buf.st_mode & S_IFDIR) | |
3716 { | |
3717 /* We now have it split */ | |
3718 path = temp; | |
3719 file = &temp[x+1]; | |
3720 } | |
3721 } | |
3722 } | |
3723 } | |
3724 } | |
3725 | |
3726 if(flags == DW_FILE_OPEN || flags == DW_DIRECTORY_OPEN) | |
3727 { | |
3728 /* Create the File Open Dialog class. */ | |
3729 NSOpenPanel* openDlg = [NSOpenPanel openPanel]; | |
3730 | |
3731 if(path) | |
3732 { | |
3733 SEL ssdu = NSSelectorFromString(@"setDirectoryURL"); | |
3734 | |
3735 if([openDlg respondsToSelector:ssdu]) | |
3736 { | |
3737 DWIMP isdu = (DWIMP)[openDlg methodForSelector:ssdu]; | |
3738 isdu(openDlg, ssdu, [NSURL fileURLWithPath:[NSString stringWithUTF8String:path]]); | |
3739 } | |
3740 } | |
3741 | |
3742 /* Enable the selection of files in the dialog. */ | |
3743 if(flags == DW_FILE_OPEN) | |
3744 { | |
3745 [openDlg setCanChooseFiles:YES]; | |
3746 [openDlg setCanChooseDirectories:NO]; | |
3747 } | |
3748 else | |
3749 { | |
3750 [openDlg setCanChooseFiles:NO]; | |
3751 [openDlg setCanChooseDirectories:YES]; | |
3752 } | |
3753 | |
3754 /* Handle file types */ | |
3755 if(ext && *ext) | |
3756 { | |
3757 NSArray* fileTypes = [[[NSArray alloc] initWithObjects:[NSString stringWithUTF8String:ext], nil] autorelease]; | |
3758 [openDlg setAllowedFileTypes:fileTypes]; | |
3759 } | |
3760 | |
3761 /* Disable multiple selection */ | |
3762 [openDlg setAllowsMultipleSelection:NO]; | |
3763 | |
3764 /* Display the dialog. If the OK button was pressed, | |
3765 * process the files. | |
3766 */ | |
3767 if([openDlg runModal] == DWModalResponseOK) | |
3768 { | |
3769 /* Get an array containing the full filenames of all | |
3770 * files and directories selected. | |
3771 */ | |
3772 NSArray *files = [openDlg URLs]; | |
3773 NSString *fileName = [[files objectAtIndex:0] path]; | |
3774 if(fileName) | |
3775 { | |
3776 char *ret = strdup([ fileName UTF8String ]); | |
3777 DW_LOCAL_POOL_OUT; | |
3778 return ret; | |
3779 } | |
3780 } | |
3781 } | |
3782 else | |
3783 { | |
3784 /* Create the File Save Dialog class. */ | |
3785 NSSavePanel* saveDlg = [NSSavePanel savePanel]; | |
3786 | |
3787 if(path) | |
3788 { | |
3789 SEL ssdu = NSSelectorFromString(@"setDirectoryURL"); | |
3790 | |
3791 if([saveDlg respondsToSelector:ssdu]) | |
3792 { | |
3793 DWIMP isdu = (DWIMP)[saveDlg methodForSelector:ssdu]; | |
3794 isdu(saveDlg, ssdu, [NSURL fileURLWithPath:[NSString stringWithUTF8String:path]]); | |
3795 } | |
3796 } | |
3797 if(file) | |
3798 { | |
3799 SEL ssnfsv = NSSelectorFromString(@"setNameFieldStringValue"); | |
3800 | |
3801 if([saveDlg respondsToSelector:ssnfsv]) | |
3802 { | |
3803 DWIMP isnfsv = (DWIMP)[saveDlg methodForSelector:ssnfsv]; | |
3804 isnfsv(saveDlg, ssnfsv, [NSString stringWithUTF8String:file]); | |
3805 } | |
3806 } | |
3807 | |
3808 /* Enable the creation of directories in the dialog. */ | |
3809 [saveDlg setCanCreateDirectories:YES]; | |
3810 | |
3811 /* Handle file types */ | |
3812 if(ext && *ext) | |
3813 { | |
3814 NSArray* fileTypes = [[[NSArray alloc] initWithObjects:[NSString stringWithUTF8String:ext], nil] autorelease]; | |
3815 [saveDlg setAllowedFileTypes:fileTypes]; | |
3816 } | |
3817 | |
3818 /* Display the dialog. If the OK button was pressed, | |
3819 * process the files. | |
3820 */ | |
3821 if([saveDlg runModal] == DWModalResponseOK) | |
3822 { | |
3823 /* Get an array containing the full filenames of all | |
3824 * files and directories selected. | |
3825 */ | |
3826 NSString* fileName = [[saveDlg URL] path]; | |
3827 if(fileName) | |
3828 { | |
3829 char *ret = strdup([ fileName UTF8String ]); | |
3830 DW_LOCAL_POOL_OUT; | |
3831 return ret; | |
3832 } | |
3833 } | |
3834 } | |
3835 DW_LOCAL_POOL_OUT; | |
3836 return NULL; | |
3837 } | |
3838 | |
3839 /* | |
3840 * Gets the contents of the default clipboard as text. | |
3841 * Parameters: | |
3842 * None. | |
3843 * Returns: | |
3844 * Pointer to an allocated string of text or NULL if clipboard empty or contents could not | |
3845 * be converted to text. | |
3846 */ | |
3847 char *dw_clipboard_get_text() | |
3848 { | |
3849 NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; | |
3850 NSString *str = [pasteboard stringForType:DWPasteboardTypeString]; | |
3851 if(str != nil) | |
3852 { | |
3853 return strdup([ str UTF8String ]); | |
3854 } | |
3855 return NULL; | |
3856 } | |
3857 | |
3858 /* | |
3859 * Sets the contents of the default clipboard to the supplied text. | |
3860 * Parameters: | |
3861 * Text. | |
3862 */ | |
3863 void dw_clipboard_set_text(const char *str, int len) | |
3864 { | |
3865 NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; | |
3866 SEL scc = NSSelectorFromString(@"clearContents"); | |
3867 | |
3868 if([pasteboard respondsToSelector:scc]) | |
3869 { | |
3870 DWIMP icc = (DWIMP)[pasteboard methodForSelector:scc]; | |
3871 icc(pasteboard, scc); | |
3872 } | |
3873 | |
3874 [pasteboard setString:[ NSString stringWithUTF8String:str ] forType:DWPasteboardTypeString]; | |
3875 } | |
3876 | |
3877 | |
3878 /* | |
3879 * Allocates and initializes a dialog struct. | |
3880 * Parameters: | |
3881 * data: User defined data to be passed to functions. | |
3882 */ | |
3883 DWDialog * API dw_dialog_new(void *data) | |
3884 { | |
3885 DWDialog *tmp = malloc(sizeof(DWDialog)); | |
3886 | |
3887 if(tmp) | |
3888 { | |
3889 tmp->eve = dw_event_new(); | |
3890 dw_event_reset(tmp->eve); | |
3891 tmp->data = data; | |
3892 tmp->done = FALSE; | |
3893 tmp->result = NULL; | |
3894 } | |
3895 return tmp; | |
3896 } | |
3897 | |
3898 /* | |
3899 * Accepts a dialog struct and returns the given data to the | |
3900 * initial called of dw_dialog_wait(). | |
3901 * Parameters: | |
3902 * dialog: Pointer to a dialog struct aquired by dw_dialog_new). | |
3903 * result: Data to be returned by dw_dialog_wait(). | |
3904 */ | |
3905 int API dw_dialog_dismiss(DWDialog *dialog, void *result) | |
3906 { | |
3907 dialog->result = result; | |
3908 dw_event_post(dialog->eve); | |
3909 dialog->done = TRUE; | |
3910 return 0; | |
3911 } | |
3912 | |
3913 /* | |
3914 * Accepts a dialog struct waits for dw_dialog_dismiss() to be | |
3915 * called by a signal handler with the given dialog struct. | |
3916 * Parameters: | |
3917 * dialog: Pointer to a dialog struct aquired by dw_dialog_new). | |
3918 */ | |
3919 void * API dw_dialog_wait(DWDialog *dialog) | |
3920 { | |
3921 void *tmp = NULL; | |
3922 | |
3923 if(dialog) | |
3924 { | |
3925 while(!dialog->done) | |
3926 { | |
3927 _dw_main_iteration([NSDate dateWithTimeIntervalSinceNow:0.01]); | |
3928 } | |
3929 dw_event_close(&dialog->eve); | |
3930 tmp = dialog->result; | |
3931 free(dialog); | |
3932 } | |
3933 return tmp; | |
3934 } | |
3935 | |
3936 /* | |
3937 * Create a new Box to be packed. | |
3938 * Parameters: | |
3939 * type: Either DW_VERT (vertical) or DW_HORZ (horizontal). | |
3940 * pad: Number of pixels to pad around the box. | |
3941 */ | |
3942 DW_FUNCTION_DEFINITION(dw_box_new, HWND, int type, int pad) | |
3943 DW_FUNCTION_ADD_PARAM2(type, pad) | |
3944 DW_FUNCTION_RETURN(dw_box_new, HWND) | |
3945 DW_FUNCTION_RESTORE_PARAM2(type, int, pad, int) | |
3946 { | |
3947 DW_FUNCTION_INIT; | |
3948 DWBox *view = [[DWBox alloc] init]; | |
3949 Box *newbox = [view box]; | |
3950 memset(newbox, 0, sizeof(Box)); | |
3951 newbox->pad = pad; | |
3952 newbox->type = type; | |
3953 DW_FUNCTION_RETURN_THIS(view); | |
3954 } | |
3955 | |
3956 /* | |
3957 * Create a new Group Box to be packed. | |
3958 * Parameters: | |
3959 * type: Either DW_VERT (vertical) or DW_HORZ (horizontal). | |
3960 * pad: Number of pixels to pad around the box. | |
3961 * title: Text to be displayined in the group outline. | |
3962 */ | |
3963 HWND API dw_groupbox_new(int type, int pad, const char *title) | |
3964 { | |
3965 DWGroupBox *groupbox = [[DWGroupBox alloc] init]; | |
3966 DWBox *thisbox = dw_box_new(type, pad); | |
3967 Box *box = [thisbox box]; | |
3968 | |
3969 [groupbox setTitle:[NSString stringWithUTF8String:title]]; | |
3970 box->grouphwnd = groupbox; | |
3971 [groupbox setContentView:thisbox]; | |
3972 [thisbox autorelease]; | |
3973 return groupbox; | |
3974 } | |
3975 | |
3976 /* | |
3977 * Create a new scrollable Box to be packed. | |
3978 * Parameters: | |
3979 * type: Either DW_VERT (vertical) or DW_HORZ (horizontal). | |
3980 * pad: Number of pixels to pad around the box. | |
3981 */ | |
3982 HWND API dw_scrollbox_new( int type, int pad ) | |
3983 { | |
3984 DWScrollBox *scrollbox = [[DWScrollBox alloc] init]; | |
3985 DWBox *box = dw_box_new(type, pad); | |
3986 DWBox *tmpbox = dw_box_new(DW_VERT, 0); | |
3987 dw_box_pack_start(tmpbox, box, 1, 1, TRUE, TRUE, 0); | |
3988 [scrollbox setHasVerticalScroller:YES]; | |
3989 [scrollbox setHasHorizontalScroller:YES]; | |
3990 [scrollbox setBorderType:NSNoBorder]; | |
3991 [scrollbox setDrawsBackground:NO]; | |
3992 [scrollbox setBox:box]; | |
3993 [scrollbox setDocumentView:tmpbox]; | |
3994 [tmpbox autorelease]; | |
3995 return scrollbox; | |
3996 } | |
3997 | |
3998 /* | |
3999 * Returns the position of the scrollbar in the scrollbox | |
4000 * Parameters: | |
4001 * handle: Handle to the scrollbox to be queried. | |
4002 * orient: The vertical or horizontal scrollbar. | |
4003 */ | |
4004 int API dw_scrollbox_get_pos(HWND handle, int orient) | |
4005 { | |
4006 DWScrollBox *scrollbox = handle; | |
4007 UIView *view = [scrollbox documentView]; | |
4008 NSSize contentsize = [scrollbox contentSize]; | |
4009 NSScroller *scrollbar; | |
4010 int range = 0; | |
4011 int val = 0; | |
4012 if(orient == DW_VERT) | |
4013 { | |
4014 scrollbar = [scrollbox verticalScroller]; | |
4015 range = [view bounds].size.height - contentsize.height; | |
4016 } | |
4017 else | |
4018 { | |
4019 scrollbar = [scrollbox horizontalScroller]; | |
4020 range = [view bounds].size.width - contentsize.width; | |
4021 } | |
4022 if(range > 0) | |
4023 { | |
4024 val = [scrollbar floatValue] * range; | |
4025 } | |
4026 return val; | |
4027 } | |
4028 | |
4029 /* | |
4030 * Gets the range for the scrollbar in the scrollbox. | |
4031 * Parameters: | |
4032 * handle: Handle to the scrollbox to be queried. | |
4033 * orient: The vertical or horizontal scrollbar. | |
4034 */ | |
4035 int API dw_scrollbox_get_range(HWND handle, int orient) | |
4036 { | |
4037 DWScrollBox *scrollbox = handle; | |
4038 UIView *view = [scrollbox documentView]; | |
4039 int range = 0; | |
4040 if(orient == DW_VERT) | |
4041 { | |
4042 range = [view bounds].size.height; | |
4043 } | |
4044 else | |
4045 { | |
4046 range = [view bounds].size.width; | |
4047 } | |
4048 return range; | |
4049 } | |
4050 | |
4051 /* Return the handle to the text object */ | |
4052 id _text_handle(id object) | |
4053 { | |
4054 if([object isMemberOfClass:[ DWSpinButton class]]) | |
4055 { | |
4056 DWSpinButton *spinbutton = object; | |
4057 object = [spinbutton textfield]; | |
4058 } | |
4059 if([object isMemberOfClass:[ NSBox class]]) | |
4060 { | |
4061 NSBox *box = object; | |
4062 id content = [box contentView]; | |
4063 | |
4064 if([content isMemberOfClass:[ DWText class]]) | |
4065 { | |
4066 object = content; | |
4067 } | |
4068 } | |
4069 return object; | |
4070 } | |
4071 | |
4072 /* Internal function to calculate the widget's required size.. | |
4073 * These are the general rules for widget sizes: | |
4074 * | |
4075 * Render/Unspecified: 1x1 | |
4076 * Scrolled(Container,Tree,MLE): Guessed size clamped to min and max in dw.h | |
4077 * Entryfield/Combobox/Spinbutton: 150x(maxfontheight) | |
4078 * Spinbutton: 50x(maxfontheight) | |
4079 * Text/Status: (textwidth)x(textheight) | |
4080 * Ranged: 100x14 or 14x100 for vertical. | |
4081 * Buttons/Bitmaps: Size of text or image and border. | |
4082 */ | |
4083 void _dw_control_size(id handle, int *width, int *height) | |
4084 { | |
4085 int thiswidth = 1, thisheight = 1, extrawidth = 0, extraheight = 0; | |
4086 NSString *nsstr = nil; | |
4087 id object = _text_handle(handle); | |
4088 | |
4089 /* Handle all the different button types */ | |
4090 if([ object isKindOfClass:[ UIButton class ] ]) | |
4091 { | |
4092 switch([object buttonType]) | |
4093 { | |
4094 case DWButtonTypeSwitch: | |
4095 case DWButtonTypeRadio: | |
4096 extrawidth = 24; | |
4097 extraheight = 4; | |
4098 nsstr = [object title]; | |
4099 break; | |
4100 default: | |
4101 { | |
4102 UIImage *image = [object image]; | |
4103 | |
4104 if(image) | |
4105 { | |
4106 /* Image button */ | |
4107 NSSize size = [image size]; | |
4108 thiswidth = (int)size.width; | |
4109 thisheight = (int)size.height; | |
4110 if([object isBordered]) | |
4111 { | |
4112 extrawidth = 4; | |
4113 extraheight = 4; | |
4114 } | |
4115 } | |
4116 else | |
4117 { | |
4118 /* Text button */ | |
4119 nsstr = [object title]; | |
4120 | |
4121 if([object isBordered]) | |
4122 { | |
4123 extrawidth = 30; | |
4124 extraheight = 8; | |
4125 } | |
4126 else | |
4127 { | |
4128 extrawidth = 8; | |
4129 extraheight = 4; | |
4130 } | |
4131 } | |
4132 break; | |
4133 } | |
4134 } | |
4135 } | |
4136 /* If the control is an entryfield set width to 150 */ | |
4137 else if([object isKindOfClass:[ UITextField class ]]) | |
4138 { | |
4139 UIFont *font = [object font]; | |
4140 | |
4141 if([object isEditable]) | |
4142 { | |
4143 /* Spinbuttons don't need to be as wide */ | |
4144 if([object isMemberOfClass:[ DWSpinButton class]]) | |
4145 thiswidth = 50; | |
4146 else | |
4147 thiswidth = 150; | |
4148 /* Comboboxes need some extra height for the border */ | |
4149 if([object isMemberOfClass:[ DWComboBox class]]) | |
4150 extraheight = 4; | |
4151 /* Yosemite and higher requires even more border space */ | |
4152 if(DWOSMinor > 9 || DWOSMajor > 10) | |
4153 extraheight += 4; | |
4154 } | |
4155 else | |
4156 nsstr = [object stringValue]; | |
4157 | |
4158 if(font) | |
4159 thisheight = (int)[font boundingRectForFont].size.height; | |
4160 } | |
4161 /* Handle the ranged widgets */ | |
4162 else if([ object isMemberOfClass:[DWPercent class] ] || | |
4163 [ object isMemberOfClass:[DWSlider class] ]) | |
4164 { | |
4165 thiswidth = 100; | |
4166 thisheight = 20; | |
4167 } | |
4168 /* Handle the ranged widgets */ | |
4169 else if([ object isMemberOfClass:[DWScrollbar class] ]) | |
4170 { | |
4171 if([object vertical]) | |
4172 { | |
4173 thiswidth = 14; | |
4174 thisheight = 100; | |
4175 } | |
4176 else | |
4177 { | |
4178 thiswidth = 100; | |
4179 thisheight = 14; | |
4180 } | |
4181 } | |
4182 /* Handle bitmap size */ | |
4183 else if([ object isMemberOfClass:[UIImageView class] ]) | |
4184 { | |
4185 UIImage *image = [object image]; | |
4186 | |
4187 if(image) | |
4188 { | |
4189 NSSize size = [image size]; | |
4190 thiswidth = (int)size.width; | |
4191 thisheight = (int)size.height; | |
4192 } | |
4193 } | |
4194 /* Handle calendar */ | |
4195 else if([ object isMemberOfClass:[DWCalendar class] ]) | |
4196 { | |
4197 NSCell *cell = [object cell]; | |
4198 | |
4199 if(cell) | |
4200 { | |
4201 NSSize size = [cell cellSize]; | |
4202 | |
4203 thiswidth = size.width; | |
4204 thisheight = size.height; | |
4205 } | |
4206 } | |
4207 /* MLE and Container */ | |
4208 else if([ object isMemberOfClass:[DWMLE class] ] || | |
4209 [ object isMemberOfClass:[DWContainer class] ]) | |
4210 { | |
4211 NSSize size; | |
4212 | |
4213 if([ object isMemberOfClass:[DWMLE class] ]) | |
4214 { | |
4215 UIScrollView *sv = [object scrollview]; | |
4216 NSSize frame = [sv frame].size; | |
4217 BOOL hscroll = [sv hasHorizontalScroller]; | |
4218 | |
4219 /* Make sure word wrap is off for the first part */ | |
4220 if(!hscroll) | |
4221 { | |
4222 [[object textContainer] setWidthTracksTextView:NO]; | |
4223 [[object textContainer] setContainerSize:[object maxSize]]; | |
4224 [object setHorizontallyResizable:YES]; | |
4225 [sv setHasHorizontalScroller:YES]; | |
4226 } | |
4227 /* Size the text view to fit */ | |
4228 [object sizeToFit]; | |
4229 size = [object bounds].size; | |
4230 size.width += 2.0; | |
4231 size.height += 2.0; | |
4232 /* Re-enable word wrapping if it was on */ | |
4233 if(!hscroll) | |
4234 { | |
4235 [[object textContainer] setWidthTracksTextView:YES]; | |
4236 [sv setHasHorizontalScroller:NO]; | |
4237 | |
4238 /* If the un wrapped it is beyond the bounds... */ | |
4239 if(size.width > _DW_SCROLLED_MAX_WIDTH) | |
4240 { | |
4241 NSSize max = [object maxSize]; | |
4242 | |
4243 /* Set the max size to the limit */ | |
4244 [object setMaxSize:NSMakeSize(_DW_SCROLLED_MAX_WIDTH, max.height)]; | |
4245 /* Recalculate the size */ | |
4246 [object sizeToFit]; | |
4247 size = [object bounds].size; | |
4248 size.width += 2.0; | |
4249 size.height += 2.0; | |
4250 [object setMaxSize:max]; | |
4251 } | |
4252 } | |
4253 [sv setFrameSize:frame]; | |
4254 /* Take into account the horizontal scrollbar */ | |
4255 if(hscroll && size.width > _DW_SCROLLED_MAX_WIDTH) | |
4256 size.height += 16.0; | |
4257 } | |
4258 else | |
4259 size = [object getsize]; | |
4260 | |
4261 thiswidth = size.width; | |
4262 thisheight = size.height; | |
4263 | |
4264 if(thiswidth < _DW_SCROLLED_MIN_WIDTH) | |
4265 thiswidth = _DW_SCROLLED_MIN_WIDTH; | |
4266 if(thiswidth > _DW_SCROLLED_MAX_WIDTH) | |
4267 thiswidth = _DW_SCROLLED_MAX_WIDTH; | |
4268 if(thisheight < _DW_SCROLLED_MIN_HEIGHT) | |
4269 thisheight = _DW_SCROLLED_MIN_HEIGHT; | |
4270 if(thisheight > _DW_SCROLLED_MAX_HEIGHT) | |
4271 thisheight = _DW_SCROLLED_MAX_HEIGHT; | |
4272 } | |
4273 /* Tree */ | |
4274 else if([ object isMemberOfClass:[DWTree class] ]) | |
4275 { | |
4276 thiswidth = (int)((_DW_SCROLLED_MAX_WIDTH + _DW_SCROLLED_MIN_WIDTH)/2); | |
4277 thisheight = (int)((_DW_SCROLLED_MAX_HEIGHT + _DW_SCROLLED_MIN_HEIGHT)/2); | |
4278 } | |
4279 /* Any other control type */ | |
4280 else if([ object isKindOfClass:[ UIControl class ] ]) | |
4281 nsstr = [object stringValue]; | |
4282 | |
4283 /* If we have a string... | |
4284 * calculate the size with the current font. | |
4285 */ | |
4286 if(nsstr && [nsstr length]) | |
4287 dw_font_text_extents_get(object, NULL, (char *)[nsstr UTF8String], &thiswidth, &thisheight); | |
4288 | |
4289 /* Handle static text fields */ | |
4290 if([object isKindOfClass:[ UITextField class ]] && ![object isEditable]) | |
4291 { | |
4292 id border = handle; | |
4293 | |
4294 extrawidth = 10; | |
4295 | |
4296 /* Handle status bar field */ | |
4297 if([border isMemberOfClass:[ NSBox class ] ]) | |
4298 { | |
4299 extrawidth += 2; | |
4300 extraheight = 8; | |
4301 } | |
4302 } | |
4303 | |
4304 /* Set the requested sizes */ | |
4305 if(width) | |
4306 *width = thiswidth + extrawidth; | |
4307 if(height) | |
4308 *height = thisheight + extraheight; | |
4309 } | |
4310 | |
4311 /* Internal box packing function called by the other 3 functions */ | |
4312 void _dw_box_pack(HWND box, HWND item, int index, int width, int height, int hsize, int vsize, int pad, char *funcname) | |
4313 { | |
4314 id object = box; | |
4315 DWBox *view = box; | |
4316 DWBox *this = item; | |
4317 Box *thisbox; | |
4318 int z, x = 0; | |
4319 Item *tmpitem, *thisitem; | |
4320 | |
4321 /* | |
4322 * If you try and pack an item into itself VERY bad things can happen; like at least an | |
4323 * infinite loop on GTK! Lets be safe! | |
4324 */ | |
4325 if(box == item) | |
4326 { | |
4327 dw_messagebox(funcname, DW_MB_OK|DW_MB_ERROR, "Danger! Danger! Will Robinson; box and item are the same!"); | |
4328 return; | |
4329 } | |
4330 | |
4331 /* Query the objects */ | |
4332 if([ object isKindOfClass:[ UIWindow class ] ]) | |
4333 { | |
4334 UIWindow *window = box; | |
4335 view = [window contentView]; | |
4336 } | |
4337 else if([ object isMemberOfClass:[ DWScrollBox class ] ]) | |
4338 { | |
4339 DWScrollBox *scrollbox = box; | |
4340 view = [scrollbox box]; | |
4341 } | |
4342 | |
4343 thisbox = [view box]; | |
4344 thisitem = thisbox->items; | |
4345 object = item; | |
4346 | |
4347 /* Query the objects */ | |
4348 if([ object isMemberOfClass:[ DWContainer class ] ] || | |
4349 [ object isMemberOfClass:[ DWTree class ] ] || | |
4350 [ object isMemberOfClass:[ DWMLE class ] ]) | |
4351 { | |
4352 this = item = [object scrollview]; | |
4353 } | |
4354 | |
4355 /* Do some sanity bounds checking */ | |
4356 if(!thisitem) | |
4357 thisbox->count = 0; | |
4358 if(index < 0) | |
4359 index = 0; | |
4360 if(index > thisbox->count) | |
4361 index = thisbox->count; | |
4362 | |
4363 /* Duplicate the existing data */ | |
4364 tmpitem = calloc(sizeof(Item), (thisbox->count+1)); | |
4365 | |
4366 for(z=0;z<thisbox->count;z++) | |
4367 { | |
4368 if(z == index) | |
4369 x++; | |
4370 tmpitem[x] = thisitem[z]; | |
4371 x++; | |
4372 } | |
4373 | |
4374 /* Sanity checks */ | |
4375 if(vsize && !height) | |
4376 height = 1; | |
4377 if(hsize && !width) | |
4378 width = 1; | |
4379 | |
4380 /* Fill in the item data appropriately */ | |
4381 if([object isKindOfClass:[DWBox class]] || [object isMemberOfClass:[DWGroupBox class]]) | |
4382 tmpitem[index].type = TYPEBOX; | |
4383 else | |
4384 { | |
4385 if ( width == 0 && hsize == FALSE ) | |
4386 dw_messagebox(funcname, DW_MB_OK|DW_MB_ERROR, "Width and expand Horizonal both unset for box: %x item: %x",box,item); | |
4387 if ( height == 0 && vsize == FALSE ) | |
4388 dw_messagebox(funcname, DW_MB_OK|DW_MB_ERROR, "Height and expand Vertical both unset for box: %x item: %x",box,item); | |
4389 | |
4390 tmpitem[index].type = TYPEITEM; | |
4391 } | |
4392 | |
4393 tmpitem[index].hwnd = item; | |
4394 tmpitem[index].origwidth = tmpitem[index].width = width; | |
4395 tmpitem[index].origheight = tmpitem[index].height = height; | |
4396 tmpitem[index].pad = pad; | |
4397 tmpitem[index].hsize = hsize ? SIZEEXPAND : SIZESTATIC; | |
4398 tmpitem[index].vsize = vsize ? SIZEEXPAND : SIZESTATIC; | |
4399 | |
4400 /* If either of the parameters are -1 ... calculate the size */ | |
4401 if(width == -1 || height == -1) | |
4402 _dw_control_size(object, width == -1 ? &tmpitem[index].width : NULL, height == -1 ? &tmpitem[index].height : NULL); | |
4403 | |
4404 thisbox->items = tmpitem; | |
4405 | |
4406 /* Update the item count */ | |
4407 thisbox->count++; | |
4408 | |
4409 /* Add the item to the box */ | |
4410 [view addSubview:this]; | |
4411 /* Enable autorelease on the item... | |
4412 * so it will get destroyed when the parent is. | |
4413 */ | |
4414 [this autorelease]; | |
4415 /* If we are packing a button... */ | |
4416 if([this isMemberOfClass:[DWButton class]]) | |
4417 { | |
4418 DWButton *button = (DWButton *)this; | |
4419 | |
4420 /* Save the parent box so radio | |
4421 * buttons can use it later. | |
4422 */ | |
4423 [button setParent:view]; | |
4424 } | |
4425 /* Queue a redraw on the top-level window */ | |
4426 _dw_redraw([view window], TRUE); | |
4427 | |
4428 /* Free the old data */ | |
4429 if(thisitem) | |
4430 free(thisitem); | |
4431 } | |
4432 | |
4433 /* | |
4434 * Remove windows (widgets) from the box they are packed into. | |
4435 * Parameters: | |
4436 * handle: Window handle of the packed item to be removed. | |
4437 * Returns: | |
4438 * DW_ERROR_NONE on success and DW_ERROR_GENERAL on failure. | |
4439 */ | |
4440 DW_FUNCTION_DEFINITION(dw_box_unpack, int, HWND handle) | |
4441 DW_FUNCTION_ADD_PARAM1(handle) | |
4442 DW_FUNCTION_RETURN(dw_box_unpack, int) | |
4443 DW_FUNCTION_RESTORE_PARAM1(handle, HWND) | |
4444 { | |
4445 DW_FUNCTION_INIT; | |
4446 DW_LOCAL_POOL_IN; | |
4447 id object = handle; | |
4448 int retval = DW_ERROR_NONE; | |
4449 | |
4450 if([object isKindOfClass:[UIView class]] || [object isKindOfClass:[UIControl class]]) | |
4451 { | |
4452 DWBox *parent = (DWBox *)[object superview]; | |
4453 | |
4454 /* Some controls are embedded in scrollviews... | |
4455 * so get the parent of the scrollview in that case. | |
4456 */ | |
4457 if(([object isKindOfClass:[NSTableView class]] || [object isMemberOfClass:[DWMLE class]]) | |
4458 && [parent isMemberOfClass:[NSClipView class]]) | |
4459 { | |
4460 object = [parent superview]; | |
4461 parent = (DWBox *)[object superview]; | |
4462 } | |
4463 | |
4464 if([parent isKindOfClass:[DWBox class]] || [parent isKindOfClass:[DWGroupBox class]]) | |
4465 { | |
4466 id window = [object window]; | |
4467 Box *thisbox = [parent box]; | |
4468 int z, index = -1; | |
4469 Item *tmpitem = NULL, *thisitem = thisbox->items; | |
4470 | |
4471 if(!thisitem) | |
4472 thisbox->count = 0; | |
4473 | |
4474 for(z=0;z<thisbox->count;z++) | |
4475 { | |
4476 if(thisitem[z].hwnd == object) | |
4477 index = z; | |
4478 } | |
4479 | |
4480 if(index == -1) | |
4481 retval = DW_ERROR_GENERAL; | |
4482 else | |
4483 { | |
4484 [object retain]; | |
4485 [object removeFromSuperview]; | |
4486 | |
4487 if(thisbox->count > 1) | |
4488 { | |
4489 tmpitem = calloc(sizeof(Item), (thisbox->count-1)); | |
4490 | |
4491 /* Copy all but the current entry to the new list */ | |
4492 for(z=0;z<index;z++) | |
4493 { | |
4494 tmpitem[z] = thisitem[z]; | |
4495 } | |
4496 for(z=index+1;z<thisbox->count;z++) | |
4497 { | |
4498 tmpitem[z-1] = thisitem[z]; | |
4499 } | |
4500 } | |
4501 | |
4502 thisbox->items = tmpitem; | |
4503 if(thisitem) | |
4504 free(thisitem); | |
4505 if(tmpitem) | |
4506 thisbox->count--; | |
4507 else | |
4508 thisbox->count = 0; | |
4509 /* Queue a redraw on the top-level window */ | |
4510 _dw_redraw(window, TRUE); | |
4511 } | |
4512 } | |
4513 } | |
4514 DW_LOCAL_POOL_OUT; | |
4515 DW_FUNCTION_RETURN_THIS(retval); | |
4516 } | |
4517 | |
4518 /* | |
4519 * Remove windows (widgets) from a box at an arbitrary location. | |
4520 * Parameters: | |
4521 * box: Window handle of the box to be removed from. | |
4522 * index: 0 based index of packed items. | |
4523 * Returns: | |
4524 * Handle to the removed item on success, 0 on failure or padding. | |
4525 */ | |
4526 DW_FUNCTION_DEFINITION(dw_box_unpack_at_index, HWND, HWND box, int index) | |
4527 DW_FUNCTION_ADD_PARAM2(box, index) | |
4528 DW_FUNCTION_RETURN(dw_box_unpack_at_index, HWND) | |
4529 DW_FUNCTION_RESTORE_PARAM2(box, HWND, index, int) | |
4530 { | |
4531 DW_FUNCTION_INIT; | |
4532 DW_LOCAL_POOL_IN; | |
4533 DWBox *parent = (DWBox *)box; | |
4534 id object = nil; | |
4535 | |
4536 if([parent isKindOfClass:[DWBox class]] || [parent isKindOfClass:[DWGroupBox class]]) | |
4537 { | |
4538 id window = [parent window]; | |
4539 Box *thisbox = [parent box]; | |
4540 | |
4541 if(thisbox && index > -1 && index < thisbox->count) | |
4542 { | |
4543 int z; | |
4544 Item *tmpitem = NULL, *thisitem = thisbox->items; | |
4545 | |
4546 object = thisitem[index].hwnd; | |
4547 | |
4548 if(object) | |
4549 { | |
4550 [object retain]; | |
4551 [object removeFromSuperview]; | |
4552 } | |
4553 | |
4554 if(thisbox->count > 1) | |
4555 { | |
4556 tmpitem = calloc(sizeof(Item), (thisbox->count-1)); | |
4557 | |
4558 /* Copy all but the current entry to the new list */ | |
4559 for(z=0;thisitem && z<index;z++) | |
4560 { | |
4561 tmpitem[z] = thisitem[z]; | |
4562 } | |
4563 for(z=index+1;z<thisbox->count;z++) | |
4564 { | |
4565 tmpitem[z-1] = thisitem[z]; | |
4566 } | |
4567 } | |
4568 | |
4569 thisbox->items = tmpitem; | |
4570 if(thisitem) | |
4571 free(thisitem); | |
4572 if(tmpitem) | |
4573 thisbox->count--; | |
4574 else | |
4575 thisbox->count = 0; | |
4576 | |
4577 /* Queue a redraw on the top-level window */ | |
4578 _dw_redraw(window, TRUE); | |
4579 } | |
4580 } | |
4581 DW_LOCAL_POOL_OUT; | |
4582 DW_FUNCTION_RETURN_THIS(object); | |
4583 } | |
4584 | |
4585 /* | |
4586 * Pack windows (widgets) into a box at an arbitrary location. | |
4587 * Parameters: | |
4588 * box: Window handle of the box to be packed into. | |
4589 * item: Window handle of the item to pack. | |
4590 * index: 0 based index of packed items. | |
4591 * width: Width in pixels of the item or -1 to be self determined. | |
4592 * height: Height in pixels of the item or -1 to be self determined. | |
4593 * hsize: TRUE if the window (widget) should expand horizontally to fill space given. | |
4594 * vsize: TRUE if the window (widget) should expand vertically to fill space given. | |
4595 * pad: Number of pixels of padding around the item. | |
4596 */ | |
4597 void API dw_box_pack_at_index(HWND box, HWND item, int index, int width, int height, int hsize, int vsize, int pad) | |
4598 { | |
4599 _dw_box_pack(box, item, index, width, height, hsize, vsize, pad, "dw_box_pack_at_index()"); | |
4600 } | |
4601 | |
4602 /* | |
4603 * Pack windows (widgets) into a box from the start (or top). | |
4604 * Parameters: | |
4605 * box: Window handle of the box to be packed into. | |
4606 * item: Window handle of the item to pack. | |
4607 * width: Width in pixels of the item or -1 to be self determined. | |
4608 * height: Height in pixels of the item or -1 to be self determined. | |
4609 * hsize: TRUE if the window (widget) should expand horizontally to fill space given. | |
4610 * vsize: TRUE if the window (widget) should expand vertically to fill space given. | |
4611 * pad: Number of pixels of padding around the item. | |
4612 */ | |
4613 void API dw_box_pack_start(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad) | |
4614 { | |
4615 /* 65536 is the table limit on GTK... | |
4616 * seems like a high enough value we will never hit it here either. | |
4617 */ | |
4618 _dw_box_pack(box, item, 65536, width, height, hsize, vsize, pad, "dw_box_pack_start()"); | |
4619 } | |
4620 | |
4621 /* | |
4622 * Pack windows (widgets) into a box from the end (or bottom). | |
4623 * Parameters: | |
4624 * box: Window handle of the box to be packed into. | |
4625 * item: Window handle of the item to pack. | |
4626 * width: Width in pixels of the item or -1 to be self determined. | |
4627 * height: Height in pixels of the item or -1 to be self determined. | |
4628 * hsize: TRUE if the window (widget) should expand horizontally to fill space given. | |
4629 * vsize: TRUE if the window (widget) should expand vertically to fill space given. | |
4630 * pad: Number of pixels of padding around the item. | |
4631 */ | |
4632 void API dw_box_pack_end(HWND box, HWND item, int width, int height, int hsize, int vsize, int pad) | |
4633 { | |
4634 _dw_box_pack(box, item, 0, width, height, hsize, vsize, pad, "dw_box_pack_end()"); | |
4635 } | |
4636 | |
4637 /* Internal function to create a basic button, used by all button types */ | |
4638 HWND _dw_button_new(const char *text, ULONG cid) | |
4639 { | |
4640 DWButton *button = [[DWButton alloc] init]; | |
4641 if(text) | |
4642 { | |
4643 [button setTitle:[ NSString stringWithUTF8String:text ]]; | |
4644 } | |
4645 [button setTarget:button]; | |
4646 [button setAction:@selector(buttonClicked:)]; | |
4647 [button setTag:cid]; | |
4648 [button setButtonType:DWButtonTypeMomentaryPushIn]; | |
4649 [button setBezelStyle:DWBezelStyleRegularSquare]; | |
4650 /* TODO: Reenable scaling in the future if it is possible on other platforms. | |
4651 [[button cell] setImageScaling:UIImageScaleProportionallyDown]; */ | |
4652 if(DWDefaultFont) | |
4653 { | |
4654 [[button cell] setFont:DWDefaultFont]; | |
4655 } | |
4656 return button; | |
4657 } | |
4658 | |
4659 /* | |
4660 * Create a new button window (widget) to be packed. | |
4661 * Parameters: | |
4662 * text: The text to be display by the static text widget. | |
4663 * id: An ID to be used with dw_window_from_id() or 0L. | |
4664 */ | |
4665 HWND API dw_button_new(const char *text, ULONG cid) | |
4666 { | |
4667 DWButton *button = _dw_button_new(text, cid); | |
4668 [button setButtonType:DWButtonTypeMomentaryPushIn]; | |
4669 [button setBezelStyle:DWBezelStyleRounded]; | |
4670 [button setImagePosition:NSNoImage]; | |
4671 [button setAlignment:DWTextAlignmentCenter]; | |
4672 [[button cell] setControlTint:NSBlueControlTint]; | |
4673 return button; | |
4674 } | |
4675 | |
4676 /* | |
4677 * Create a new Entryfield window (widget) to be packed. | |
4678 * Parameters: | |
4679 * text: The default text to be in the entryfield widget. | |
4680 * id: An ID to be used with dw_window_from_id() or 0L. | |
4681 */ | |
4682 HWND API dw_entryfield_new(const char *text, ULONG cid) | |
4683 { | |
4684 DWEntryField *entry = [[DWEntryField alloc] init]; | |
4685 [entry setStringValue:[ NSString stringWithUTF8String:text ]]; | |
4686 [entry setTag:cid]; | |
4687 [[entry cell] setScrollable:YES]; | |
4688 [[entry cell] setWraps:NO]; | |
4689 return entry; | |
4690 } | |
4691 | |
4692 /* | |
4693 * Create a new Entryfield (password) window (widget) to be packed. | |
4694 * Parameters: | |
4695 * text: The default text to be in the entryfield widget. | |
4696 * id: An ID to be used with dw_window_from_id() or 0L. | |
4697 */ | |
4698 HWND API dw_entryfield_password_new(const char *text, ULONG cid) | |
4699 { | |
4700 DWEntryFieldPassword *entry = [[DWEntryFieldPassword alloc] init]; | |
4701 [entry setStringValue:[ NSString stringWithUTF8String:text ]]; | |
4702 [entry setTag:cid]; | |
4703 [[entry cell] setScrollable:YES]; | |
4704 [[entry cell] setWraps:NO]; | |
4705 return entry; | |
4706 } | |
4707 | |
4708 /* | |
4709 * Sets the entryfield character limit. | |
4710 * Parameters: | |
4711 * handle: Handle to the spinbutton to be set. | |
4712 * limit: Number of characters the entryfield will take. | |
4713 */ | |
4714 void API dw_entryfield_set_limit(HWND handle, ULONG limit) | |
4715 { | |
4716 DWEntryField *entry = handle; | |
4717 DWEntryFieldFormatter *formatter = [[[DWEntryFieldFormatter alloc] init] autorelease]; | |
4718 | |
4719 [formatter setMaximumLength:(int)limit]; | |
4720 [[entry cell] setFormatter:formatter]; | |
4721 } | |
4722 | |
4723 /* | |
4724 * Create a new bitmap button window (widget) to be packed. | |
4725 * Parameters: | |
4726 * text: Bubble help text to be displayed. | |
4727 * id: An ID of a bitmap in the resource file. | |
4728 */ | |
4729 HWND API dw_bitmapbutton_new(const char *text, ULONG resid) | |
4730 { | |
4731 NSBundle *bundle = [NSBundle mainBundle]; | |
4732 NSString *respath = [bundle resourcePath]; | |
4733 NSString *filepath = [respath stringByAppendingFormat:@"/%lu.png", resid]; | |
4734 UIImage *image = [[UIImage alloc] initWithContentsOfFile:filepath]; | |
4735 DWButton *button = _dw_button_new("", resid); | |
4736 if(image) | |
4737 { | |
4738 [button setImage:image]; | |
4739 } | |
4740 if(text) | |
4741 [button setToolTip:[NSString stringWithUTF8String:text]]; | |
4742 [image release]; | |
4743 return button; | |
4744 } | |
4745 | |
4746 /* | |
4747 * Create a new bitmap button window (widget) to be packed from a file. | |
4748 * Parameters: | |
4749 * text: Bubble help text to be displayed. | |
4750 * id: An ID to be used with dw_window_from_id() or 0L. | |
4751 * filename: Name of the file, omit extention to have | |
4752 * DW pick the appropriate file extension. | |
4753 * (BMP on OS/2 or Windows, XPM on Unix) | |
4754 */ | |
4755 HWND API dw_bitmapbutton_new_from_file(const char *text, unsigned long cid, const char *filename) | |
4756 { | |
4757 char *ext = _dw_get_image_extension(filename); | |
4758 | |
4759 NSString *nstr = [ NSString stringWithUTF8String:filename ]; | |
4760 UIImage *image = [[UIImage alloc] initWithContentsOfFile:nstr]; | |
4761 | |
4762 if(!image && ext) | |
4763 { | |
4764 nstr = [nstr stringByAppendingString: [NSString stringWithUTF8String:ext]]; | |
4765 image = [[UIImage alloc] initWithContentsOfFile:nstr]; | |
4766 } | |
4767 DWButton *button = _dw_button_new("", cid); | |
4768 if(image) | |
4769 { | |
4770 [button setImage:image]; | |
4771 } | |
4772 if(text) | |
4773 [button setToolTip:[NSString stringWithUTF8String:text]]; | |
4774 [image release]; | |
4775 return button; | |
4776 } | |
4777 | |
4778 /* | |
4779 * Create a new bitmap button window (widget) to be packed from data. | |
4780 * Parameters: | |
4781 * text: Bubble help text to be displayed. | |
4782 * id: An ID to be used with dw_window_from_id() or 0L. | |
4783 * data: The contents of the image | |
4784 * (BMP or ICO on OS/2 or Windows, XPM on Unix) | |
4785 * len: length of str | |
4786 */ | |
4787 HWND API dw_bitmapbutton_new_from_data(const char *text, unsigned long cid, const char *data, int len) | |
4788 { | |
4789 NSData *thisdata = [NSData dataWithBytes:data length:len]; | |
4790 UIImage *image = [[UIImage alloc] initWithData:thisdata]; | |
4791 DWButton *button = _dw_button_new("", cid); | |
4792 if(image) | |
4793 { | |
4794 [button setImage:image]; | |
4795 } | |
4796 if(text) | |
4797 [button setToolTip:[NSString stringWithUTF8String:text]]; | |
4798 [image release]; | |
4799 return button; | |
4800 } | |
4801 | |
4802 /* | |
4803 * Create a new spinbutton window (widget) to be packed. | |
4804 * Parameters: | |
4805 * text: The text to be display by the static text widget. | |
4806 * id: An ID to be used with dw_window_from_id() or 0L. | |
4807 */ | |
4808 HWND API dw_spinbutton_new(const char *text, ULONG cid) | |
4809 { | |
4810 DWSpinButton *spinbutton = [[DWSpinButton alloc] init]; | |
4811 UIStepper *stepper = [spinbutton stepper]; | |
4812 UITextField *textfield = [spinbutton textfield]; | |
4813 [stepper setIncrement:1]; | |
4814 [stepper setTag:cid]; | |
4815 [stepper setMinValue:-65536]; | |
4816 [stepper setMaxValue:65536]; | |
4817 [stepper setIntValue:atoi(text)]; | |
4818 [textfield takeIntValueFrom:stepper]; | |
4819 return spinbutton; | |
4820 } | |
4821 | |
4822 /* | |
4823 * Sets the spinbutton value. | |
4824 * Parameters: | |
4825 * handle: Handle to the spinbutton to be set. | |
4826 * position: Current value of the spinbutton. | |
4827 */ | |
4828 void API dw_spinbutton_set_pos(HWND handle, long position) | |
4829 { | |
4830 DWSpinButton *spinbutton = handle; | |
4831 UIStepper *stepper = [spinbutton stepper]; | |
4832 UITextField *textfield = [spinbutton textfield]; | |
4833 [stepper setIntValue:(int)position]; | |
4834 [textfield takeIntValueFrom:stepper]; | |
4835 } | |
4836 | |
4837 /* | |
4838 * Sets the spinbutton limits. | |
4839 * Parameters: | |
4840 * handle: Handle to the spinbutton to be set. | |
4841 * upper: Upper limit. | |
4842 * lower: Lower limit. | |
4843 */ | |
4844 void API dw_spinbutton_set_limits(HWND handle, long upper, long lower) | |
4845 { | |
4846 DWSpinButton *spinbutton = handle; | |
4847 UIStepper *stepper = [spinbutton stepper]; | |
4848 [stepper setMinValue:(double)lower]; | |
4849 [stepper setMaxValue:(double)upper]; | |
4850 } | |
4851 | |
4852 /* | |
4853 * Returns the current value of the spinbutton. | |
4854 * Parameters: | |
4855 * handle: Handle to the spinbutton to be queried. | |
4856 */ | |
4857 long API dw_spinbutton_get_pos(HWND handle) | |
4858 { | |
4859 DWSpinButton *spinbutton = handle; | |
4860 UIStepper *stepper = [spinbutton stepper]; | |
4861 return (long)[stepper integerValue]; | |
4862 } | |
4863 | |
4864 /* | |
4865 * Create a new radiobutton window (widget) to be packed. | |
4866 * Parameters: | |
4867 * text: The text to be display by the static text widget. | |
4868 * id: An ID to be used with dw_window_from_id() or 0L. | |
4869 */ | |
4870 HWND API dw_radiobutton_new(const char *text, ULONG cid) | |
4871 { | |
4872 DWButton *button = _dw_button_new(text, cid); | |
4873 [button setButtonType:DWButtonTypeRadio]; | |
4874 return button; | |
4875 } | |
4876 | |
4877 /* | |
4878 * Create a new slider window (widget) to be packed. | |
4879 * Parameters: | |
4880 * vertical: TRUE or FALSE if slider is vertical. | |
4881 * increments: Number of increments available. | |
4882 * id: An ID to be used with dw_window_from_id() or 0L. | |
4883 */ | |
4884 HWND API dw_slider_new(int vertical, int increments, ULONG cid) | |
4885 { | |
4886 DWSlider *slider = [[DWSlider alloc] init]; | |
4887 [slider setMaxValue:(double)increments]; | |
4888 [slider setMinValue:0]; | |
4889 [slider setContinuous:YES]; | |
4890 [slider setTarget:slider]; | |
4891 [slider setAction:@selector(sliderChanged:)]; | |
4892 [slider setTag:cid]; | |
4893 return slider; | |
4894 } | |
4895 | |
4896 /* | |
4897 * Returns the position of the slider. | |
4898 * Parameters: | |
4899 * handle: Handle to the slider to be queried. | |
4900 */ | |
4901 unsigned int API dw_slider_get_pos(HWND handle) | |
4902 { | |
4903 DWSlider *slider = handle; | |
4904 double val = [slider doubleValue]; | |
4905 return (int)val; | |
4906 } | |
4907 | |
4908 /* | |
4909 * Sets the slider position. | |
4910 * Parameters: | |
4911 * handle: Handle to the slider to be set. | |
4912 * position: Position of the slider withing the range. | |
4913 */ | |
4914 void API dw_slider_set_pos(HWND handle, unsigned int position) | |
4915 { | |
4916 DWSlider *slider = handle; | |
4917 [slider setDoubleValue:(double)position]; | |
4918 } | |
4919 | |
4920 /* | |
4921 * Create a new scrollbar window (widget) to be packed. | |
4922 * Parameters: | |
4923 * vertical: TRUE or FALSE if scrollbar is vertical. | |
4924 * increments: Number of increments available. | |
4925 * id: An ID to be used with dw_window_from_id() or 0L. | |
4926 */ | |
4927 HWND API dw_scrollbar_new(int vertical, ULONG cid) | |
4928 { | |
4929 DWScrollbar *scrollbar; | |
4930 if(vertical) | |
4931 { | |
4932 scrollbar = [[DWScrollbar alloc] init]; | |
4933 [scrollbar setVertical:YES]; | |
4934 } | |
4935 else | |
4936 { | |
4937 scrollbar = [[DWScrollbar alloc] initWithFrame:NSMakeRect(0,0,100,5)]; | |
4938 } | |
4939 [scrollbar setRange:0.0 andVisible:0.0]; | |
4940 [scrollbar setKnobProportion:1.0]; | |
4941 [scrollbar setTarget:scrollbar]; | |
4942 [scrollbar setAction:@selector(scrollerChanged:)]; | |
4943 [scrollbar setTag:cid]; | |
4944 [scrollbar setEnabled:YES]; | |
4945 return scrollbar; | |
4946 } | |
4947 | |
4948 /* | |
4949 * Returns the position of the scrollbar. | |
4950 * Parameters: | |
4951 * handle: Handle to the scrollbar to be queried. | |
4952 */ | |
4953 unsigned int API dw_scrollbar_get_pos(HWND handle) | |
4954 { | |
4955 DWScrollbar *scrollbar = handle; | |
4956 float range = [scrollbar range]; | |
4957 float fresult = [scrollbar doubleValue] * range; | |
4958 return (int)fresult; | |
4959 } | |
4960 | |
4961 /* | |
4962 * Sets the scrollbar position. | |
4963 * Parameters: | |
4964 * handle: Handle to the scrollbar to be set. | |
4965 * position: Position of the scrollbar withing the range. | |
4966 */ | |
4967 void API dw_scrollbar_set_pos(HWND handle, unsigned int position) | |
4968 { | |
4969 DWScrollbar *scrollbar = handle; | |
4970 double range = [scrollbar range]; | |
4971 double visible = [scrollbar visible]; | |
4972 double newpos = (double)position/(range-visible); | |
4973 [scrollbar setDoubleValue:newpos]; | |
4974 } | |
4975 | |
4976 /* | |
4977 * Sets the scrollbar range. | |
4978 * Parameters: | |
4979 * handle: Handle to the scrollbar to be set. | |
4980 * range: Maximum range value. | |
4981 * visible: Visible area relative to the range. | |
4982 */ | |
4983 void API dw_scrollbar_set_range(HWND handle, unsigned int range, unsigned int visible) | |
4984 { | |
4985 DWScrollbar *scrollbar = handle; | |
4986 double knob = (double)visible/(double)range; | |
4987 [scrollbar setRange:(double)range andVisible:(double)visible]; | |
4988 [scrollbar setKnobProportion:knob]; | |
4989 } | |
4990 | |
4991 /* | |
4992 * Create a new percent bar window (widget) to be packed. | |
4993 * Parameters: | |
4994 * id: An ID to be used with dw_window_from_id() or 0L. | |
4995 */ | |
4996 HWND API dw_percent_new(ULONG cid) | |
4997 { | |
4998 DWPercent *percent = [[DWPercent alloc] init]; | |
4999 [percent setStyle:DWProgressIndicatorStyleBar]; | |
5000 [percent setBezeled:YES]; | |
5001 [percent setMaxValue:100]; | |
5002 [percent setMinValue:0]; | |
5003 [percent incrementBy:1]; | |
5004 [percent setIndeterminate:NO]; | |
5005 [percent setDoubleValue:0]; | |
5006 /*[percent setTag:cid]; Why doesn't this work? */ | |
5007 return percent; | |
5008 } | |
5009 | |
5010 /* | |
5011 * Sets the percent bar position. | |
5012 * Parameters: | |
5013 * handle: Handle to the percent bar to be set. | |
5014 * position: Position of the percent bar withing the range. | |
5015 */ | |
5016 DW_FUNCTION_DEFINITION(dw_percent_set_pos, void, HWND handle, unsigned int position) | |
5017 DW_FUNCTION_ADD_PARAM2(handle, position) | |
5018 DW_FUNCTION_NO_RETURN(dw_percent_set_pos) | |
5019 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, position, unsigned int) | |
5020 { | |
5021 DW_FUNCTION_INIT; | |
5022 DWPercent *percent = handle; | |
5023 | |
5024 /* Handle indeterminate */ | |
5025 if(position == DW_PERCENT_INDETERMINATE) | |
5026 { | |
5027 [percent setIndeterminate:YES]; | |
5028 [percent startAnimation:percent]; | |
5029 } | |
5030 else | |
5031 { | |
5032 /* Handle normal */ | |
5033 if([percent isIndeterminate]) | |
5034 { | |
5035 [percent stopAnimation:percent]; | |
5036 [percent setIndeterminate:NO]; | |
5037 } | |
5038 [percent setDoubleValue:(double)position]; | |
5039 } | |
5040 DW_FUNCTION_RETURN_NOTHING; | |
5041 } | |
5042 | |
5043 /* | |
5044 * Create a new checkbox window (widget) to be packed. | |
5045 * Parameters: | |
5046 * text: The text to be display by the static text widget. | |
5047 * id: An ID to be used with dw_window_from_id() or 0L. | |
5048 */ | |
5049 HWND API dw_checkbox_new(const char *text, ULONG cid) | |
5050 { | |
5051 DWButton *button = _dw_button_new(text, cid); | |
5052 [button setButtonType:DWButtonTypeSwitch]; | |
5053 [button setBezelStyle:DWBezelStyleRegularSquare]; | |
5054 return button; | |
5055 } | |
5056 | |
5057 /* | |
5058 * Returns the state of the checkbox. | |
5059 * Parameters: | |
5060 * handle: Handle to the checkbox to be queried. | |
5061 */ | |
5062 int API dw_checkbox_get(HWND handle) | |
5063 { | |
5064 DWButton *button = handle; | |
5065 if([button state]) | |
5066 { | |
5067 return TRUE; | |
5068 } | |
5069 return FALSE; | |
5070 } | |
5071 | |
5072 /* | |
5073 * Sets the state of the checkbox. | |
5074 * Parameters: | |
5075 * handle: Handle to the checkbox to be queried. | |
5076 * value: TRUE for checked, FALSE for unchecked. | |
5077 */ | |
5078 void API dw_checkbox_set(HWND handle, int value) | |
5079 { | |
5080 DWButton *button = handle; | |
5081 if(value) | |
5082 { | |
5083 [button setState:DWControlStateValueOn]; | |
5084 } | |
5085 else | |
5086 { | |
5087 [button setState:DWControlStateValueOff]; | |
5088 } | |
5089 | |
5090 } | |
5091 | |
5092 /* Internal common function to create containers and listboxes */ | |
5093 HWND _dw_cont_new(ULONG cid, int multi) | |
5094 { | |
5095 DWFocusRingScrollView *scrollview = [[DWFocusRingScrollView alloc] init]; | |
5096 DWContainer *cont = [[DWContainer alloc] init]; | |
5097 | |
5098 [cont setScrollview:scrollview]; | |
5099 [scrollview setBorderType:NSBezelBorder]; | |
5100 [scrollview setHasVerticalScroller:YES]; | |
5101 [scrollview setAutohidesScrollers:YES]; | |
5102 [cont setAllowsMultipleSelection:(multi ? YES : NO)]; | |
5103 [cont setAllowsColumnReordering:NO]; | |
5104 [cont setDataSource:cont]; | |
5105 [cont setDelegate:cont]; | |
5106 [scrollview setDocumentView:cont]; | |
5107 [cont setTag:cid]; | |
5108 [cont autorelease]; | |
5109 [cont setRowBgOdd:DW_RGB_TRANSPARENT andEven:DW_RGB_TRANSPARENT]; | |
5110 return cont; | |
5111 } | |
5112 | |
5113 /* | |
5114 * Create a new listbox window (widget) to be packed. | |
5115 * Parameters: | |
5116 * id: An ID to be used with dw_window_from_id() or 0L. | |
5117 * multi: Multiple select TRUE or FALSE. | |
5118 */ | |
5119 DW_FUNCTION_DEFINITION(dw_listbox_new, HWND, ULONG cid, int multi) | |
5120 DW_FUNCTION_ADD_PARAM2(cid, multi) | |
5121 DW_FUNCTION_RETURN(dw_listbox_new, HWND) | |
5122 DW_FUNCTION_RESTORE_PARAM2(cid, ULONG, multi, int) | |
5123 { | |
5124 DW_FUNCTION_INIT; | |
5125 DWContainer *cont = _dw_cont_new(cid, multi); | |
5126 [cont setHeaderView:nil]; | |
5127 int type = DW_CFA_STRING; | |
5128 [cont setup]; | |
5129 NSTableColumn *column = [[[NSTableColumn alloc] initWithIdentifier:@"_DWListboxColumn"] autorelease]; | |
5130 [column setEditable:NO]; | |
5131 [cont addTableColumn:column]; | |
5132 [cont addColumn:column andType:type]; | |
5133 DW_FUNCTION_RETURN_THIS(cont); | |
5134 } | |
5135 | |
5136 /* | |
5137 * Appends the specified text to the listbox's (or combobox) entry list. | |
5138 * Parameters: | |
5139 * handle: Handle to the listbox to be appended to. | |
5140 * text: Text to append into listbox. | |
5141 */ | |
5142 DW_FUNCTION_DEFINITION(dw_listbox_append, void, HWND handle, const char *text) | |
5143 DW_FUNCTION_ADD_PARAM2(handle, text) | |
5144 DW_FUNCTION_NO_RETURN(dw_listbox_append) | |
5145 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, text, char *) | |
5146 { | |
5147 DW_FUNCTION_INIT; | |
5148 id object = handle; | |
5149 | |
5150 if([object isMemberOfClass:[DWComboBox class]]) | |
5151 { | |
5152 DWComboBox *combo = handle; | |
5153 | |
5154 [combo addItemWithObjectValue:[NSString stringWithUTF8String:text]]; | |
5155 } | |
5156 else if([object isMemberOfClass:[DWContainer class]]) | |
5157 { | |
5158 DWContainer *cont = handle; | |
5159 NSString *nstr = [NSString stringWithUTF8String:text]; | |
5160 NSArray *newrow = [NSArray arrayWithObject:_dw_table_cell_view_new(nil, nstr)]; | |
5161 | |
5162 [cont addRow:newrow]; | |
5163 [cont reloadData]; | |
5164 [cont optimize]; | |
5165 [cont setNeedsDisplay:YES]; | |
5166 } | |
5167 DW_FUNCTION_RETURN_NOTHING; | |
5168 } | |
5169 | |
5170 /* | |
5171 * Inserts the specified text into the listbox's (or combobox) entry list. | |
5172 * Parameters: | |
5173 * handle: Handle to the listbox to be inserted into. | |
5174 * text: Text to insert into listbox. | |
5175 * pos: 0-based position to insert text | |
5176 */ | |
5177 DW_FUNCTION_DEFINITION(dw_listbox_insert, void, HWND handle, const char *text, int pos) | |
5178 DW_FUNCTION_ADD_PARAM3(handle, text, pos) | |
5179 DW_FUNCTION_NO_RETURN(dw_listbox_insert) | |
5180 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, text, const char *, pos, int) | |
5181 { | |
5182 DW_FUNCTION_INIT; | |
5183 id object = handle; | |
5184 | |
5185 if([object isMemberOfClass:[DWComboBox class]]) | |
5186 { | |
5187 DWComboBox *combo = handle; | |
5188 | |
5189 [combo insertItemWithObjectValue:[NSString stringWithUTF8String:text] atIndex:pos]; | |
5190 } | |
5191 else if([object isMemberOfClass:[DWContainer class]]) | |
5192 { | |
5193 DWContainer *cont = handle; | |
5194 NSString *nstr = [NSString stringWithUTF8String:text]; | |
5195 NSArray *newrow = [NSArray arrayWithObject:_dw_table_cell_view_new(nil, nstr)]; | |
5196 | |
5197 [cont insertRow:newrow at:pos]; | |
5198 [cont reloadData]; | |
5199 [cont optimize]; | |
5200 [cont setNeedsDisplay:YES]; | |
5201 } | |
5202 DW_FUNCTION_RETURN_NOTHING; | |
5203 } | |
5204 | |
5205 /* | |
5206 * Appends the specified text items to the listbox's (or combobox) entry list. | |
5207 * Parameters: | |
5208 * handle: Handle to the listbox to be appended to. | |
5209 * text: Text strings to append into listbox. | |
5210 * count: Number of text strings to append | |
5211 */ | |
5212 DW_FUNCTION_DEFINITION(dw_listbox_list_append, void, HWND handle, char **text, int count) | |
5213 DW_FUNCTION_ADD_PARAM3(handle, text, count) | |
5214 DW_FUNCTION_NO_RETURN(dw_listbox_list_append) | |
5215 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, text, char **, count, int) | |
5216 { | |
5217 DW_FUNCTION_INIT; | |
5218 id object = handle; | |
5219 | |
5220 if([object isMemberOfClass:[DWComboBox class]]) | |
5221 { | |
5222 DWComboBox *combo = handle; | |
5223 int z; | |
5224 | |
5225 for(z=0;z<count;z++) | |
5226 { | |
5227 [combo addItemWithObjectValue:[ NSString stringWithUTF8String:text[z] ]]; | |
5228 } | |
5229 } | |
5230 else if([object isMemberOfClass:[DWContainer class]]) | |
5231 { | |
5232 DWContainer *cont = handle; | |
5233 int z; | |
5234 | |
5235 for(z=0;z<count;z++) | |
5236 { | |
5237 NSString *nstr = [NSString stringWithUTF8String:text[z]]; | |
5238 NSArray *newrow = [NSArray arrayWithObjects:_dw_table_cell_view_new(nil, nstr),nil]; | |
5239 | |
5240 [cont addRow:newrow]; | |
5241 } | |
5242 [cont reloadData]; | |
5243 [cont optimize]; | |
5244 [cont setNeedsDisplay:YES]; | |
5245 } | |
5246 DW_FUNCTION_RETURN_NOTHING; | |
5247 } | |
5248 | |
5249 /* | |
5250 * Clears the listbox's (or combobox) list of all entries. | |
5251 * Parameters: | |
5252 * handle: Handle to the listbox to be cleared. | |
5253 */ | |
5254 DW_FUNCTION_DEFINITION(dw_listbox_clear, void, HWND handle) | |
5255 DW_FUNCTION_ADD_PARAM1(handle) | |
5256 DW_FUNCTION_NO_RETURN(dw_listbox_clear) | |
5257 DW_FUNCTION_RESTORE_PARAM1(handle, HWND) | |
5258 { | |
5259 DW_FUNCTION_INIT; | |
5260 id object = handle; | |
5261 | |
5262 if([object isMemberOfClass:[DWComboBox class]]) | |
5263 { | |
5264 DWComboBox *combo = handle; | |
5265 | |
5266 [combo removeAllItems]; | |
5267 } | |
5268 else if([object isMemberOfClass:[DWContainer class]]) | |
5269 { | |
5270 DWContainer *cont = handle; | |
5271 | |
5272 [cont clear]; | |
5273 [cont reloadData]; | |
5274 [cont setNeedsDisplay:YES]; | |
5275 } | |
5276 DW_FUNCTION_RETURN_NOTHING; | |
5277 } | |
5278 | |
5279 /* | |
5280 * Returns the listbox's item count. | |
5281 * Parameters: | |
5282 * handle: Handle to the listbox to be cleared. | |
5283 */ | |
5284 DW_FUNCTION_DEFINITION(dw_listbox_count, int, HWND handle) | |
5285 DW_FUNCTION_ADD_PARAM1(handle) | |
5286 DW_FUNCTION_RETURN(dw_listbox_count, int) | |
5287 DW_FUNCTION_RESTORE_PARAM1(handle, HWND) | |
5288 { | |
5289 DW_FUNCTION_INIT; | |
5290 id object = handle; | |
5291 int result = 0; | |
5292 | |
5293 if([object isMemberOfClass:[DWComboBox class]]) | |
5294 { | |
5295 DWComboBox *combo = handle; | |
5296 | |
5297 result = (int)[combo numberOfItems]; | |
5298 } | |
5299 else if([object isMemberOfClass:[DWContainer class]]) | |
5300 { | |
5301 DWContainer *cont = handle; | |
5302 result = (int)[cont numberOfRowsInTableView:cont]; | |
5303 } | |
5304 DW_FUNCTION_RETURN_THIS(result); | |
5305 } | |
5306 | |
5307 /* | |
5308 * Sets the topmost item in the viewport. | |
5309 * Parameters: | |
5310 * handle: Handle to the listbox to be cleared. | |
5311 * top: Index to the top item. | |
5312 */ | |
5313 DW_FUNCTION_DEFINITION(dw_listbox_set_top, void, HWND handle, int top) | |
5314 DW_FUNCTION_ADD_PARAM2(handle, top) | |
5315 DW_FUNCTION_NO_RETURN(dw_listbox_set_top) | |
5316 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, top, int) | |
5317 { | |
5318 DW_FUNCTION_INIT; | |
5319 id object = handle; | |
5320 | |
5321 if([object isMemberOfClass:[DWComboBox class]]) | |
5322 { | |
5323 DWComboBox *combo = handle; | |
5324 | |
5325 [combo scrollItemAtIndexToTop:top]; | |
5326 } | |
5327 else if([object isMemberOfClass:[DWContainer class]]) | |
5328 { | |
5329 DWContainer *cont = handle; | |
5330 | |
5331 [cont scrollRowToVisible:top]; | |
5332 } | |
5333 DW_FUNCTION_RETURN_NOTHING; | |
5334 } | |
5335 | |
5336 /* | |
5337 * Copies the given index item's text into buffer. | |
5338 * Parameters: | |
5339 * handle: Handle to the listbox to be queried. | |
5340 * index: Index into the list to be queried. | |
5341 * buffer: Buffer where text will be copied. | |
5342 * length: Length of the buffer (including NULL). | |
5343 */ | |
5344 DW_FUNCTION_DEFINITION(dw_listbox_get_text, void, HWND handle, unsigned int index, char *buffer, unsigned int length) | |
5345 DW_FUNCTION_ADD_PARAM4(handle, index, buffer, length) | |
5346 DW_FUNCTION_NO_RETURN(dw_listbox_get_text) | |
5347 DW_FUNCTION_RESTORE_PARAM4(handle, HWND, index, unsigned int, buffer, char *, length, unsigned int) | |
5348 { | |
5349 DW_FUNCTION_INIT; | |
5350 id object = handle; | |
5351 | |
5352 if([object isMemberOfClass:[DWComboBox class]]) | |
5353 { | |
5354 DWComboBox *combo = handle; | |
5355 int count = (int)[combo numberOfItems]; | |
5356 | |
5357 if(index > count) | |
5358 { | |
5359 *buffer = '\0'; | |
5360 } | |
5361 else | |
5362 { | |
5363 NSString *nstr = [combo itemObjectValueAtIndex:index]; | |
5364 strncpy(buffer, [ nstr UTF8String ], length - 1); | |
5365 } | |
5366 } | |
5367 else if([object isMemberOfClass:[DWContainer class]]) | |
5368 { | |
5369 DWContainer *cont = handle; | |
5370 int count = (int)[cont numberOfRowsInTableView:cont]; | |
5371 | |
5372 if(index > count) | |
5373 { | |
5374 *buffer = '\0'; | |
5375 } | |
5376 else | |
5377 { | |
5378 NSTableCellView *cell = [cont getRow:index and:0]; | |
5379 NSString *nstr = [[cell textField] stringValue]; | |
5380 | |
5381 strncpy(buffer, [nstr UTF8String], length - 1); | |
5382 } | |
5383 } | |
5384 DW_FUNCTION_RETURN_NOTHING; | |
5385 } | |
5386 | |
5387 /* | |
5388 * Sets the text of a given listbox entry. | |
5389 * Parameters: | |
5390 * handle: Handle to the listbox to be queried. | |
5391 * index: Index into the list to be queried. | |
5392 * buffer: Buffer where text will be copied. | |
5393 */ | |
5394 DW_FUNCTION_DEFINITION(dw_listbox_set_text, void, HWND handle, unsigned int index, const char *buffer) | |
5395 DW_FUNCTION_ADD_PARAM3(handle, index, buffer) | |
5396 DW_FUNCTION_NO_RETURN(dw_listbox_set_text) | |
5397 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, index, unsigned int, buffer, char *) | |
5398 { | |
5399 DW_FUNCTION_INIT; | |
5400 id object = handle; | |
5401 | |
5402 if([object isMemberOfClass:[DWComboBox class]]) | |
5403 { | |
5404 DWComboBox *combo = handle; | |
5405 int count = (int)[combo numberOfItems]; | |
5406 | |
5407 if(index <= count) | |
5408 { | |
5409 [combo removeItemAtIndex:index]; | |
5410 [combo insertItemWithObjectValue:[NSString stringWithUTF8String:buffer] atIndex:index]; | |
5411 } | |
5412 } | |
5413 else if([object isMemberOfClass:[DWContainer class]]) | |
5414 { | |
5415 DWContainer *cont = handle; | |
5416 int count = (int)[cont numberOfRowsInTableView:cont]; | |
5417 | |
5418 if(index <= count) | |
5419 { | |
5420 NSString *nstr = [NSString stringWithUTF8String:buffer]; | |
5421 NSTableCellView *cell = [cont getRow:index and:0]; | |
5422 | |
5423 [[cell textField] setStringValue:nstr]; | |
5424 [cont reloadData]; | |
5425 [cont optimize]; | |
5426 [cont setNeedsDisplay:YES]; | |
5427 } | |
5428 } | |
5429 DW_FUNCTION_RETURN_NOTHING; | |
5430 } | |
5431 | |
5432 /* | |
5433 * Returns the index to the item in the list currently selected. | |
5434 * Parameters: | |
5435 * handle: Handle to the listbox to be queried. | |
5436 */ | |
5437 DW_FUNCTION_DEFINITION(dw_listbox_selected, int, HWND handle) | |
5438 DW_FUNCTION_ADD_PARAM1(handle) | |
5439 DW_FUNCTION_RETURN(dw_listbox_selected, int) | |
5440 DW_FUNCTION_RESTORE_PARAM1(handle, HWND) | |
5441 { | |
5442 DW_FUNCTION_INIT; | |
5443 id object = handle; | |
5444 int result = -1; | |
5445 | |
5446 if([object isMemberOfClass:[DWComboBox class]]) | |
5447 { | |
5448 DWComboBox *combo = handle; | |
5449 result = (int)[combo indexOfSelectedItem]; | |
5450 } | |
5451 else if([object isMemberOfClass:[DWContainer class]]) | |
5452 { | |
5453 DWContainer *cont = handle; | |
5454 result = (int)[cont selectedRow]; | |
5455 } | |
5456 DW_FUNCTION_RETURN_THIS(result); | |
5457 } | |
5458 | |
5459 /* | |
5460 * Returns the index to the current selected item or -1 when done. | |
5461 * Parameters: | |
5462 * handle: Handle to the listbox to be queried. | |
5463 * where: Either the previous return or -1 to restart. | |
5464 */ | |
5465 DW_FUNCTION_DEFINITION(dw_listbox_selected_multi, int, HWND handle, int where) | |
5466 DW_FUNCTION_ADD_PARAM2(handle, where) | |
5467 DW_FUNCTION_RETURN(dw_listbox_selected_multi, int) | |
5468 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, where, int) | |
5469 { | |
5470 DW_FUNCTION_INIT; | |
5471 id object = handle; | |
5472 int retval = -1; | |
5473 | |
5474 if([object isMemberOfClass:[DWContainer class]]) | |
5475 { | |
5476 NSUInteger result; | |
5477 DWContainer *cont = handle; | |
5478 NSIndexSet *selected = [cont selectedRowIndexes]; | |
5479 if( where == -1 ) | |
5480 result = [selected indexGreaterThanOrEqualToIndex:0]; | |
5481 else | |
5482 result = [selected indexGreaterThanIndex:where]; | |
5483 | |
5484 if(result != NSNotFound) | |
5485 { | |
5486 retval = (int)result; | |
5487 } | |
5488 } | |
5489 DW_FUNCTION_RETURN_THIS(retval) | |
5490 } | |
5491 | |
5492 /* | |
5493 * Sets the selection state of a given index. | |
5494 * Parameters: | |
5495 * handle: Handle to the listbox to be set. | |
5496 * index: Item index. | |
5497 * state: TRUE if selected FALSE if unselected. | |
5498 */ | |
5499 DW_FUNCTION_DEFINITION(dw_listbox_select, void, HWND handle, int index, int state) | |
5500 DW_FUNCTION_ADD_PARAM3(handle, index, state) | |
5501 DW_FUNCTION_NO_RETURN(dw_listbox_select) | |
5502 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, index, int, state, int) | |
5503 { | |
5504 DW_FUNCTION_INIT; | |
5505 id object = handle; | |
5506 | |
5507 if([object isMemberOfClass:[DWComboBox class]]) | |
5508 { | |
5509 DWComboBox *combo = handle; | |
5510 if(state) | |
5511 [combo selectItemAtIndex:index]; | |
5512 else | |
5513 [combo deselectItemAtIndex:index]; | |
5514 } | |
5515 else if([object isMemberOfClass:[DWContainer class]]) | |
5516 { | |
5517 DWContainer *cont = handle; | |
5518 NSIndexSet *selected = [[NSIndexSet alloc] initWithIndex:(NSUInteger)index]; | |
5519 | |
5520 [cont selectRowIndexes:selected byExtendingSelection:YES]; | |
5521 [selected release]; | |
5522 } | |
5523 DW_FUNCTION_RETURN_NOTHING; | |
5524 } | |
5525 | |
5526 /* | |
5527 * Deletes the item with given index from the list. | |
5528 * Parameters: | |
5529 * handle: Handle to the listbox to be set. | |
5530 * index: Item index. | |
5531 */ | |
5532 DW_FUNCTION_DEFINITION(dw_listbox_delete, void, HWND handle, int index) | |
5533 DW_FUNCTION_ADD_PARAM2(handle, index) | |
5534 DW_FUNCTION_NO_RETURN(dw_listbox_delete) | |
5535 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, index, int) | |
5536 { | |
5537 DW_FUNCTION_INIT; | |
5538 id object = handle; | |
5539 | |
5540 if([object isMemberOfClass:[DWComboBox class]]) | |
5541 { | |
5542 DWComboBox *combo = handle; | |
5543 | |
5544 [combo removeItemAtIndex:index]; | |
5545 } | |
5546 else if([object isMemberOfClass:[DWContainer class]]) | |
5547 { | |
5548 DWContainer *cont = handle; | |
5549 | |
5550 [cont removeRow:index]; | |
5551 [cont reloadData]; | |
5552 [cont setNeedsDisplay:YES]; | |
5553 } | |
5554 DW_FUNCTION_RETURN_NOTHING; | |
5555 } | |
5556 | |
5557 /* | |
5558 * Create a new Combobox window (widget) to be packed. | |
5559 * Parameters: | |
5560 * text: The default text to be in the combpbox widget. | |
5561 * id: An ID to be used with dw_window_from_id() or 0L. | |
5562 */ | |
5563 DW_FUNCTION_DEFINITION(dw_combobox_new, HWND, const char *text, ULONG cid) | |
5564 DW_FUNCTION_ADD_PARAM2(text, cid) | |
5565 DW_FUNCTION_RETURN(dw_combobox_new, HWND) | |
5566 DW_FUNCTION_RESTORE_PARAM2(text, const char *, cid, ULONG) | |
5567 { | |
5568 DW_FUNCTION_INIT; | |
5569 DWComboBox *combo = [[DWComboBox alloc] init]; | |
5570 [combo setStringValue:[NSString stringWithUTF8String:text]]; | |
5571 [combo setDelegate:combo]; | |
5572 [combo setTag:cid]; | |
5573 DW_FUNCTION_RETURN_THIS(combo); | |
5574 } | |
5575 | |
5576 /* | |
5577 * Create a new Multiline Editbox window (widget) to be packed. | |
5578 * Parameters: | |
5579 * id: An ID to be used with dw_window_from_id() or 0L. | |
5580 */ | |
5581 HWND API dw_mle_new(ULONG cid) | |
5582 { | |
5583 DWMLE *mle = [[DWMLE alloc] init]; | |
5584 UIScrollView *scrollview = [[UIScrollView alloc] init]; | |
5585 NSSize size = [mle maxSize]; | |
5586 | |
5587 size.width = size.height; | |
5588 [mle setMaxSize:size]; | |
5589 [scrollview setBorderType:NSBezelBorder]; | |
5590 [scrollview setHasVerticalScroller:YES]; | |
5591 [scrollview setAutohidesScrollers:YES]; | |
5592 [scrollview setAutoresizingMask:UIViewWidthSizable|UIViewHeightSizable]; | |
5593 [scrollview setDocumentView:mle]; | |
5594 [mle setVerticallyResizable:YES]; | |
5595 [mle setAutoresizingMask:UIViewWidthSizable|UIViewHeightSizable]; | |
5596 [mle setScrollview:scrollview]; | |
5597 [mle setAutomaticQuoteSubstitutionEnabled:NO]; | |
5598 [mle setAutomaticDashSubstitutionEnabled:NO]; | |
5599 [mle setAutomaticTextReplacementEnabled:NO]; | |
5600 /* [mle setTag:cid]; Why doesn't this work? */ | |
5601 [mle autorelease]; | |
5602 return mle; | |
5603 } | |
5604 | |
5605 /* | |
5606 * Adds text to an MLE box and returns the current point. | |
5607 * Parameters: | |
5608 * handle: Handle to the MLE to be queried. | |
5609 * buffer: Text buffer to be imported. | |
5610 * startpoint: Point to start entering text. | |
5611 */ | |
5612 DW_FUNCTION_DEFINITION(dw_mle_import, unsigned int, HWND handle, const char *buffer, int startpoint) | |
5613 DW_FUNCTION_ADD_PARAM3(handle, buffer, startpoint) | |
5614 DW_FUNCTION_RETURN(dw_mle_import, unsigned int) | |
5615 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, buffer, const char *, startpoint, int) | |
5616 { | |
5617 DW_FUNCTION_INIT; | |
5618 DWMLE *mle = handle; | |
5619 unsigned int retval; | |
5620 NSTextStorage *ts = [mle textStorage]; | |
5621 NSString *nstr = [NSString stringWithUTF8String:buffer]; | |
5622 UIColor *fgcolor = [ts foregroundColor]; | |
5623 UIFont *font = [ts font]; | |
5624 NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init]; | |
5625 [attributes setObject:(fgcolor ? fgcolor : [UIColor textColor]) forKey:NSForegroundColorAttributeName]; | |
5626 if(font) | |
5627 [attributes setObject:font forKey:UIFontAttributeName]; | |
5628 NSAttributedString *nastr = [[NSAttributedString alloc] initWithString:nstr attributes:attributes]; | |
5629 NSUInteger length = [ts length]; | |
5630 if(startpoint < 0) | |
5631 startpoint = 0; | |
5632 if(startpoint > length) | |
5633 startpoint = (int)length; | |
5634 [ts insertAttributedString:nastr atIndex:startpoint]; | |
5635 retval = (unsigned int)strlen(buffer) + startpoint; | |
5636 DW_FUNCTION_RETURN_THIS(retval); | |
5637 } | |
5638 | |
5639 /* | |
5640 * Grabs text from an MLE box. | |
5641 * Parameters: | |
5642 * handle: Handle to the MLE to be queried. | |
5643 * buffer: Text buffer to be exported. | |
5644 * startpoint: Point to start grabbing text. | |
5645 * length: Amount of text to be grabbed. | |
5646 */ | |
5647 DW_FUNCTION_DEFINITION(dw_mle_export, void, HWND handle, char *buffer, int startpoint, int length) | |
5648 DW_FUNCTION_ADD_PARAM4(handle, buffer, startpoint, length) | |
5649 DW_FUNCTION_NO_RETURN(dw_mle_export) | |
5650 DW_FUNCTION_RESTORE_PARAM4(handle, HWND, buffer, char *, startpoint, int, length, int) | |
5651 { | |
5652 DW_FUNCTION_INIT; | |
5653 DWMLE *mle = handle; | |
5654 NSTextStorage *ts = [mle textStorage]; | |
5655 NSMutableString *ms = [ts mutableString]; | |
5656 const char *tmp = [ms UTF8String]; | |
5657 strncpy(buffer, tmp+startpoint, length); | |
5658 buffer[length] = '\0'; | |
5659 DW_FUNCTION_RETURN_NOTHING; | |
5660 } | |
5661 | |
5662 /* | |
5663 * Obtains information about an MLE box. | |
5664 * Parameters: | |
5665 * handle: Handle to the MLE to be queried. | |
5666 * bytes: A pointer to a variable to return the total bytes. | |
5667 * lines: A pointer to a variable to return the number of lines. | |
5668 */ | |
5669 DW_FUNCTION_DEFINITION(dw_mle_get_size, void, HWND handle, unsigned long *bytes, unsigned long *lines) | |
5670 DW_FUNCTION_ADD_PARAM3(handle, bytes, lines) | |
5671 DW_FUNCTION_NO_RETURN(dw_mle_get_size) | |
5672 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, bytes, unsigned long *, lines, unsigned long *) | |
5673 { | |
5674 DW_FUNCTION_INIT; | |
5675 DWMLE *mle = handle; | |
5676 NSTextStorage *ts = [mle textStorage]; | |
5677 NSMutableString *ms = [ts mutableString]; | |
5678 NSUInteger numberOfLines, index, stringLength = [ms length]; | |
5679 | |
5680 if(bytes) | |
5681 *bytes = stringLength; | |
5682 if(lines) | |
5683 { | |
5684 for(index=0, numberOfLines=0; index < stringLength; numberOfLines++) | |
5685 index = NSMaxRange([ms lineRangeForRange:NSMakeRange(index, 0)]); | |
5686 | |
5687 *lines = numberOfLines; | |
5688 } | |
5689 DW_FUNCTION_RETURN_NOTHING; | |
5690 } | |
5691 | |
5692 /* | |
5693 * Deletes text from an MLE box. | |
5694 * Parameters: | |
5695 * handle: Handle to the MLE to be deleted from. | |
5696 * startpoint: Point to start deleting text. | |
5697 * length: Amount of text to be deleted. | |
5698 */ | |
5699 DW_FUNCTION_DEFINITION(dw_mle_delete, void, HWND handle, int startpoint, int length) | |
5700 DW_FUNCTION_ADD_PARAM3(handle, startpoint, length) | |
5701 DW_FUNCTION_NO_RETURN(dw_mle_delete) | |
5702 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, startpoint, int, length, int) | |
5703 { | |
5704 DW_FUNCTION_INIT; | |
5705 DWMLE *mle = handle; | |
5706 NSTextStorage *ts = [mle textStorage]; | |
5707 NSMutableString *ms = [ts mutableString]; | |
5708 NSUInteger mslength = [ms length]; | |
5709 if(startpoint < 0) | |
5710 startpoint = 0; | |
5711 if(startpoint > mslength) | |
5712 startpoint = (int)mslength; | |
5713 if(startpoint + length > mslength) | |
5714 length = (int)mslength - startpoint; | |
5715 [ms deleteCharactersInRange:NSMakeRange(startpoint, length)]; | |
5716 DW_FUNCTION_RETURN_NOTHING; | |
5717 } | |
5718 | |
5719 /* | |
5720 * Clears all text from an MLE box. | |
5721 * Parameters: | |
5722 * handle: Handle to the MLE to be cleared. | |
5723 */ | |
5724 DW_FUNCTION_DEFINITION(dw_mle_clear, void, HWND handle) | |
5725 DW_FUNCTION_ADD_PARAM1(handle) | |
5726 DW_FUNCTION_NO_RETURN(dw_mle_clear) | |
5727 DW_FUNCTION_RESTORE_PARAM1(handle, HWND) | |
5728 { | |
5729 DW_FUNCTION_INIT; | |
5730 DWMLE *mle = handle; | |
5731 NSTextStorage *ts = [mle textStorage]; | |
5732 NSMutableString *ms = [ts mutableString]; | |
5733 NSUInteger length = [ms length]; | |
5734 [ms deleteCharactersInRange:NSMakeRange(0, length)]; | |
5735 DW_FUNCTION_RETURN_NOTHING; | |
5736 } | |
5737 | |
5738 /* | |
5739 * Sets the visible line of an MLE box. | |
5740 * Parameters: | |
5741 * handle: Handle to the MLE to be positioned. | |
5742 * line: Line to be visible. | |
5743 */ | |
5744 DW_FUNCTION_DEFINITION(dw_mle_set_visible, void, HWND handle, int line) | |
5745 DW_FUNCTION_ADD_PARAM2(handle, line) | |
5746 DW_FUNCTION_NO_RETURN(dw_mle_set_visible) | |
5747 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, line, int) | |
5748 { | |
5749 DW_FUNCTION_INIT; | |
5750 DWMLE *mle = handle; | |
5751 NSTextStorage *ts = [mle textStorage]; | |
5752 NSMutableString *ms = [ts mutableString]; | |
5753 NSUInteger numberOfLines, index, stringLength = [ms length]; | |
5754 | |
5755 for(index=0, numberOfLines=0; index < stringLength && numberOfLines < line; numberOfLines++) | |
5756 index = NSMaxRange([ms lineRangeForRange:NSMakeRange(index, 0)]); | |
5757 | |
5758 if(line == numberOfLines) | |
5759 { | |
5760 [mle scrollRangeToVisible:[ms lineRangeForRange:NSMakeRange(index, 0)]]; | |
5761 } | |
5762 DW_FUNCTION_RETURN_NOTHING; | |
5763 } | |
5764 | |
5765 /* | |
5766 * Sets the editablity of an MLE box. | |
5767 * Parameters: | |
5768 * handle: Handle to the MLE. | |
5769 * state: TRUE if it can be edited, FALSE for readonly. | |
5770 */ | |
5771 void API dw_mle_set_editable(HWND handle, int state) | |
5772 { | |
5773 DWMLE *mle = handle; | |
5774 if(state) | |
5775 { | |
5776 [mle setEditable:YES]; | |
5777 } | |
5778 else | |
5779 { | |
5780 [mle setEditable:NO]; | |
5781 } | |
5782 } | |
5783 | |
5784 /* | |
5785 * Sets the word wrap state of an MLE box. | |
5786 * Parameters: | |
5787 * handle: Handle to the MLE. | |
5788 * state: TRUE if it wraps, FALSE if it doesn't. | |
5789 */ | |
5790 void API dw_mle_set_word_wrap(HWND handle, int state) | |
5791 { | |
5792 DWMLE *mle = handle; | |
5793 UIScrollView *sv = [mle scrollview]; | |
5794 | |
5795 if(state) | |
5796 { | |
5797 NSSize newsize = NSMakeSize([sv contentSize].width,[mle maxSize].height); | |
5798 NSRect newrect = NSMakeRect(0, 0, [sv contentSize].width, 0); | |
5799 | |
5800 [[mle textContainer] setWidthTracksTextView:YES]; | |
5801 [mle setFrame:newrect]; | |
5802 [[mle textContainer] setContainerSize:newsize]; | |
5803 [mle setHorizontallyResizable:NO]; | |
5804 [sv setHasHorizontalScroller:NO]; | |
5805 } | |
5806 else | |
5807 { | |
5808 [[mle textContainer] setWidthTracksTextView:NO]; | |
5809 [[mle textContainer] setContainerSize:[mle maxSize]]; | |
5810 [mle setHorizontallyResizable:YES]; | |
5811 [sv setHasHorizontalScroller:YES]; | |
5812 } | |
5813 } | |
5814 | |
5815 /* | |
5816 * Sets the word auto complete state of an MLE box. | |
5817 * Parameters: | |
5818 * handle: Handle to the MLE. | |
5819 * state: Bitwise combination of DW_MLE_COMPLETE_TEXT/DASH/QUOTE | |
5820 */ | |
5821 void API dw_mle_set_auto_complete(HWND handle, int state) | |
5822 { | |
5823 DWMLE *mle = handle; | |
5824 [mle setAutomaticQuoteSubstitutionEnabled:(state & DW_MLE_COMPLETE_QUOTE ? YES : NO)]; | |
5825 [mle setAutomaticDashSubstitutionEnabled:(state & DW_MLE_COMPLETE_DASH ? YES : NO)]; | |
5826 [mle setAutomaticTextReplacementEnabled:(state & DW_MLE_COMPLETE_TEXT ? YES : NO)]; | |
5827 } | |
5828 | |
5829 /* | |
5830 * Sets the current cursor position of an MLE box. | |
5831 * Parameters: | |
5832 * handle: Handle to the MLE to be positioned. | |
5833 * point: Point to position cursor. | |
5834 */ | |
5835 DW_FUNCTION_DEFINITION(dw_mle_set_cursor, void, HWND handle, int point) | |
5836 DW_FUNCTION_ADD_PARAM2(handle, point) | |
5837 DW_FUNCTION_NO_RETURN(dw_mle_set_cursor) | |
5838 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, point, int) | |
5839 { | |
5840 DW_FUNCTION_INIT; | |
5841 DWMLE *mle = handle; | |
5842 NSTextStorage *ts = [mle textStorage]; | |
5843 NSMutableString *ms = [ts mutableString]; | |
5844 NSUInteger length = [ms length]; | |
5845 if(point < 0) | |
5846 point = 0; | |
5847 if(point > length) | |
5848 point = (int)length; | |
5849 [mle setSelectedRange: NSMakeRange(point,point)]; | |
5850 [mle scrollRangeToVisible:NSMakeRange(point,point)]; | |
5851 DW_FUNCTION_RETURN_NOTHING; | |
5852 } | |
5853 | |
5854 /* | |
5855 * Finds text in an MLE box. | |
5856 * Parameters: | |
5857 * handle: Handle to the MLE to be cleared. | |
5858 * text: Text to search for. | |
5859 * point: Start point of search. | |
5860 * flags: Search specific flags. | |
5861 */ | |
5862 DW_FUNCTION_DEFINITION(dw_mle_search, int, HWND handle, const char *text, int point, unsigned long flags) | |
5863 DW_FUNCTION_ADD_PARAM4(handle, text, point, flags) | |
5864 DW_FUNCTION_RETURN(dw_mle_search, int) | |
5865 DW_FUNCTION_RESTORE_PARAM4(handle, HWND, text, const char *, point, int, flags, unsigned long) | |
5866 { | |
5867 DW_FUNCTION_INIT; | |
5868 DWMLE *mle = handle; | |
5869 NSTextStorage *ts = [mle textStorage]; | |
5870 NSMutableString *ms = [ts mutableString]; | |
5871 NSString *searchForMe = [NSString stringWithUTF8String:text]; | |
5872 NSRange searchRange = NSMakeRange(point, [ms length] - point); | |
5873 NSRange range = NSMakeRange(NSNotFound, 0); | |
5874 NSUInteger options = flags ? flags : NSCaseInsensitiveSearch; | |
5875 int retval = -1; | |
5876 | |
5877 if(ms) | |
5878 range = [ms rangeOfString:searchForMe options:options range:searchRange]; | |
5879 if(range.location == NSNotFound) | |
5880 retval = (int)range.location; | |
5881 DW_FUNCTION_RETURN_THIS(retval); | |
5882 } | |
5883 | |
5884 /* | |
5885 * Stops redrawing of an MLE box. | |
5886 * Parameters: | |
5887 * handle: Handle to the MLE to freeze. | |
5888 */ | |
5889 void API dw_mle_freeze(HWND handle) | |
5890 { | |
5891 /* Don't think this is necessary */ | |
5892 } | |
5893 | |
5894 /* | |
5895 * Resumes redrawing of an MLE box. | |
5896 * Parameters: | |
5897 * handle: Handle to the MLE to thaw. | |
5898 */ | |
5899 void API dw_mle_thaw(HWND handle) | |
5900 { | |
5901 /* Don't think this is necessary */ | |
5902 } | |
5903 | |
5904 /* | |
5905 * Create a new status text window (widget) to be packed. | |
5906 * Parameters: | |
5907 * text: The text to be display by the static text widget. | |
5908 * id: An ID to be used with dw_window_from_id() or 0L. | |
5909 */ | |
5910 HWND API dw_status_text_new(const char *text, ULONG cid) | |
5911 { | |
5912 NSBox *border = [[NSBox alloc] init]; | |
5913 UITextField *textfield = dw_text_new(text, cid); | |
5914 | |
5915 [border setTitlePosition:NSNoTitle]; | |
5916 [border setContentView:textfield]; | |
5917 [border setContentViewMargins:NSMakeSize(1.5,1.5)]; | |
5918 [textfield autorelease]; | |
5919 [textfield setBackgroundColor:[UIColor clearColor]]; | |
5920 [[textfield cell] setVCenter:YES]; | |
5921 return border; | |
5922 } | |
5923 | |
5924 /* | |
5925 * Create a new static text window (widget) to be packed. | |
5926 * Parameters: | |
5927 * text: The text to be display by the static text widget. | |
5928 * id: An ID to be used with dw_window_from_id() or 0L. | |
5929 */ | |
5930 HWND API dw_text_new(const char *text, ULONG cid) | |
5931 { | |
5932 DWText *textfield = [[DWText alloc] init]; | |
5933 [textfield setEditable:NO]; | |
5934 [textfield setSelectable:NO]; | |
5935 [textfield setBordered:NO]; | |
5936 [textfield setDrawsBackground:NO]; | |
5937 [textfield setStringValue:[ NSString stringWithUTF8String:text ]]; | |
5938 [textfield setTag:cid]; | |
5939 if(DWDefaultFont) | |
5940 { | |
5941 [[textfield cell] setFont:DWDefaultFont]; | |
5942 } | |
5943 [[textfield cell] setWraps:NO]; | |
5944 return textfield; | |
5945 } | |
5946 | |
5947 /* | |
5948 * Creates a rendering context widget (window) to be packed. | |
5949 * Parameters: | |
5950 * id: An id to be used with dw_window_from_id. | |
5951 * Returns: | |
5952 * A handle to the widget or NULL on failure. | |
5953 */ | |
5954 HWND API dw_render_new(unsigned long cid) | |
5955 { | |
5956 DWRender *render = [[DWRender alloc] init]; | |
5957 [render setTag:cid]; | |
5958 return render; | |
5959 } | |
5960 | |
5961 /* | |
5962 * Invalidate the render widget triggering an expose event. | |
5963 * Parameters: | |
5964 * handle: A handle to a render widget to be redrawn. | |
5965 */ | |
5966 DW_FUNCTION_DEFINITION(dw_render_redraw, void, HWND handle) | |
5967 DW_FUNCTION_ADD_PARAM1(handle) | |
5968 DW_FUNCTION_NO_RETURN(dw_render_redraw) | |
5969 DW_FUNCTION_RESTORE_PARAM1(handle, HWND) | |
5970 { | |
5971 DW_FUNCTION_INIT; | |
5972 DWRender *render = (DWRender *)handle; | |
5973 | |
5974 [render setNeedsDisplay:YES]; | |
5975 DW_FUNCTION_RETURN_NOTHING; | |
5976 } | |
5977 | |
5978 /* Sets the current foreground drawing color. | |
5979 * Parameters: | |
5980 * red: red value. | |
5981 * green: green value. | |
5982 * blue: blue value. | |
5983 */ | |
5984 void API dw_color_foreground_set(unsigned long value) | |
5985 { | |
5986 UIColor *oldcolor = pthread_getspecific(_dw_fg_color_key); | |
5987 UIColor *newcolor; | |
5988 DW_LOCAL_POOL_IN; | |
5989 | |
5990 _foreground = _get_color(value); | |
5991 | |
5992 newcolor = [[UIColor colorWithDeviceRed: DW_RED_VALUE(_foreground)/255.0 green: | |
5993 DW_GREEN_VALUE(_foreground)/255.0 blue: | |
5994 DW_BLUE_VALUE(_foreground)/255.0 alpha: 1] retain]; | |
5995 pthread_setspecific(_dw_fg_color_key, newcolor); | |
5996 [oldcolor release]; | |
5997 DW_LOCAL_POOL_OUT; | |
5998 } | |
5999 | |
6000 /* Sets the current background drawing color. | |
6001 * Parameters: | |
6002 * red: red value. | |
6003 * green: green value. | |
6004 * blue: blue value. | |
6005 */ | |
6006 void API dw_color_background_set(unsigned long value) | |
6007 { | |
6008 UIColor *oldcolor = pthread_getspecific(_dw_bg_color_key); | |
6009 UIColor *newcolor; | |
6010 DW_LOCAL_POOL_IN; | |
6011 | |
6012 if(value == DW_CLR_DEFAULT) | |
6013 { | |
6014 pthread_setspecific(_dw_bg_color_key, NULL); | |
6015 } | |
6016 else | |
6017 { | |
6018 _background = _get_color(value); | |
6019 | |
6020 newcolor = [[UIColor colorWithDeviceRed: DW_RED_VALUE(_background)/255.0 green: | |
6021 DW_GREEN_VALUE(_background)/255.0 blue: | |
6022 DW_BLUE_VALUE(_background)/255.0 alpha: 1] retain]; | |
6023 pthread_setspecific(_dw_bg_color_key, newcolor); | |
6024 } | |
6025 [oldcolor release]; | |
6026 DW_LOCAL_POOL_OUT; | |
6027 } | |
6028 | |
6029 /* Allows the user to choose a color using the system's color chooser dialog. | |
6030 * Parameters: | |
6031 * value: current color | |
6032 * Returns: | |
6033 * The selected color or the current color if cancelled. | |
6034 */ | |
6035 unsigned long API dw_color_choose(unsigned long value) | |
6036 { | |
6037 /* Create the Color Chooser Dialog class. */ | |
6038 DWColorChoose *colorDlg; | |
6039 DWDialog *dialog; | |
6040 DW_LOCAL_POOL_IN; | |
6041 | |
6042 if(![DWColorChoose sharedColorPanelExists]) | |
6043 { | |
6044 colorDlg = (DWColorChoose *)[DWColorChoose sharedColorPanel]; | |
6045 /* Set defaults for the dialog. */ | |
6046 [colorDlg setContinuous:NO]; | |
6047 [colorDlg setTarget:colorDlg]; | |
6048 [colorDlg setAction:@selector(changeColor:)]; | |
6049 } | |
6050 else | |
6051 colorDlg = (DWColorChoose *)[DWColorChoose sharedColorPanel]; | |
6052 | |
6053 /* If someone is already waiting just return */ | |
6054 if([colorDlg dialog]) | |
6055 { | |
6056 DW_LOCAL_POOL_OUT; | |
6057 return value; | |
6058 } | |
6059 | |
6060 unsigned long tempcol = _get_color(value); | |
6061 UIColor *color = [[UIColor colorWithDeviceRed: DW_RED_VALUE(tempcol)/255.0 green: DW_GREEN_VALUE(tempcol)/255.0 blue: DW_BLUE_VALUE(tempcol)/255.0 alpha: 1] retain]; | |
6062 [colorDlg setColor:color]; | |
6063 | |
6064 dialog = dw_dialog_new(colorDlg); | |
6065 [colorDlg setDialog:dialog]; | |
6066 [colorDlg makeKeyAndOrderFront:nil]; | |
6067 | |
6068 /* Wait for them to pick a color */ | |
6069 color = (UIColor *)dw_dialog_wait(dialog); | |
6070 | |
6071 /* Figure out the value of what they returned */ | |
6072 CGFloat red, green, blue; | |
6073 [color getRed:&red green:&green blue:&blue alpha:NULL]; | |
6074 value = DW_RGB((int)(red * 255), (int)(green *255), (int)(blue *255)); | |
6075 DW_LOCAL_POOL_OUT; | |
6076 return value; | |
6077 } | |
6078 | |
6079 CGContextRef _dw_draw_context(NSBitmapImageRep *image) | |
6080 { | |
6081 return [NSGraphicsContext graphicsContextWithCGContext:[[NSGraphicsContext graphicsContextWithBitmapImageRep:image] CGContext] flipped:YES]; | |
6082 } | |
6083 | |
6084 /* Draw a point on a window (preferably a render window). | |
6085 * Parameters: | |
6086 * handle: Handle to the window. | |
6087 * pixmap: Handle to the pixmap. (choose only one of these) | |
6088 * x: X coordinate. | |
6089 * y: Y coordinate. | |
6090 */ | |
6091 DW_FUNCTION_DEFINITION(dw_draw_point, void, HWND handle, HPIXMAP pixmap, int x, int y) | |
6092 DW_FUNCTION_ADD_PARAM4(handle, pixmap, x, y) | |
6093 DW_FUNCTION_NO_RETURN(dw_draw_point) | |
6094 DW_FUNCTION_RESTORE_PARAM4(handle, HWND, pixmap, HPIXMAP, x, int, y, int) | |
6095 { | |
6096 DW_FUNCTION_INIT; | |
6097 DW_LOCAL_POOL_IN; | |
6098 id image = handle; | |
6099 NSBitmapImageRep *bi = nil; | |
6100 bool bCanDraw = YES; | |
6101 | |
6102 if(pixmap) | |
6103 bi = image = (id)pixmap->image; | |
6104 else | |
6105 { | |
6106 if([image isMemberOfClass:[DWRender class]]) | |
6107 { | |
6108 DWRender *render = image; | |
6109 | |
6110 bi = [render cachedDrawingRep]; | |
6111 } | |
6112 } | |
6113 if(bi) | |
6114 { | |
6115 [NSGraphicsContext saveGraphicsState]; | |
6116 [NSGraphicsContext setCurrentContext:_dw_draw_context(bi)]; | |
6117 } | |
6118 if(bCanDraw == YES) | |
6119 { | |
6120 NSBezierPath* aPath = [NSBezierPath bezierPath]; | |
6121 [aPath setLineWidth: 0.5]; | |
6122 UIColor *color = pthread_getspecific(_dw_fg_color_key); | |
6123 [color set]; | |
6124 | |
6125 [aPath moveToPoint:NSMakePoint(x, y)]; | |
6126 [aPath stroke]; | |
6127 } | |
6128 if(bi) | |
6129 [NSGraphicsContext restoreGraphicsState]; | |
6130 DW_LOCAL_POOL_OUT; | |
6131 DW_FUNCTION_RETURN_NOTHING; | |
6132 } | |
6133 | |
6134 /* Draw a line on a window (preferably a render window). | |
6135 * Parameters: | |
6136 * handle: Handle to the window. | |
6137 * pixmap: Handle to the pixmap. (choose only one of these) | |
6138 * x1: First X coordinate. | |
6139 * y1: First Y coordinate. | |
6140 * x2: Second X coordinate. | |
6141 * y2: Second Y coordinate. | |
6142 */ | |
6143 DW_FUNCTION_DEFINITION(dw_draw_line, void, HWND handle, HPIXMAP pixmap, int x1, int y1, int x2, int y2) | |
6144 DW_FUNCTION_ADD_PARAM6(handle, pixmap, x1, y1, x2, y2) | |
6145 DW_FUNCTION_NO_RETURN(dw_draw_line) | |
6146 DW_FUNCTION_RESTORE_PARAM6(handle, HWND, pixmap, HPIXMAP, x1, int, y1, int, x2, int, y2, int) | |
6147 { | |
6148 DW_FUNCTION_INIT; | |
6149 DW_LOCAL_POOL_IN; | |
6150 id image = handle; | |
6151 NSBitmapImageRep *bi = nil; | |
6152 bool bCanDraw = YES; | |
6153 | |
6154 if(pixmap) | |
6155 bi = image = (id)pixmap->image; | |
6156 else | |
6157 { | |
6158 if([image isMemberOfClass:[DWRender class]]) | |
6159 { | |
6160 DWRender *render = image; | |
6161 | |
6162 bi = [render cachedDrawingRep]; | |
6163 } | |
6164 } | |
6165 if(bi) | |
6166 { | |
6167 [NSGraphicsContext saveGraphicsState]; | |
6168 [NSGraphicsContext setCurrentContext:_dw_draw_context(bi)]; | |
6169 } | |
6170 if(bCanDraw == YES) | |
6171 { | |
6172 NSBezierPath* aPath = [NSBezierPath bezierPath]; | |
6173 UIColor *color = pthread_getspecific(_dw_fg_color_key); | |
6174 [color set]; | |
6175 | |
6176 [aPath moveToPoint:NSMakePoint(x1 + 0.5, y1 + 0.5)]; | |
6177 [aPath lineToPoint:NSMakePoint(x2 + 0.5, y2 + 0.5)]; | |
6178 [aPath stroke]; | |
6179 } | |
6180 | |
6181 if(bi) | |
6182 [NSGraphicsContext restoreGraphicsState]; | |
6183 DW_LOCAL_POOL_OUT; | |
6184 DW_FUNCTION_RETURN_NOTHING; | |
6185 } | |
6186 | |
6187 /* Draw text on a window (preferably a render window). | |
6188 * Parameters: | |
6189 * handle: Handle to the window. | |
6190 * pixmap: Handle to the pixmap. (choose only one of these) | |
6191 * x: X coordinate. | |
6192 * y: Y coordinate. | |
6193 * text: Text to be displayed. | |
6194 */ | |
6195 DW_FUNCTION_DEFINITION(dw_draw_text, void, HWND handle, HPIXMAP pixmap, int x, int y, const char *text) | |
6196 DW_FUNCTION_ADD_PARAM5(handle, pixmap, x, y, text) | |
6197 DW_FUNCTION_NO_RETURN(dw_draw_text) | |
6198 DW_FUNCTION_RESTORE_PARAM5(handle, HWND, pixmap, HPIXMAP, x, int, y, int, text, const char *) | |
6199 { | |
6200 DW_FUNCTION_INIT; | |
6201 DW_LOCAL_POOL_IN; | |
6202 id image = handle; | |
6203 NSString *nstr = [ NSString stringWithUTF8String:text ]; | |
6204 NSBitmapImageRep *bi = nil; | |
6205 UIFont *font = nil; | |
6206 DWRender *render; | |
6207 bool bCanDraw = YES; | |
6208 | |
6209 if(pixmap) | |
6210 { | |
6211 bi = image = (id)pixmap->image; | |
6212 font = pixmap->font; | |
6213 render = pixmap->handle; | |
6214 if(!font && [render isMemberOfClass:[DWRender class]]) | |
6215 { | |
6216 font = [render font]; | |
6217 } | |
6218 image = (id)pixmap->image; | |
6219 } | |
6220 else if(image && [image isMemberOfClass:[DWRender class]]) | |
6221 { | |
6222 render = image; | |
6223 font = [render font]; | |
6224 bi = [render cachedDrawingRep]; | |
6225 } | |
6226 if(bi) | |
6227 { | |
6228 [NSGraphicsContext saveGraphicsState]; | |
6229 [NSGraphicsContext setCurrentContext:_dw_draw_context(bi)]; | |
6230 } | |
6231 | |
6232 if(bCanDraw == YES) | |
6233 { | |
6234 UIColor *fgcolor = pthread_getspecific(_dw_fg_color_key); | |
6235 UIColor *bgcolor = pthread_getspecific(_dw_bg_color_key); | |
6236 NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:fgcolor, NSForegroundColorAttributeName, nil]; | |
6237 if(bgcolor) | |
6238 [dict setValue:bgcolor forKey:NSBackgroundColorAttributeName]; | |
6239 if(font) | |
6240 [dict setValue:font forKey:UIFontAttributeName]; | |
6241 [nstr drawAtPoint:NSMakePoint(x, y) withAttributes:dict]; | |
6242 [dict release]; | |
6243 } | |
6244 | |
6245 if(bi) | |
6246 [NSGraphicsContext restoreGraphicsState]; | |
6247 DW_LOCAL_POOL_OUT; | |
6248 DW_FUNCTION_RETURN_NOTHING; | |
6249 } | |
6250 | |
6251 /* Query the width and height of a text string. | |
6252 * Parameters: | |
6253 * handle: Handle to the window. | |
6254 * pixmap: Handle to the pixmap. (choose only one of these) | |
6255 * text: Text to be queried. | |
6256 * width: Pointer to a variable to be filled in with the width. | |
6257 * height Pointer to a variable to be filled in with the height. | |
6258 */ | |
6259 void API dw_font_text_extents_get(HWND handle, HPIXMAP pixmap, const char *text, int *width, int *height) | |
6260 { | |
6261 id object = handle; | |
6262 NSString *nstr; | |
6263 UIFont *font = nil; | |
6264 DW_LOCAL_POOL_IN; | |
6265 | |
6266 nstr = [NSString stringWithUTF8String:text]; | |
6267 | |
6268 /* Check the pixmap for associated object or font */ | |
6269 if(pixmap) | |
6270 { | |
6271 object = pixmap->handle; | |
6272 font = pixmap->font; | |
6273 } | |
6274 NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; | |
6275 /* If we didn't get a font from the pixmap... try the associated object */ | |
6276 if(!font && ([object isMemberOfClass:[DWRender class]] || [object isKindOfClass:[UIControl class]])) | |
6277 { | |
6278 font = [object font]; | |
6279 } | |
6280 /* If we got a font... add it to the dictionary */ | |
6281 if(font) | |
6282 { | |
6283 [dict setValue:font forKey:UIFontAttributeName]; | |
6284 } | |
6285 /* Calculate the size of the string */ | |
6286 NSSize size = [nstr sizeWithAttributes:dict]; | |
6287 [dict release]; | |
6288 /* Return whatever information we can */ | |
6289 if(width) | |
6290 { | |
6291 *width = size.width; | |
6292 } | |
6293 if(height) | |
6294 { | |
6295 *height = size.height; | |
6296 } | |
6297 DW_LOCAL_POOL_OUT; | |
6298 } | |
6299 | |
6300 /* Internal function to create an image graphics context... | |
6301 * with or without antialiasing enabled. | |
6302 */ | |
6303 id _create_gc(id image, bool antialiased) | |
6304 { | |
6305 CGContextRef context = (CGContextRef)[[NSGraphicsContext graphicsContextWithBitmapImageRep:image] CGContext]; | |
6306 NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithCGContext:context flipped:YES]; | |
6307 [gc setShouldAntialias:antialiased]; | |
6308 CGContextSetAllowsAntialiasing(context, antialiased); | |
6309 return gc; | |
6310 } | |
6311 | |
6312 /* Draw a polygon on a window (preferably a render window). | |
6313 * Parameters: | |
6314 * handle: Handle to the window. | |
6315 * pixmap: Handle to the pixmap. (choose only one of these) | |
6316 * flags: DW_DRAW_FILL (1) to fill the polygon or DW_DRAW_DEFAULT (0). | |
6317 * x: X coordinate. | |
6318 * y: Y coordinate. | |
6319 * width: Width of rectangle. | |
6320 * height: Height of rectangle. | |
6321 */ | |
6322 DW_FUNCTION_DEFINITION(dw_draw_polygon, void, HWND handle, HPIXMAP pixmap, int flags, int npoints, int *x, int *y) | |
6323 DW_FUNCTION_ADD_PARAM6(handle, pixmap, flags, npoints, x, y) | |
6324 DW_FUNCTION_NO_RETURN(dw_draw_polygon) | |
6325 DW_FUNCTION_RESTORE_PARAM6(handle, HWND, pixmap, HPIXMAP, flags, int, npoints, int, x, int *, y, int *) | |
6326 { | |
6327 DW_FUNCTION_INIT; | |
6328 DW_LOCAL_POOL_IN; | |
6329 id image = handle; | |
6330 NSBitmapImageRep *bi = nil; | |
6331 bool bCanDraw = YES; | |
6332 int z; | |
6333 | |
6334 if(pixmap) | |
6335 bi = image = (id)pixmap->image; | |
6336 else | |
6337 { | |
6338 if([image isMemberOfClass:[DWRender class]]) | |
6339 { | |
6340 DWRender *render = image; | |
6341 | |
6342 bi = [render cachedDrawingRep]; | |
6343 } | |
6344 } | |
6345 if(bi) | |
6346 { | |
6347 id gc = _create_gc(bi, flags & DW_DRAW_NOAA ? NO : YES); | |
6348 [NSGraphicsContext saveGraphicsState]; | |
6349 [NSGraphicsContext setCurrentContext:gc]; | |
6350 } | |
6351 | |
6352 if(bCanDraw == YES) | |
6353 { | |
6354 NSBezierPath* aPath = [NSBezierPath bezierPath]; | |
6355 UIColor *color = pthread_getspecific(_dw_fg_color_key); | |
6356 [color set]; | |
6357 | |
6358 [aPath moveToPoint:NSMakePoint(*x + 0.5, *y + 0.5)]; | |
6359 for(z=1;z<npoints;z++) | |
6360 { | |
6361 [aPath lineToPoint:NSMakePoint(x[z] + 0.5, y[z] + 0.5)]; | |
6362 } | |
6363 [aPath closePath]; | |
6364 if(flags & DW_DRAW_FILL) | |
6365 { | |
6366 [aPath fill]; | |
6367 } | |
6368 [aPath stroke]; | |
6369 } | |
6370 | |
6371 if(bi) | |
6372 [NSGraphicsContext restoreGraphicsState]; | |
6373 DW_LOCAL_POOL_OUT; | |
6374 DW_FUNCTION_RETURN_NOTHING; | |
6375 } | |
6376 | |
6377 /* Draw a rectangle on a window (preferably a render window). | |
6378 * Parameters: | |
6379 * handle: Handle to the window. | |
6380 * pixmap: Handle to the pixmap. (choose only one of these) | |
6381 * flags: DW_DRAW_FILL (1) to fill the box or DW_DRAW_DEFAULT (0). | |
6382 * x: X coordinate. | |
6383 * y: Y coordinate. | |
6384 * width: Width of rectangle. | |
6385 * height: Height of rectangle. | |
6386 */ | |
6387 DW_FUNCTION_DEFINITION(dw_draw_rect, void, HWND handle, HPIXMAP pixmap, int flags, int x, int y, int width, int height) | |
6388 DW_FUNCTION_ADD_PARAM7(handle, pixmap, flags, x, y, width, height) | |
6389 DW_FUNCTION_NO_RETURN(dw_draw_rect) | |
6390 DW_FUNCTION_RESTORE_PARAM7(handle, HWND, pixmap, HPIXMAP, flags, int, x, int, y, int, width, int, height, int) | |
6391 { | |
6392 DW_FUNCTION_INIT; | |
6393 DW_LOCAL_POOL_IN; | |
6394 id image = handle; | |
6395 NSBitmapImageRep *bi = nil; | |
6396 bool bCanDraw = YES; | |
6397 | |
6398 if(pixmap) | |
6399 bi = image = (id)pixmap->image; | |
6400 else | |
6401 { | |
6402 if([image isMemberOfClass:[DWRender class]]) | |
6403 { | |
6404 DWRender *render = image; | |
6405 | |
6406 bi = [render cachedDrawingRep]; | |
6407 } | |
6408 } | |
6409 if(bi) | |
6410 { | |
6411 id gc = _create_gc(bi, flags & DW_DRAW_NOAA ? NO : YES); | |
6412 [NSGraphicsContext saveGraphicsState]; | |
6413 [NSGraphicsContext setCurrentContext:gc]; | |
6414 } | |
6415 | |
6416 if(bCanDraw == YES) | |
6417 { | |
6418 UIColor *color = pthread_getspecific(_dw_fg_color_key); | |
6419 [color set]; | |
6420 | |
6421 if(flags & DW_DRAW_FILL) | |
6422 [NSBezierPath fillRect:NSMakeRect(x, y, width, height)]; | |
6423 else | |
6424 [NSBezierPath strokeRect:NSMakeRect(x, y, width, height)]; | |
6425 } | |
6426 | |
6427 if(bi) | |
6428 [NSGraphicsContext restoreGraphicsState]; | |
6429 DW_LOCAL_POOL_OUT; | |
6430 DW_FUNCTION_RETURN_NOTHING; | |
6431 } | |
6432 | |
6433 /* Draw an arc on a window (preferably a render window). | |
6434 * Parameters: | |
6435 * handle: Handle to the window. | |
6436 * pixmap: Handle to the pixmap. (choose only one of these) | |
6437 * flags: DW_DRAW_FILL (1) to fill the arc or DW_DRAW_DEFAULT (0). | |
6438 * DW_DRAW_FULL will draw a complete circle/elipse. | |
6439 * xorigin: X coordinate of center of arc. | |
6440 * yorigin: Y coordinate of center of arc. | |
6441 * x1: X coordinate of first segment of arc. | |
6442 * y1: Y coordinate of first segment of arc. | |
6443 * x2: X coordinate of second segment of arc. | |
6444 * y2: Y coordinate of second segment of arc. | |
6445 */ | |
6446 DW_FUNCTION_DEFINITION(dw_draw_arc, void, HWND handle, HPIXMAP pixmap, int flags, int xorigin, int yorigin, int x1, int y1, int x2, int y2) | |
6447 DW_FUNCTION_ADD_PARAM9(handle, pixmap, flags, xorigin, yorigin, x1, y1, x2, y2) | |
6448 DW_FUNCTION_NO_RETURN(dw_draw_arc) | |
6449 DW_FUNCTION_RESTORE_PARAM9(handle, HWND, pixmap, HPIXMAP, flags, int, xorigin, int, yorigin, int, x1, int, y1, int, x2, int, y2, int) | |
6450 { | |
6451 DW_FUNCTION_INIT; | |
6452 DW_LOCAL_POOL_IN; | |
6453 id image = handle; | |
6454 NSBitmapImageRep *bi = nil; | |
6455 bool bCanDraw = YES; | |
6456 | |
6457 if(pixmap) | |
6458 bi = image = (id)pixmap->image; | |
6459 else | |
6460 { | |
6461 if([image isMemberOfClass:[DWRender class]]) | |
6462 { | |
6463 DWRender *render = image; | |
6464 | |
6465 bi = [render cachedDrawingRep]; | |
6466 } | |
6467 } | |
6468 if(bi) | |
6469 { | |
6470 id gc = _create_gc(bi, flags & DW_DRAW_NOAA ? NO : YES); | |
6471 [NSGraphicsContext saveGraphicsState]; | |
6472 [NSGraphicsContext setCurrentContext:gc]; | |
6473 } | |
6474 | |
6475 if(bCanDraw) | |
6476 { | |
6477 NSBezierPath* aPath = [NSBezierPath bezierPath]; | |
6478 UIColor *color = pthread_getspecific(_dw_fg_color_key); | |
6479 [color set]; | |
6480 | |
6481 /* Special case of a full circle/oval */ | |
6482 if(flags & DW_DRAW_FULL) | |
6483 { | |
6484 [aPath appendBezierPathWithOvalInRect:NSMakeRect(x1, y1, x2 - x1, y2 - y1)]; | |
6485 } | |
6486 else | |
6487 { | |
6488 double a1 = atan2((y1-yorigin), (x1-xorigin)); | |
6489 double a2 = atan2((y2-yorigin), (x2-xorigin)); | |
6490 double dx = xorigin - x1; | |
6491 double dy = yorigin - y1; | |
6492 double r = sqrt(dx*dx + dy*dy); | |
6493 | |
6494 /* Convert to degrees */ | |
6495 a1 *= (180.0 / M_PI); | |
6496 a2 *= (180.0 / M_PI); | |
6497 | |
6498 /* Prepare to draw */ | |
6499 [aPath appendBezierPathWithArcWithCenter:NSMakePoint(xorigin, yorigin) | |
6500 radius:r startAngle:a1 endAngle:a2]; | |
6501 } | |
6502 /* If the fill flag is passed */ | |
6503 if(flags & DW_DRAW_FILL) | |
6504 { | |
6505 [aPath fill]; | |
6506 } | |
6507 /* Actually do the drawing */ | |
6508 [aPath stroke]; | |
6509 } | |
6510 | |
6511 if(bi) | |
6512 [NSGraphicsContext restoreGraphicsState]; | |
6513 DW_LOCAL_POOL_OUT; | |
6514 DW_FUNCTION_RETURN_NOTHING; | |
6515 } | |
6516 | |
6517 /* | |
6518 * Create a tree object to be packed. | |
6519 * Parameters: | |
6520 * id: An ID to be used for getting the resource from the | |
6521 * resource file. | |
6522 */ | |
6523 DW_FUNCTION_DEFINITION(dw_tree_new, HWND, ULONG cid) | |
6524 DW_FUNCTION_ADD_PARAM1(cid) | |
6525 DW_FUNCTION_RETURN(dw_tree_new, HWND) | |
6526 DW_FUNCTION_RESTORE_PARAM1(cid, ULONG) | |
6527 { | |
6528 DW_FUNCTION_INIT; | |
6529 UIScrollView *scrollview = [[UIScrollView alloc] init]; | |
6530 DWTree *tree = [[DWTree alloc] init]; | |
6531 | |
6532 [tree setScrollview:scrollview]; | |
6533 [scrollview setBorderType:NSBezelBorder]; | |
6534 [scrollview setHasVerticalScroller:YES]; | |
6535 [scrollview setAutohidesScrollers:YES]; | |
6536 | |
6537 [tree setAllowsMultipleSelection:NO]; | |
6538 [tree setDataSource:tree]; | |
6539 [tree setDelegate:tree]; | |
6540 [scrollview setDocumentView:tree]; | |
6541 [tree setHeaderView:nil]; | |
6542 [tree setTag:cid]; | |
6543 [tree autorelease]; | |
6544 DW_FUNCTION_RETURN_THIS(tree); | |
6545 } | |
6546 | |
6547 /* | |
6548 * Inserts an item into a tree window (widget) after another item. | |
6549 * Parameters: | |
6550 * handle: Handle to the tree to be inserted. | |
6551 * item: Handle to the item to be positioned after. | |
6552 * title: The text title of the entry. | |
6553 * icon: Handle to coresponding icon. | |
6554 * parent: Parent handle or 0 if root. | |
6555 * itemdata: Item specific data. | |
6556 */ | |
6557 DW_FUNCTION_DEFINITION(dw_tree_insert_after, HTREEITEM, HWND handle, HTREEITEM item, const char *title, HICN icon, HTREEITEM parent, void *itemdata) | |
6558 DW_FUNCTION_ADD_PARAM6(handle, item, title, icon, parent, itemdata) | |
6559 DW_FUNCTION_RETURN(dw_tree_insert_after, HTREEITEM) | |
6560 DW_FUNCTION_RESTORE_PARAM6(handle, HWND, item, HTREEITEM, title, char *, icon, HICN, parent, HTREEITEM, itemdata, void *) | |
6561 { | |
6562 DW_FUNCTION_INIT; | |
6563 DWTree *tree = handle; | |
6564 NSString *nstr = [[NSString stringWithUTF8String:title] retain]; | |
6565 NSMutableArray *treenode = [[[NSMutableArray alloc] init] retain]; | |
6566 if(icon) | |
6567 [treenode addObject:icon]; | |
6568 else | |
6569 [treenode addObject:[NSNull null]]; | |
6570 [treenode addObject:nstr]; | |
6571 [treenode addObject:[NSValue valueWithPointer:itemdata]]; | |
6572 [treenode addObject:[NSNull null]]; | |
6573 [tree addTree:treenode and:parent after:item]; | |
6574 if(parent) | |
6575 [tree reloadItem:parent reloadChildren:YES]; | |
6576 else | |
6577 [tree reloadData]; | |
6578 DW_FUNCTION_RETURN_THIS(treenode); | |
6579 } | |
6580 | |
6581 /* | |
6582 * Inserts an item into a tree window (widget). | |
6583 * Parameters: | |
6584 * handle: Handle to the tree to be inserted. | |
6585 * title: The text title of the entry. | |
6586 * icon: Handle to coresponding icon. | |
6587 * parent: Parent handle or 0 if root. | |
6588 * itemdata: Item specific data. | |
6589 */ | |
6590 HTREEITEM API dw_tree_insert(HWND handle, const char *title, HICN icon, HTREEITEM parent, void *itemdata) | |
6591 { | |
6592 return dw_tree_insert_after(handle, NULL, title, icon, parent, itemdata); | |
6593 } | |
6594 | |
6595 /* | |
6596 * Gets the text an item in a tree window (widget). | |
6597 * Parameters: | |
6598 * handle: Handle to the tree containing the item. | |
6599 * item: Handle of the item to be modified. | |
6600 */ | |
6601 DW_FUNCTION_DEFINITION(dw_tree_get_title, char *, HWND handle, HTREEITEM item) | |
6602 DW_FUNCTION_ADD_PARAM2(handle, item) | |
6603 DW_FUNCTION_RETURN(dw_tree_get_title, char *) | |
6604 DW_FUNCTION_RESTORE_PARAM2(DW_UNUSED(handle), HWND, item, HTREEITEM) | |
6605 { | |
6606 DW_FUNCTION_INIT; | |
6607 char *retval = NULL; | |
6608 NSMutableArray *array = (NSMutableArray *)item; | |
6609 NSString *nstr = (NSString *)[array objectAtIndex:1]; | |
6610 retval = strdup([nstr UTF8String]); | |
6611 DW_FUNCTION_RETURN_THIS(retval); | |
6612 } | |
6613 | |
6614 /* | |
6615 * Gets the text an item in a tree window (widget). | |
6616 * Parameters: | |
6617 * handle: Handle to the tree containing the item. | |
6618 * item: Handle of the item to be modified. | |
6619 */ | |
6620 DW_FUNCTION_DEFINITION(dw_tree_get_parent, HTREEITEM, HWND handle, HTREEITEM item) | |
6621 DW_FUNCTION_ADD_PARAM2(handle, item) | |
6622 DW_FUNCTION_RETURN(dw_tree_get_parent, HTREEITEM) | |
6623 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, item, HTREEITEM) | |
6624 { | |
6625 DW_FUNCTION_INIT; | |
6626 HTREEITEM parent; | |
6627 DWTree *tree = handle; | |
6628 | |
6629 parent = [tree parentForItem:item]; | |
6630 DW_FUNCTION_RETURN_THIS(parent); | |
6631 } | |
6632 | |
6633 /* | |
6634 * Sets the text and icon of an item in a tree window (widget). | |
6635 * Parameters: | |
6636 * handle: Handle to the tree containing the item. | |
6637 * item: Handle of the item to be modified. | |
6638 * title: The text title of the entry. | |
6639 * icon: Handle to coresponding icon. | |
6640 */ | |
6641 DW_FUNCTION_DEFINITION(dw_tree_item_change, void, HWND handle, HTREEITEM item, const char *title, HICN icon) | |
6642 DW_FUNCTION_ADD_PARAM4(handle, item, title, icon) | |
6643 DW_FUNCTION_NO_RETURN(dw_tree_item_change) | |
6644 DW_FUNCTION_RESTORE_PARAM4(handle, HWND, item, HTREEITEM, title, char *, icon, HICN) | |
6645 { | |
6646 DW_FUNCTION_INIT; | |
6647 DWTree *tree = handle; | |
6648 NSMutableArray *array = (NSMutableArray *)item; | |
6649 DW_LOCAL_POOL_IN; | |
6650 | |
6651 if(title) | |
6652 { | |
6653 NSString *oldstr = [array objectAtIndex:1]; | |
6654 NSString *nstr = [[NSString stringWithUTF8String:title] retain]; | |
6655 [array replaceObjectAtIndex:1 withObject:nstr]; | |
6656 [oldstr release]; | |
6657 } | |
6658 if(icon) | |
6659 { | |
6660 [array replaceObjectAtIndex:0 withObject:icon]; | |
6661 } | |
6662 NSInteger row = [tree rowForItem:item]; | |
6663 [tree reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:row] | |
6664 columnIndexes:[NSIndexSet indexSetWithIndex:0]]; | |
6665 DW_LOCAL_POOL_OUT; | |
6666 DW_FUNCTION_RETURN_NOTHING; | |
6667 } | |
6668 | |
6669 /* | |
6670 * Sets the item data of a tree item. | |
6671 * Parameters: | |
6672 * handle: Handle to the tree containing the item. | |
6673 * item: Handle of the item to be modified. | |
6674 * itemdata: User defined data to be associated with item. | |
6675 */ | |
6676 DW_FUNCTION_DEFINITION(dw_tree_item_set_data, void, HWND handle, HTREEITEM item, void *itemdata) | |
6677 DW_FUNCTION_ADD_PARAM3(handle, item, itemdata) | |
6678 DW_FUNCTION_NO_RETURN(dw_tree_item_set_data) | |
6679 DW_FUNCTION_RESTORE_PARAM3(DW_UNUSED(handle), HWND, item, HTREEITEM, itemdata, void *) | |
6680 { | |
6681 DW_FUNCTION_INIT; | |
6682 NSMutableArray *array = (NSMutableArray *)item; | |
6683 [array replaceObjectAtIndex:2 withObject:[NSValue valueWithPointer:itemdata]]; | |
6684 DW_FUNCTION_RETURN_NOTHING; | |
6685 } | |
6686 | |
6687 /* | |
6688 * Gets the item data of a tree item. | |
6689 * Parameters: | |
6690 * handle: Handle to the tree containing the item. | |
6691 * item: Handle of the item to be modified. | |
6692 */ | |
6693 DW_FUNCTION_DEFINITION(dw_tree_item_get_data, void *, HWND handle, HTREEITEM item) | |
6694 DW_FUNCTION_ADD_PARAM2(handle, item) | |
6695 DW_FUNCTION_RETURN(dw_tree_item_get_data, void *) | |
6696 DW_FUNCTION_RESTORE_PARAM2(DW_UNUSED(handle), HWND, item, HTREEITEM) | |
6697 { | |
6698 DW_FUNCTION_INIT; | |
6699 void *result = NULL; | |
6700 NSMutableArray *array = (NSMutableArray *)item; | |
6701 NSValue *value = [array objectAtIndex:2]; | |
6702 if(value) | |
6703 result = [value pointerValue]; | |
6704 DW_FUNCTION_RETURN_THIS(result); | |
6705 } | |
6706 | |
6707 /* | |
6708 * Sets this item as the active selection. | |
6709 * Parameters: | |
6710 * handle: Handle to the tree window (widget) to be selected. | |
6711 * item: Handle to the item to be selected. | |
6712 */ | |
6713 DW_FUNCTION_DEFINITION(dw_tree_item_select, void, HWND handle, HTREEITEM item) | |
6714 DW_FUNCTION_ADD_PARAM2(handle, item) | |
6715 DW_FUNCTION_NO_RETURN(dw_tree_item_select) | |
6716 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, item, HTREEITEM) | |
6717 { | |
6718 DW_FUNCTION_INIT; | |
6719 DWTree *tree = handle; | |
6720 NSInteger itemIndex = [tree rowForItem:item]; | |
6721 if(itemIndex > -1) | |
6722 { | |
6723 [tree selectRowIndexes:[NSIndexSet indexSetWithIndex:itemIndex] byExtendingSelection:NO]; | |
6724 } | |
6725 DW_FUNCTION_RETURN_NOTHING; | |
6726 } | |
6727 | |
6728 /* | |
6729 * Removes all nodes from a tree. | |
6730 * Parameters: | |
6731 * handle: Handle to the window (widget) to be cleared. | |
6732 */ | |
6733 DW_FUNCTION_DEFINITION(dw_tree_clear, void, HWND handle) | |
6734 DW_FUNCTION_ADD_PARAM1(handle) | |
6735 DW_FUNCTION_NO_RETURN(dw_tree_clear) | |
6736 DW_FUNCTION_RESTORE_PARAM1(handle, HWND) | |
6737 { | |
6738 DW_FUNCTION_INIT; | |
6739 DWTree *tree = handle; | |
6740 [tree clear]; | |
6741 DW_FUNCTION_RETURN_NOTHING; | |
6742 } | |
6743 | |
6744 /* | |
6745 * Expands a node on a tree. | |
6746 * Parameters: | |
6747 * handle: Handle to the tree window (widget). | |
6748 * item: Handle to node to be expanded. | |
6749 */ | |
6750 DW_FUNCTION_DEFINITION(dw_tree_item_expand, void, HWND handle, HTREEITEM item) | |
6751 DW_FUNCTION_ADD_PARAM2(handle, item) | |
6752 DW_FUNCTION_NO_RETURN(dw_tree_item_expand) | |
6753 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, item, HTREEITEM) | |
6754 { | |
6755 DW_FUNCTION_INIT; | |
6756 DWTree *tree = handle; | |
6757 [tree expandItem:item]; | |
6758 DW_FUNCTION_RETURN_NOTHING; | |
6759 } | |
6760 | |
6761 /* | |
6762 * Collapses a node on a tree. | |
6763 * Parameters: | |
6764 * handle: Handle to the tree window (widget). | |
6765 * item: Handle to node to be collapsed. | |
6766 */ | |
6767 DW_FUNCTION_DEFINITION(dw_tree_item_collapse, void, HWND handle, HTREEITEM item) | |
6768 DW_FUNCTION_ADD_PARAM2(handle, item) | |
6769 DW_FUNCTION_NO_RETURN(dw_tree_item_collapse) | |
6770 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, item, HTREEITEM) | |
6771 { | |
6772 DW_FUNCTION_INIT; | |
6773 DWTree *tree = handle; | |
6774 [tree collapseItem:item]; | |
6775 DW_FUNCTION_RETURN_NOTHING; | |
6776 } | |
6777 | |
6778 /* | |
6779 * Removes a node from a tree. | |
6780 * Parameters: | |
6781 * handle: Handle to the window (widget) to be cleared. | |
6782 * item: Handle to node to be deleted. | |
6783 */ | |
6784 DW_FUNCTION_DEFINITION(dw_tree_item_delete, void, HWND handle, HTREEITEM item) | |
6785 DW_FUNCTION_ADD_PARAM2(handle, item) | |
6786 DW_FUNCTION_NO_RETURN(dw_tree_item_delete) | |
6787 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, item, HTREEITEM) | |
6788 { | |
6789 DW_FUNCTION_INIT; | |
6790 DWTree *tree = handle; | |
6791 [tree deleteNode:item]; | |
6792 [tree reloadData]; | |
6793 DW_FUNCTION_RETURN_NOTHING; | |
6794 } | |
6795 | |
6796 /* | |
6797 * Create a container object to be packed. | |
6798 * Parameters: | |
6799 * id: An ID to be used for getting the resource from the | |
6800 * resource file. | |
6801 */ | |
6802 DW_FUNCTION_DEFINITION(dw_container_new, HWND, ULONG cid, int multi) | |
6803 DW_FUNCTION_ADD_PARAM2(cid, multi) | |
6804 DW_FUNCTION_RETURN(dw_container_new, HWND) | |
6805 DW_FUNCTION_RESTORE_PARAM2(cid, ULONG, multi, int) | |
6806 { | |
6807 DW_FUNCTION_INIT; | |
6808 DWContainer *cont = _dw_cont_new(cid, multi); | |
6809 UIScrollView *scrollview = [cont scrollview]; | |
6810 [scrollview setHasHorizontalScroller:YES]; | |
6811 NSTableHeaderView *header = [[[NSTableHeaderView alloc] init] autorelease]; | |
6812 [cont setHeaderView:header]; | |
6813 [cont setTarget:cont]; | |
6814 [cont setDoubleAction:@selector(doubleClicked:)]; | |
6815 DW_FUNCTION_RETURN_THIS(cont); | |
6816 } | |
6817 | |
6818 /* | |
6819 * Sets up the container columns. | |
6820 * Parameters: | |
6821 * handle: Handle to the container to be configured. | |
6822 * flags: An array of unsigned longs with column flags. | |
6823 * titles: An array of strings with column text titles. | |
6824 * count: The number of columns (this should match the arrays). | |
6825 * separator: The column number that contains the main separator. | |
6826 * (this item may only be used in OS/2) | |
6827 */ | |
6828 DW_FUNCTION_DEFINITION(dw_container_setup, int, HWND handle, unsigned long *flags, char **titles, int count, int separator) | |
6829 DW_FUNCTION_ADD_PARAM5(handle, flags, titles, count, separator) | |
6830 DW_FUNCTION_RETURN(dw_container_setup, int) | |
6831 DW_FUNCTION_RESTORE_PARAM5(handle, HWND, flags, unsigned long *, titles, char **, count, int, DW_UNUSED(separator), int) | |
6832 { | |
6833 DW_FUNCTION_INIT; | |
6834 int z, retval = DW_ERROR_NONE; | |
6835 DWContainer *cont = handle; | |
6836 | |
6837 [cont setup]; | |
6838 | |
6839 for(z=0;z<count;z++) | |
6840 { | |
6841 NSString *title = [NSString stringWithUTF8String:titles[z]]; | |
6842 NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:title]; | |
6843 [column setTitle:title]; | |
6844 /* Defaults to left justified so just handle right and center */ | |
6845 if(flags[z] & DW_CFA_RIGHT) | |
6846 [(NSCell *)[column headerCell] setAlignment:DWTextAlignmentRight]; | |
6847 else if(flags[z] & DW_CFA_CENTER) | |
6848 [(NSCell *)[column headerCell] setAlignment:DWTextAlignmentCenter]; | |
6849 [column setEditable:NO]; | |
6850 [cont addTableColumn:column]; | |
6851 [cont addColumn:column andType:(int)flags[z]]; | |
6852 [column release]; | |
6853 } | |
6854 DW_FUNCTION_RETURN_THIS(retval); | |
6855 } | |
6856 | |
6857 /* | |
6858 * Configures the main filesystem columnn title for localization. | |
6859 * Parameters: | |
6860 * handle: Handle to the container to be configured. | |
6861 * title: The title to be displayed in the main column. | |
6862 */ | |
6863 void API dw_filesystem_set_column_title(HWND handle, const char *title) | |
6864 { | |
6865 char *newtitle = strdup(title ? title : ""); | |
6866 | |
6867 dw_window_set_data(handle, "_dw_coltitle", newtitle); | |
6868 } | |
6869 | |
6870 /* | |
6871 * Sets up the filesystem columns, note: filesystem always has an icon/filename field. | |
6872 * Parameters: | |
6873 * handle: Handle to the container to be configured. | |
6874 * flags: An array of unsigned longs with column flags. | |
6875 * titles: An array of strings with column text titles. | |
6876 * count: The number of columns (this should match the arrays). | |
6877 */ | |
6878 int API dw_filesystem_setup(HWND handle, unsigned long *flags, char **titles, int count) | |
6879 { | |
6880 char **newtitles = malloc(sizeof(char *) * (count + 1)); | |
6881 unsigned long *newflags = malloc(sizeof(unsigned long) * (count + 1)); | |
6882 char *coltitle = (char *)dw_window_get_data(handle, "_dw_coltitle"); | |
6883 DWContainer *cont = handle; | |
6884 | |
6885 newtitles[0] = coltitle ? coltitle : "Filename"; | |
6886 | |
6887 newflags[0] = DW_CFA_STRINGANDICON | DW_CFA_LEFT | DW_CFA_HORZSEPARATOR; | |
6888 | |
6889 memcpy(&newtitles[1], titles, sizeof(char *) * count); | |
6890 memcpy(&newflags[1], flags, sizeof(unsigned long) * count); | |
6891 | |
6892 dw_container_setup(handle, newflags, newtitles, count + 1, 0); | |
6893 [cont setFilesystem:YES]; | |
6894 | |
6895 if(coltitle) | |
6896 { | |
6897 dw_window_set_data(handle, "_dw_coltitle", NULL); | |
6898 free(coltitle); | |
6899 } | |
6900 free(newtitles); | |
6901 free(newflags); | |
6902 return DW_ERROR_NONE; | |
6903 } | |
6904 | |
6905 /* | |
6906 * Allocates memory used to populate a container. | |
6907 * Parameters: | |
6908 * handle: Handle to the container window (widget). | |
6909 * rowcount: The number of items to be populated. | |
6910 */ | |
6911 DW_FUNCTION_DEFINITION(dw_container_alloc, void *, HWND handle, int rowcount) | |
6912 DW_FUNCTION_ADD_PARAM2(handle, rowcount) | |
6913 DW_FUNCTION_RETURN(dw_container_alloc, void *) | |
6914 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, rowcount, int) | |
6915 { | |
6916 DW_FUNCTION_INIT; | |
6917 DWContainer *cont = handle; | |
6918 [cont addRows:rowcount]; | |
6919 DW_FUNCTION_RETURN_THIS(cont); | |
6920 } | |
6921 | |
6922 /* | |
6923 * Sets an item in specified row and column to the given data. | |
6924 * Parameters: | |
6925 * handle: Handle to the container window (widget). | |
6926 * pointer: Pointer to the allocated memory in dw_container_alloc(). | |
6927 * column: Zero based column of data being set. | |
6928 * row: Zero based row of data being set. | |
6929 * data: Pointer to the data to be added. | |
6930 */ | |
6931 DW_FUNCTION_DEFINITION(dw_container_set_item, void, HWND handle, void *pointer, int column, int row, void *data) | |
6932 DW_FUNCTION_ADD_PARAM5(handle, pointer, column, row, data) | |
6933 DW_FUNCTION_NO_RETURN(dw_container_set_item) | |
6934 DW_FUNCTION_RESTORE_PARAM5(handle, HWND, pointer, void *, column, int, row, int, data, void *) | |
6935 { | |
6936 DW_FUNCTION_INIT; | |
6937 DWContainer *cont = handle; | |
6938 id icon = nil, text = nil; | |
6939 int type = [cont cellType:column]; | |
6940 int lastadd = 0; | |
6941 | |
6942 /* If pointer is NULL we are getting a change request instead of set */ | |
6943 if(pointer) | |
6944 lastadd = [cont lastAddPoint]; | |
6945 | |
6946 if(data) | |
6947 { | |
6948 if(type & DW_CFA_BITMAPORICON) | |
6949 { | |
6950 icon = *((UIImage **)data); | |
6951 } | |
6952 else if(type & DW_CFA_STRING) | |
6953 { | |
6954 char *str = *((char **)data); | |
6955 text = [ NSString stringWithUTF8String:str ]; | |
6956 } | |
6957 else | |
6958 { | |
6959 char textbuffer[101] = {0}; | |
6960 | |
6961 if(type & DW_CFA_ULONG) | |
6962 { | |
6963 ULONG tmp = *((ULONG *)data); | |
6964 | |
6965 snprintf(textbuffer, 100, "%lu", tmp); | |
6966 } | |
6967 else if(type & DW_CFA_DATE) | |
6968 { | |
6969 struct tm curtm; | |
6970 CDATE cdate = *((CDATE *)data); | |
6971 | |
6972 memset( &curtm, 0, sizeof(curtm) ); | |
6973 curtm.tm_mday = cdate.day; | |
6974 curtm.tm_mon = cdate.month - 1; | |
6975 curtm.tm_year = cdate.year - 1900; | |
6976 | |
6977 strftime(textbuffer, 100, "%x", &curtm); | |
6978 } | |
6979 else if(type & DW_CFA_TIME) | |
6980 { | |
6981 struct tm curtm; | |
6982 CTIME ctime = *((CTIME *)data); | |
6983 | |
6984 memset( &curtm, 0, sizeof(curtm) ); | |
6985 curtm.tm_hour = ctime.hours; | |
6986 curtm.tm_min = ctime.minutes; | |
6987 curtm.tm_sec = ctime.seconds; | |
6988 | |
6989 strftime(textbuffer, 100, "%X", &curtm); | |
6990 } | |
6991 if(textbuffer[0]) | |
6992 text = [ NSString stringWithUTF8String:textbuffer ]; | |
6993 } | |
6994 } | |
6995 | |
6996 id object = [cont getRow:(row+lastadd) and:column]; | |
6997 | |
6998 /* If it is a cell, change the content of the cell */ | |
6999 if([object isMemberOfClass:[NSTableCellView class]]) | |
7000 { | |
7001 NSTableCellView *cell = object; | |
7002 if(icon) | |
7003 [[cell imageView] setImage:icon]; | |
7004 else | |
7005 [[cell textField] setStringValue:text]; | |
7006 } | |
7007 else /* Otherwise replace it with a new cell */ | |
7008 [cont editCell:_dw_table_cell_view_new(icon, text) at:(row+lastadd) and:column]; | |
7009 [cont setNeedsDisplay:YES]; | |
7010 DW_FUNCTION_RETURN_NOTHING; | |
7011 } | |
7012 | |
7013 /* | |
7014 * Changes an existing item in specified row and column to the given data. | |
7015 * Parameters: | |
7016 * handle: Handle to the container window (widget). | |
7017 * column: Zero based column of data being set. | |
7018 * row: Zero based row of data being set. | |
7019 * data: Pointer to the data to be added. | |
7020 */ | |
7021 void API dw_container_change_item(HWND handle, int column, int row, void *data) | |
7022 { | |
7023 dw_container_set_item(handle, NULL, column, row, data); | |
7024 } | |
7025 | |
7026 /* | |
7027 * Changes an existing item in specified row and column to the given data. | |
7028 * Parameters: | |
7029 * handle: Handle to the container window (widget). | |
7030 * column: Zero based column of data being set. | |
7031 * row: Zero based row of data being set. | |
7032 * data: Pointer to the data to be added. | |
7033 */ | |
7034 void API dw_filesystem_change_item(HWND handle, int column, int row, void *data) | |
7035 { | |
7036 dw_container_change_item(handle, column+1, row, data); | |
7037 } | |
7038 | |
7039 /* | |
7040 * Changes an item in specified row and column to the given data. | |
7041 * Parameters: | |
7042 * handle: Handle to the container window (widget). | |
7043 * pointer: Pointer to the allocated memory in dw_container_alloc(). | |
7044 * column: Zero based column of data being set. | |
7045 * row: Zero based row of data being set. | |
7046 * data: Pointer to the data to be added. | |
7047 */ | |
7048 void API dw_filesystem_change_file(HWND handle, int row, const char *filename, HICN icon) | |
7049 { | |
7050 dw_filesystem_set_file(handle, NULL, row, filename, icon); | |
7051 } | |
7052 | |
7053 /* | |
7054 * Sets an item in specified row and column to the given data. | |
7055 * Parameters: | |
7056 * handle: Handle to the container window (widget). | |
7057 * pointer: Pointer to the allocated memory in dw_container_alloc(). | |
7058 * column: Zero based column of data being set. | |
7059 * row: Zero based row of data being set. | |
7060 * data: Pointer to the data to be added. | |
7061 */ | |
7062 DW_FUNCTION_DEFINITION(dw_filesystem_set_file, void, HWND handle, void *pointer, int row, const char *filename, HICN icon) | |
7063 DW_FUNCTION_ADD_PARAM5(handle, pointer, row, filename, icon) | |
7064 DW_FUNCTION_NO_RETURN(dw_filesystem_set_file) | |
7065 DW_FUNCTION_RESTORE_PARAM5(handle, HWND, pointer, void *, row, int, filename, char *, icon, HICN) | |
7066 { | |
7067 DW_FUNCTION_INIT; | |
7068 DWContainer *cont = handle; | |
7069 NSString *text = filename ? [NSString stringWithUTF8String:filename] : nil; | |
7070 int lastadd = 0; | |
7071 | |
7072 /* If pointer is NULL we are getting a change request instead of set */ | |
7073 if(pointer) | |
7074 lastadd = [cont lastAddPoint]; | |
7075 | |
7076 id object = [cont getRow:(row+lastadd) and:0]; | |
7077 | |
7078 /* If it is a cell, change the content of the cell */ | |
7079 if([object isMemberOfClass:[NSTableCellView class]]) | |
7080 { | |
7081 NSTableCellView *cell = object; | |
7082 | |
7083 if(icon) | |
7084 [[cell imageView] setImage:icon]; | |
7085 if(text) | |
7086 [[cell textField] setStringValue:text]; | |
7087 } | |
7088 else /* Otherwise replace it with a new cell */ | |
7089 [cont editCell:_dw_table_cell_view_new(icon, text) at:(row+lastadd) and:0]; | |
7090 [cont setNeedsDisplay:YES]; | |
7091 DW_FUNCTION_RETURN_NOTHING; | |
7092 } | |
7093 | |
7094 /* | |
7095 * Sets an item in specified row and column to the given data. | |
7096 * Parameters: | |
7097 * handle: Handle to the container window (widget). | |
7098 * pointer: Pointer to the allocated memory in dw_container_alloc(). | |
7099 * column: Zero based column of data being set. | |
7100 * row: Zero based row of data being set. | |
7101 * data: Pointer to the data to be added. | |
7102 */ | |
7103 void API dw_filesystem_set_item(HWND handle, void *pointer, int column, int row, void *data) | |
7104 { | |
7105 dw_container_set_item(handle, pointer, column+1, row, data); | |
7106 } | |
7107 | |
7108 /* | |
7109 * Gets column type for a container column | |
7110 * Parameters: | |
7111 * handle: Handle to the container window (widget). | |
7112 * column: Zero based column. | |
7113 */ | |
7114 DW_FUNCTION_DEFINITION(dw_container_get_column_type, int, HWND handle, int column) | |
7115 DW_FUNCTION_ADD_PARAM2(handle, column) | |
7116 DW_FUNCTION_RETURN(dw_container_get_column_type, int) | |
7117 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, column, int) | |
7118 { | |
7119 DW_FUNCTION_INIT; | |
7120 DWContainer *cont = handle; | |
7121 int rc; | |
7122 int flag = [cont cellType:column]; | |
7123 if(flag & DW_CFA_BITMAPORICON) | |
7124 rc = DW_CFA_BITMAPORICON; | |
7125 else if(flag & DW_CFA_STRING) | |
7126 rc = DW_CFA_STRING; | |
7127 else if(flag & DW_CFA_ULONG) | |
7128 rc = DW_CFA_ULONG; | |
7129 else if(flag & DW_CFA_DATE) | |
7130 rc = DW_CFA_DATE; | |
7131 else if(flag & DW_CFA_TIME) | |
7132 rc = DW_CFA_TIME; | |
7133 else | |
7134 rc = 0; | |
7135 DW_FUNCTION_RETURN_THIS(rc); | |
7136 } | |
7137 | |
7138 /* | |
7139 * Gets column type for a filesystem container column | |
7140 * Parameters: | |
7141 * handle: Handle to the container window (widget). | |
7142 * column: Zero based column. | |
7143 */ | |
7144 int API dw_filesystem_get_column_type(HWND handle, int column) | |
7145 { | |
7146 return dw_container_get_column_type(handle, column+1); | |
7147 } | |
7148 | |
7149 /* | |
7150 * Sets the alternating row colors for container window (widget) handle. | |
7151 * Parameters: | |
7152 * handle: The window (widget) handle. | |
7153 * oddcolor: Odd row background color in DW_RGB format or a default color index. | |
7154 * evencolor: Even row background color in DW_RGB format or a default color index. | |
7155 * DW_RGB_TRANSPARENT will disable coloring rows. | |
7156 * DW_CLR_DEFAULT will use the system default alternating row colors. | |
7157 */ | |
7158 DW_FUNCTION_DEFINITION(dw_container_set_stripe, void, HWND handle, unsigned long oddcolor, unsigned long evencolor) | |
7159 DW_FUNCTION_ADD_PARAM3(handle, oddcolor, evencolor) | |
7160 DW_FUNCTION_NO_RETURN(dw_container_set_stripe) | |
7161 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, oddcolor, unsigned long, evencolor, unsigned long) | |
7162 { | |
7163 DW_FUNCTION_INIT; | |
7164 DWContainer *cont = handle; | |
7165 [cont setRowBgOdd:oddcolor | |
7166 andEven:evencolor]; | |
7167 DW_FUNCTION_RETURN_NOTHING; | |
7168 } | |
7169 | |
7170 /* | |
7171 * Sets the width of a column in the container. | |
7172 * Parameters: | |
7173 * handle: Handle to window (widget) of container. | |
7174 * column: Zero based column of width being set. | |
7175 * width: Width of column in pixels. | |
7176 */ | |
7177 DW_FUNCTION_DEFINITION(dw_container_set_column_width, void, HWND handle, int column, int width) | |
7178 DW_FUNCTION_ADD_PARAM3(handle, column, width) | |
7179 DW_FUNCTION_NO_RETURN(dw_container_set_column_width) | |
7180 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, column, int, width, int) | |
7181 { | |
7182 DW_FUNCTION_INIT; | |
7183 DWContainer *cont = handle; | |
7184 if([cont filesystem]) | |
7185 column++; | |
7186 NSTableColumn *col = [cont getColumn:column]; | |
7187 | |
7188 [col setWidth:width]; | |
7189 DW_FUNCTION_RETURN_NOTHING; | |
7190 } | |
7191 | |
7192 /* | |
7193 * Sets the title of a row in the container. | |
7194 * Parameters: | |
7195 * pointer: Pointer to the allocated memory in dw_container_alloc(). | |
7196 * row: Zero based row of data being set. | |
7197 * title: String title of the item. | |
7198 */ | |
7199 DW_FUNCTION_DEFINITION(dw_container_set_row_title, void, void *pointer, int row, const char *title) | |
7200 DW_FUNCTION_ADD_PARAM3(pointer, row, title) | |
7201 DW_FUNCTION_NO_RETURN(dw_container_set_row_title) | |
7202 DW_FUNCTION_RESTORE_PARAM3(pointer, void *, row, int, title, char *) | |
7203 { | |
7204 DW_FUNCTION_INIT; | |
7205 DWContainer *cont = pointer; | |
7206 int lastadd = [cont lastAddPoint]; | |
7207 [cont setRow:(row+lastadd) title:title]; | |
7208 DW_FUNCTION_RETURN_NOTHING; | |
7209 } | |
7210 | |
7211 | |
7212 /* | |
7213 * Sets the data pointer of a row in the container. | |
7214 * Parameters: | |
7215 * pointer: Pointer to the allocated memory in dw_container_alloc(). | |
7216 * row: Zero based row of data being set. | |
7217 * data: Data pointer. | |
7218 */ | |
7219 DW_FUNCTION_DEFINITION(dw_container_set_row_data, void, void *pointer, int row, void *data) | |
7220 DW_FUNCTION_ADD_PARAM3(pointer, row, data) | |
7221 DW_FUNCTION_NO_RETURN(dw_container_set_row_data) | |
7222 DW_FUNCTION_RESTORE_PARAM3(pointer, void *, row, int, data, void *) | |
7223 { | |
7224 DW_FUNCTION_INIT; | |
7225 DWContainer *cont = pointer; | |
7226 int lastadd = [cont lastAddPoint]; | |
7227 [cont setRowData:(row+lastadd) title:data]; | |
7228 DW_FUNCTION_RETURN_NOTHING; | |
7229 } | |
7230 | |
7231 | |
7232 /* | |
7233 * Sets the title of a row in the container. | |
7234 * Parameters: | |
7235 * handle: Handle to window (widget) of container. | |
7236 * row: Zero based row of data being set. | |
7237 * title: String title of the item. | |
7238 */ | |
7239 DW_FUNCTION_DEFINITION(dw_container_change_row_title, void, HWND handle, int row, const char *title) | |
7240 DW_FUNCTION_ADD_PARAM3(handle, row, title) | |
7241 DW_FUNCTION_NO_RETURN(dw_container_change_row_title) | |
7242 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, row, int, title, char *) | |
7243 { | |
7244 DW_FUNCTION_INIT; | |
7245 DWContainer *cont = handle; | |
7246 [cont setRow:row title:title]; | |
7247 DW_FUNCTION_RETURN_NOTHING; | |
7248 } | |
7249 | |
7250 /* | |
7251 * Sets the data pointer of a row in the container. | |
7252 * Parameters: | |
7253 * handle: Handle to window (widget) of container. | |
7254 * row: Zero based row of data being set. | |
7255 * data: Data pointer. | |
7256 */ | |
7257 DW_FUNCTION_DEFINITION(dw_container_change_row_data, void, HWND handle, int row, void *data) | |
7258 DW_FUNCTION_ADD_PARAM3(handle, row, data) | |
7259 DW_FUNCTION_NO_RETURN(dw_container_change_row_data) | |
7260 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, row, int, data, void *) | |
7261 { | |
7262 DW_FUNCTION_INIT; | |
7263 DWContainer *cont = handle; | |
7264 [cont setRowData:row title:data]; | |
7265 DW_FUNCTION_RETURN_NOTHING; | |
7266 } | |
7267 | |
7268 /* | |
7269 * Sets the title of a row in the container. | |
7270 * Parameters: | |
7271 * handle: Handle to the container window (widget). | |
7272 * pointer: Pointer to the allocated memory in dw_container_alloc(). | |
7273 * rowcount: The number of rows to be inserted. | |
7274 */ | |
7275 DW_FUNCTION_DEFINITION(dw_container_insert, void, HWND handle, void *pointer, int rowcount) | |
7276 DW_FUNCTION_ADD_PARAM3(handle, pointer, rowcount) | |
7277 DW_FUNCTION_NO_RETURN(dw_container_insert) | |
7278 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, DW_UNUSED(pointer), void *, DW_UNUSED(rowcount), int) | |
7279 { | |
7280 DW_FUNCTION_INIT; | |
7281 DWContainer *cont = handle; | |
7282 [cont reloadData]; | |
7283 DW_FUNCTION_RETURN_NOTHING; | |
7284 } | |
7285 | |
7286 /* | |
7287 * Removes all rows from a container. | |
7288 * Parameters: | |
7289 * handle: Handle to the window (widget) to be cleared. | |
7290 * redraw: TRUE to cause the container to redraw immediately. | |
7291 */ | |
7292 DW_FUNCTION_DEFINITION(dw_container_clear, void, HWND handle, int redraw) | |
7293 DW_FUNCTION_ADD_PARAM2(handle, redraw) | |
7294 DW_FUNCTION_NO_RETURN(dw_container_clear) | |
7295 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, redraw, int) | |
7296 { | |
7297 DW_FUNCTION_INIT; | |
7298 DWContainer *cont = handle; | |
7299 [cont clear]; | |
7300 if(redraw) | |
7301 [cont reloadData]; | |
7302 DW_FUNCTION_RETURN_NOTHING; | |
7303 } | |
7304 | |
7305 /* | |
7306 * Removes the first x rows from a container. | |
7307 * Parameters: | |
7308 * handle: Handle to the window (widget) to be deleted from. | |
7309 * rowcount: The number of rows to be deleted. | |
7310 */ | |
7311 DW_FUNCTION_DEFINITION(dw_container_delete, void, HWND handle, int rowcount) | |
7312 DW_FUNCTION_ADD_PARAM2(handle, rowcount) | |
7313 DW_FUNCTION_NO_RETURN(dw_container_delete) | |
7314 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, rowcount, int) | |
7315 { | |
7316 DW_FUNCTION_INIT; | |
7317 DWContainer *cont = handle; | |
7318 int x; | |
7319 | |
7320 for(x=0;x<rowcount;x++) | |
7321 { | |
7322 [cont removeRow:0]; | |
7323 } | |
7324 [cont reloadData]; | |
7325 DW_FUNCTION_RETURN_NOTHING; | |
7326 } | |
7327 | |
7328 /* | |
7329 * Scrolls container up or down. | |
7330 * Parameters: | |
7331 * handle: Handle to the window (widget) to be scrolled. | |
7332 * direction: DW_SCROLL_UP, DW_SCROLL_DOWN, DW_SCROLL_TOP or | |
7333 * DW_SCROLL_BOTTOM. (rows is ignored for last two) | |
7334 * rows: The number of rows to be scrolled. | |
7335 */ | |
7336 DW_FUNCTION_DEFINITION(dw_container_scroll, void, HWND handle, int direction, long rows) | |
7337 DW_FUNCTION_ADD_PARAM3(handle, direction, rows) | |
7338 DW_FUNCTION_NO_RETURN(dw_container_scroll) | |
7339 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, direction, int, rows, long) | |
7340 { | |
7341 DW_FUNCTION_INIT; | |
7342 DWContainer *cont = handle; | |
7343 UIScrollView *sv = [cont scrollview]; | |
7344 NSScroller *scrollbar = [sv verticalScroller]; | |
7345 int rowcount = (int)[cont numberOfRowsInTableView:cont]; | |
7346 float currpos = [scrollbar floatValue]; | |
7347 float change; | |
7348 | |
7349 /* Safety check */ | |
7350 if(rowcount < 1) | |
7351 { | |
7352 return; | |
7353 } | |
7354 | |
7355 change = (float)rows/(float)rowcount; | |
7356 | |
7357 switch(direction) | |
7358 { | |
7359 case DW_SCROLL_TOP: | |
7360 { | |
7361 [scrollbar setFloatValue:0]; | |
7362 break; | |
7363 } | |
7364 case DW_SCROLL_BOTTOM: | |
7365 { | |
7366 [scrollbar setFloatValue:1]; | |
7367 break; | |
7368 } | |
7369 case DW_SCROLL_UP: | |
7370 { | |
7371 float newpos = currpos - change; | |
7372 if(newpos < 0) | |
7373 { | |
7374 newpos = 0; | |
7375 } | |
7376 [scrollbar setFloatValue:newpos]; | |
7377 break; | |
7378 } | |
7379 case DW_SCROLL_DOWN: | |
7380 { | |
7381 float newpos = currpos + change; | |
7382 if(newpos > 1) | |
7383 { | |
7384 newpos = 1; | |
7385 } | |
7386 [scrollbar setFloatValue:newpos]; | |
7387 break; | |
7388 } | |
7389 } | |
7390 DW_FUNCTION_RETURN_NOTHING; | |
7391 } | |
7392 | |
7393 /* | |
7394 * Starts a new query of a container. | |
7395 * Parameters: | |
7396 * handle: Handle to the window (widget) to be queried. | |
7397 * flags: If this parameter is DW_CRA_SELECTED it will only | |
7398 * return items that are currently selected. Otherwise | |
7399 * it will return all records in the container. | |
7400 */ | |
7401 DW_FUNCTION_DEFINITION(dw_container_query_start, char *, HWND handle, unsigned long flags) | |
7402 DW_FUNCTION_ADD_PARAM2(handle, flags) | |
7403 DW_FUNCTION_RETURN(dw_container_query_start, char *) | |
7404 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, flags, unsigned long) | |
7405 { | |
7406 DW_FUNCTION_INIT; | |
7407 DWContainer *cont = handle; | |
7408 NSIndexSet *selected = [cont selectedRowIndexes]; | |
7409 NSUInteger result = [selected indexGreaterThanOrEqualToIndex:0]; | |
7410 void *retval = NULL; | |
7411 | |
7412 if(result != NSNotFound) | |
7413 { | |
7414 if(flags & DW_CR_RETDATA) | |
7415 retval = [cont getRowData:(int)result]; | |
7416 else | |
7417 { | |
7418 char *temp = [cont getRowTitle:(int)result]; | |
7419 if(temp) | |
7420 retval = strdup(temp); | |
7421 } | |
7422 [cont setLastQueryPoint:(int)result]; | |
7423 } | |
7424 DW_FUNCTION_RETURN_THIS(retval); | |
7425 } | |
7426 | |
7427 /* | |
7428 * Continues an existing query of a container. | |
7429 * Parameters: | |
7430 * handle: Handle to the window (widget) to be queried. | |
7431 * flags: If this parameter is DW_CRA_SELECTED it will only | |
7432 * return items that are currently selected. Otherwise | |
7433 * it will return all records in the container. | |
7434 */ | |
7435 DW_FUNCTION_DEFINITION(dw_container_query_next, char *, HWND handle, unsigned long flags) | |
7436 DW_FUNCTION_ADD_PARAM2(handle, flags) | |
7437 DW_FUNCTION_RETURN(dw_container_query_next, char *) | |
7438 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, flags, unsigned long) | |
7439 { | |
7440 DW_FUNCTION_INIT; | |
7441 DWContainer *cont = handle; | |
7442 int lastQueryPoint = [cont lastQueryPoint]; | |
7443 NSIndexSet *selected = [cont selectedRowIndexes]; | |
7444 NSUInteger result = [selected indexGreaterThanIndex:lastQueryPoint]; | |
7445 void *retval = NULL; | |
7446 | |
7447 if(result != NSNotFound) | |
7448 { | |
7449 if(flags & DW_CR_RETDATA) | |
7450 retval = [cont getRowData:(int)result]; | |
7451 else | |
7452 { | |
7453 char *temp = [cont getRowTitle:(int)result]; | |
7454 if(temp) | |
7455 retval = strdup(temp); | |
7456 } | |
7457 [cont setLastQueryPoint:(int)result]; | |
7458 } | |
7459 DW_FUNCTION_RETURN_THIS(retval); | |
7460 } | |
7461 | |
7462 /* | |
7463 * Cursors the item with the text speficied, and scrolls to that item. | |
7464 * Parameters: | |
7465 * handle: Handle to the window (widget) to be queried. | |
7466 * text: Text usually returned by dw_container_query(). | |
7467 */ | |
7468 DW_FUNCTION_DEFINITION(dw_container_cursor, void, HWND handle, const char *text) | |
7469 DW_FUNCTION_ADD_PARAM2(handle, text) | |
7470 DW_FUNCTION_NO_RETURN(dw_container_cursor) | |
7471 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, text, char *) | |
7472 { | |
7473 DW_FUNCTION_INIT; | |
7474 DW_LOCAL_POOL_IN; | |
7475 DWContainer *cont = handle; | |
7476 char *thistext; | |
7477 int x, count = (int)[cont numberOfRowsInTableView:cont]; | |
7478 | |
7479 for(x=0;x<count;x++) | |
7480 { | |
7481 thistext = [cont getRowTitle:x]; | |
7482 | |
7483 if(thistext && strcmp(thistext, text) == 0) | |
7484 { | |
7485 NSIndexSet *selected = [[NSIndexSet alloc] initWithIndex:(NSUInteger)x]; | |
7486 | |
7487 [cont selectRowIndexes:selected byExtendingSelection:YES]; | |
7488 [selected release]; | |
7489 [cont scrollRowToVisible:x]; | |
7490 x=count; | |
7491 break; | |
7492 } | |
7493 } | |
7494 DW_LOCAL_POOL_OUT; | |
7495 DW_FUNCTION_RETURN_NOTHING; | |
7496 } | |
7497 | |
7498 /* | |
7499 * Cursors the item with the data speficied, and scrolls to that item. | |
7500 * Parameters: | |
7501 * handle: Handle to the window (widget) to be queried. | |
7502 * data: Data associated with the row. | |
7503 */ | |
7504 DW_FUNCTION_DEFINITION(dw_container_cursor_by_data, void, HWND handle, void *data) | |
7505 DW_FUNCTION_ADD_PARAM2(handle, data) | |
7506 DW_FUNCTION_NO_RETURN(dw_container_cursor_by_data) | |
7507 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, data, void *) | |
7508 { | |
7509 DW_FUNCTION_INIT; | |
7510 DW_LOCAL_POOL_IN; | |
7511 DWContainer *cont = handle; | |
7512 void *thisdata; | |
7513 int x, count = (int)[cont numberOfRowsInTableView:cont]; | |
7514 | |
7515 for(x=0;x<count;x++) | |
7516 { | |
7517 thisdata = [cont getRowData:x]; | |
7518 | |
7519 if(thisdata == data) | |
7520 { | |
7521 NSIndexSet *selected = [[NSIndexSet alloc] initWithIndex:(NSUInteger)x]; | |
7522 | |
7523 [cont selectRowIndexes:selected byExtendingSelection:YES]; | |
7524 [selected release]; | |
7525 [cont scrollRowToVisible:x]; | |
7526 x=count; | |
7527 break; | |
7528 } | |
7529 } | |
7530 DW_LOCAL_POOL_OUT; | |
7531 DW_FUNCTION_RETURN_NOTHING; | |
7532 } | |
7533 | |
7534 /* | |
7535 * Deletes the item with the text speficied. | |
7536 * Parameters: | |
7537 * handle: Handle to the window (widget). | |
7538 * text: Text usually returned by dw_container_query(). | |
7539 */ | |
7540 DW_FUNCTION_DEFINITION(dw_container_delete_row, void, HWND handle, const char *text) | |
7541 DW_FUNCTION_ADD_PARAM2(handle, text) | |
7542 DW_FUNCTION_NO_RETURN(dw_container_delete_row) | |
7543 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, text, char *) | |
7544 { | |
7545 DW_FUNCTION_INIT; | |
7546 DWContainer *cont = handle; | |
7547 char *thistext; | |
7548 int x, count = (int)[cont numberOfRowsInTableView:cont]; | |
7549 | |
7550 for(x=0;x<count;x++) | |
7551 { | |
7552 thistext = [cont getRowTitle:x]; | |
7553 | |
7554 if(thistext && strcmp(thistext, text) == 0) | |
7555 { | |
7556 [cont removeRow:x]; | |
7557 [cont reloadData]; | |
7558 x=count; | |
7559 break; | |
7560 } | |
7561 } | |
7562 DW_FUNCTION_RETURN_NOTHING; | |
7563 } | |
7564 | |
7565 /* | |
7566 * Deletes the item with the data speficied. | |
7567 * Parameters: | |
7568 * handle: Handle to the window (widget). | |
7569 * data: Data specified. | |
7570 */ | |
7571 DW_FUNCTION_DEFINITION(dw_container_delete_row_by_data, void, HWND handle, void *data) | |
7572 DW_FUNCTION_ADD_PARAM2(handle, data) | |
7573 DW_FUNCTION_NO_RETURN(dw_container_delete_row_by_data) | |
7574 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, data, void *) | |
7575 { | |
7576 DW_FUNCTION_INIT; | |
7577 DWContainer *cont = handle; | |
7578 void *thisdata; | |
7579 int x, count = (int)[cont numberOfRowsInTableView:cont]; | |
7580 | |
7581 for(x=0;x<count;x++) | |
7582 { | |
7583 thisdata = [cont getRowData:x]; | |
7584 | |
7585 if(thisdata == data) | |
7586 { | |
7587 [cont removeRow:x]; | |
7588 [cont reloadData]; | |
7589 x=count; | |
7590 break; | |
7591 } | |
7592 } | |
7593 DW_FUNCTION_RETURN_NOTHING; | |
7594 } | |
7595 | |
7596 /* | |
7597 * Optimizes the column widths so that all data is visible. | |
7598 * Parameters: | |
7599 * handle: Handle to the window (widget) to be optimized. | |
7600 */ | |
7601 DW_FUNCTION_DEFINITION(dw_container_optimize, void, HWND handle) | |
7602 DW_FUNCTION_ADD_PARAM1(handle) | |
7603 DW_FUNCTION_NO_RETURN(dw_container_optimize) | |
7604 DW_FUNCTION_RESTORE_PARAM1(handle, HWND) | |
7605 { | |
7606 DW_FUNCTION_INIT; | |
7607 DWContainer *cont = handle; | |
7608 [cont optimize]; | |
7609 DW_FUNCTION_RETURN_NOTHING; | |
7610 } | |
7611 | |
7612 /* | |
7613 * Inserts an icon into the taskbar. | |
7614 * Parameters: | |
7615 * handle: Window handle that will handle taskbar icon messages. | |
7616 * icon: Icon handle to display in the taskbar. | |
7617 * bubbletext: Text to show when the mouse is above the icon. | |
7618 */ | |
7619 void API dw_taskbar_insert(HWND handle, HICN icon, const char *bubbletext) | |
7620 { | |
7621 } | |
7622 | |
7623 /* | |
7624 * Deletes an icon from the taskbar. | |
7625 * Parameters: | |
7626 * handle: Window handle that was used with dw_taskbar_insert(). | |
7627 * icon: Icon handle that was used with dw_taskbar_insert(). | |
7628 */ | |
7629 void API dw_taskbar_delete(HWND handle, HICN icon) | |
7630 { | |
7631 } | |
7632 | |
7633 /* Internal function to keep HICNs from getting too big */ | |
7634 void _icon_resize(UIImage *image) | |
7635 { | |
7636 if(image) | |
7637 { | |
7638 NSSize size = [image size]; | |
7639 if(size.width > 24 || size.height > 24) | |
7640 { | |
7641 if(size.width > 24) | |
7642 size.width = 24; | |
7643 if(size.height > 24) | |
7644 size.height = 24; | |
7645 [image setSize:size]; | |
7646 } | |
7647 } | |
7648 } | |
7649 | |
7650 /* Internal version that does not resize the image */ | |
7651 HICN _dw_icon_load(unsigned long resid) | |
7652 { | |
7653 NSBundle *bundle = [NSBundle mainBundle]; | |
7654 NSString *respath = [bundle resourcePath]; | |
7655 NSString *filepath = [respath stringByAppendingFormat:@"/%lu.png", resid]; | |
7656 UIImage *image = [[UIImage alloc] initWithContentsOfFile:filepath]; | |
7657 return image; | |
7658 } | |
7659 | |
7660 /* | |
7661 * Obtains an icon from a module (or header in GTK). | |
7662 * Parameters: | |
7663 * module: Handle to module (DLL) in OS/2 and Windows. | |
7664 * id: A unsigned long id int the resources on OS/2 and | |
7665 * Windows, on GTK this is converted to a pointer | |
7666 * to an embedded XPM. | |
7667 */ | |
7668 HICN API dw_icon_load(unsigned long module, unsigned long resid) | |
7669 { | |
7670 UIImage *image = _dw_icon_load(resid); | |
7671 _icon_resize(image); | |
7672 return image; | |
7673 } | |
7674 | |
7675 /* | |
7676 * Obtains an icon from a file. | |
7677 * Parameters: | |
7678 * filename: Name of the file, omit extention to have | |
7679 * DW pick the appropriate file extension. | |
7680 * (ICO on OS/2 or Windows, XPM on Unix) | |
7681 */ | |
7682 HICN API dw_icon_load_from_file(const char *filename) | |
7683 { | |
7684 char *ext = _dw_get_image_extension( filename ); | |
7685 | |
7686 NSString *nstr = [ NSString stringWithUTF8String:filename ]; | |
7687 UIImage *image = [[UIImage alloc] initWithContentsOfFile:nstr]; | |
7688 if(!image && ext) | |
7689 { | |
7690 nstr = [nstr stringByAppendingString: [NSString stringWithUTF8String:ext]]; | |
7691 image = [[UIImage alloc] initWithContentsOfFile:nstr]; | |
7692 } | |
7693 _icon_resize(image); | |
7694 return image; | |
7695 } | |
7696 | |
7697 /* | |
7698 * Obtains an icon from data | |
7699 * Parameters: | |
7700 * filename: Name of the file, omit extention to have | |
7701 * DW pick the appropriate file extension. | |
7702 * (ICO on OS/2 or Windows, XPM on Unix) | |
7703 */ | |
7704 HICN API dw_icon_load_from_data(const char *data, int len) | |
7705 { | |
7706 NSData *thisdata = [NSData dataWithBytes:data length:len]; | |
7707 UIImage *image = [[UIImage alloc] initWithData:thisdata]; | |
7708 _icon_resize(image); | |
7709 return image; | |
7710 } | |
7711 | |
7712 /* | |
7713 * Frees a loaded resource in OS/2 and Windows. | |
7714 * Parameters: | |
7715 * handle: Handle to icon returned by dw_icon_load(). | |
7716 */ | |
7717 void API dw_icon_free(HICN handle) | |
7718 { | |
7719 UIImage *image = handle; | |
7720 DW_LOCAL_POOL_IN; | |
7721 [image release]; | |
7722 DW_LOCAL_POOL_OUT; | |
7723 } | |
7724 | |
7725 /* | |
7726 * Create a new MDI Frame to be packed. | |
7727 * Parameters: | |
7728 * id: An ID to be used with dw_window_from_id or 0L. | |
7729 */ | |
7730 HWND API dw_mdi_new(unsigned long cid) | |
7731 { | |
7732 /* There isn't anything like quite like MDI on MacOS... | |
7733 * However we will make floating windows that hide | |
7734 * when the application is deactivated to simulate | |
7735 * similar behavior. | |
7736 */ | |
7737 DWMDI *mdi = [[DWMDI alloc] init]; | |
7738 /* [mdi setTag:cid]; Why doesn't this work? */ | |
7739 return mdi; | |
7740 } | |
7741 | |
7742 /* | |
7743 * Creates a splitbar window (widget) with given parameters. | |
7744 * Parameters: | |
7745 * type: Value can be DW_VERT or DW_HORZ. | |
7746 * topleft: Handle to the window to be top or left. | |
7747 * bottomright: Handle to the window to be bottom or right. | |
7748 * Returns: | |
7749 * A handle to a splitbar window or NULL on failure. | |
7750 */ | |
7751 DW_FUNCTION_DEFINITION(dw_splitbar_new, HWND, int type, HWND topleft, HWND bottomright, unsigned long cid) | |
7752 DW_FUNCTION_ADD_PARAM4(type, topleft, bottomright, cid) | |
7753 DW_FUNCTION_RETURN(dw_splitbar_new, HWND) | |
7754 DW_FUNCTION_RESTORE_PARAM4(type, int, topleft, HWND, bottomright, HWND, cid, unsigned long) | |
7755 { | |
7756 DW_FUNCTION_INIT; | |
7757 id tmpbox = dw_box_new(DW_VERT, 0); | |
7758 DWSplitBar *split = [[DWSplitBar alloc] init]; | |
7759 [split setDelegate:split]; | |
7760 dw_box_pack_start(tmpbox, topleft, 0, 0, TRUE, TRUE, 0); | |
7761 [split addSubview:tmpbox]; | |
7762 [tmpbox autorelease]; | |
7763 tmpbox = dw_box_new(DW_VERT, 0); | |
7764 dw_box_pack_start(tmpbox, bottomright, 0, 0, TRUE, TRUE, 0); | |
7765 [split addSubview:tmpbox]; | |
7766 [tmpbox autorelease]; | |
7767 if(type == DW_VERT) | |
7768 { | |
7769 [split setVertical:NO]; | |
7770 } | |
7771 else | |
7772 { | |
7773 [split setVertical:YES]; | |
7774 } | |
7775 /* Set the default percent to 50% split */ | |
7776 [split setPercent:50.0]; | |
7777 [split setTag:cid]; | |
7778 DW_FUNCTION_RETURN_THIS(split); | |
7779 } | |
7780 | |
7781 /* | |
7782 * Sets the position of a splitbar (pecentage). | |
7783 * Parameters: | |
7784 * handle: The handle to the splitbar returned by dw_splitbar_new(). | |
7785 * percent: The position of the splitbar. | |
7786 */ | |
7787 DW_FUNCTION_DEFINITION(dw_splitbar_set, void, HWND handle, float percent) | |
7788 DW_FUNCTION_ADD_PARAM2(handle, percent) | |
7789 DW_FUNCTION_NO_RETURN(dw_splitbar_set) | |
7790 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, percent, float) | |
7791 { | |
7792 DW_FUNCTION_INIT; | |
7793 DWSplitBar *split = handle; | |
7794 NSRect rect = [split frame]; | |
7795 float pos; | |
7796 /* Calculate the position based on the size */ | |
7797 if([split isVertical]) | |
7798 { | |
7799 pos = rect.size.width * (percent / 100.0); | |
7800 } | |
7801 else | |
7802 { | |
7803 pos = rect.size.height * (percent / 100.0); | |
7804 } | |
7805 if(pos > 0) | |
7806 { | |
7807 [split setPosition:pos ofDividerAtIndex:0]; | |
7808 } | |
7809 else | |
7810 { | |
7811 /* If we have no size.. wait until the resize | |
7812 * event when we get an actual size to try | |
7813 * to set the splitbar again. | |
7814 */ | |
7815 [split setPercent:percent]; | |
7816 } | |
7817 DW_FUNCTION_RETURN_NOTHING; | |
7818 } | |
7819 | |
7820 /* | |
7821 * Gets the position of a splitbar (pecentage). | |
7822 * Parameters: | |
7823 * handle: The handle to the splitbar returned by dw_splitbar_new(). | |
7824 */ | |
7825 float API dw_splitbar_get(HWND handle) | |
7826 { | |
7827 DWSplitBar *split = handle; | |
7828 NSRect rect1 = [split frame]; | |
7829 NSArray *subviews = [split subviews]; | |
7830 UIView *view = [subviews objectAtIndex:0]; | |
7831 NSRect rect2 = [view frame]; | |
7832 float pos, total, retval = 0.0; | |
7833 if([split isVertical]) | |
7834 { | |
7835 total = rect1.size.width; | |
7836 pos = rect2.size.width; | |
7837 } | |
7838 else | |
7839 { | |
7840 total = rect1.size.height; | |
7841 pos = rect2.size.height; | |
7842 } | |
7843 if(total > 0) | |
7844 { | |
7845 retval = pos / total; | |
7846 } | |
7847 return retval; | |
7848 } | |
7849 | |
7850 /* Internal function to convert fontname to UIFont */ | |
7851 UIFont *_dw_font_by_name(const char *fontname) | |
7852 { | |
7853 UIFont *font = DWDefaultFont; | |
7854 | |
7855 if(fontname) | |
7856 { | |
7857 char *name = strchr(fontname, '.'); | |
7858 | |
7859 if(name && (name++)) | |
7860 { | |
7861 int size = atoi(fontname); | |
7862 char *Italic = strstr(name, " Italic"); | |
7863 char *Bold = strstr(name, " Bold"); | |
7864 size_t len = (Italic ? (Bold ? (Italic > Bold ? (Bold - name) : (Italic - name)) : (Italic - name)) : (Bold ? (Bold - name) : strlen(name))); | |
7865 char *newname = alloca(len+1); | |
7866 | |
7867 memset(newname, 0, len+1); | |
7868 strncpy(newname, name, len); | |
7869 | |
7870 font = [DWFontManager fontWithFamily:[NSString stringWithUTF8String:newname] | |
7871 traits:(Italic ? NSItalicFontMask : 0)|(Bold ? NSBoldFontMask : 0) | |
7872 weight:5 | |
7873 size:(float)size]; | |
7874 } | |
7875 } | |
7876 return font; | |
7877 } | |
7878 | |
7879 /* | |
7880 * Create a bitmap object to be packed. | |
7881 * Parameters: | |
7882 * id: An ID to be used with dw_window_from_id() or 0L. | |
7883 */ | |
7884 DW_FUNCTION_DEFINITION(dw_bitmap_new, HWND, ULONG cid) | |
7885 DW_FUNCTION_ADD_PARAM1(cid) | |
7886 DW_FUNCTION_RETURN(dw_bitmap_new, HWND) | |
7887 DW_FUNCTION_RESTORE_PARAM1(cid, ULONG) | |
7888 { | |
7889 DW_FUNCTION_INIT; | |
7890 UIImageView *bitmap = [[UIImageView alloc] init]; | |
7891 [bitmap setImageFrameStyle:UIImageFrameNone]; | |
7892 [bitmap setImageScaling:UIImageScaleNone]; | |
7893 [bitmap setEditable:NO]; | |
7894 [bitmap setTag:cid]; | |
7895 DW_FUNCTION_RETURN_THIS(bitmap); | |
7896 } | |
7897 | |
7898 /* | |
7899 * Creates a pixmap with given parameters. | |
7900 * Parameters: | |
7901 * handle: Window handle the pixmap is associated with. | |
7902 * width: Width of the pixmap in pixels. | |
7903 * height: Height of the pixmap in pixels. | |
7904 * depth: Color depth of the pixmap. | |
7905 * Returns: | |
7906 * A handle to a pixmap or NULL on failure. | |
7907 */ | |
7908 HPIXMAP API dw_pixmap_new(HWND handle, unsigned long width, unsigned long height, int depth) | |
7909 { | |
7910 HPIXMAP pixmap; | |
7911 | |
7912 if(!(pixmap = calloc(1,sizeof(struct _hpixmap)))) | |
7913 return NULL; | |
7914 pixmap->width = width; | |
7915 pixmap->height = height; | |
7916 pixmap->handle = handle; | |
7917 pixmap->image = [[NSBitmapImageRep alloc] | |
7918 initWithBitmapDataPlanes:NULL | |
7919 pixelsWide:width | |
7920 pixelsHigh:height | |
7921 bitsPerSample:8 | |
7922 samplesPerPixel:4 | |
7923 hasAlpha:YES | |
7924 isPlanar:NO | |
7925 colorSpaceName:NSDeviceRGBColorSpace | |
7926 bytesPerRow:0 | |
7927 bitsPerPixel:0]; | |
7928 return pixmap; | |
7929 } | |
7930 | |
7931 /* Function takes an UIImage and copies it into a flipped NSBitmapImageRep */ | |
7932 void _flip_image(UIImage *tmpimage, NSBitmapImageRep *image, NSSize size) | |
7933 { | |
7934 NSCompositingOperation op = DWCompositingOperationSourceOver; | |
7935 [NSGraphicsContext saveGraphicsState]; | |
7936 [NSGraphicsContext setCurrentContext:_dw_draw_context(image)]; | |
7937 [[[NSDictionary alloc] initWithObjectsAndKeys:image, NSGraphicsContextDestinationAttributeName, nil] autorelease]; | |
7938 /* Make a new transform */ | |
7939 NSAffineTransform *t = [NSAffineTransform transform]; | |
7940 | |
7941 /* By scaling Y negatively, we effectively flip the image */ | |
7942 [t scaleXBy:1.0 yBy:-1.0]; | |
7943 | |
7944 /* But we also have to translate it back by its height */ | |
7945 [t translateXBy:0.0 yBy:-size.height]; | |
7946 | |
7947 /* Apply the transform */ | |
7948 [t concat]; | |
7949 [tmpimage drawAtPoint:NSMakePoint(0, 0) fromRect:NSMakeRect(0, 0, size.width, size.height) | |
7950 operation:op fraction:1.0]; | |
7951 [NSGraphicsContext restoreGraphicsState]; | |
7952 } | |
7953 | |
7954 /* | |
7955 * Creates a pixmap from a file. | |
7956 * Parameters: | |
7957 * handle: Window handle the pixmap is associated with. | |
7958 * filename: Name of the file, omit extention to have | |
7959 * DW pick the appropriate file extension. | |
7960 * (BMP on OS/2 or Windows, XPM on Unix) | |
7961 * Returns: | |
7962 * A handle to a pixmap or NULL on failure. | |
7963 */ | |
7964 HPIXMAP API dw_pixmap_new_from_file(HWND handle, const char *filename) | |
7965 { | |
7966 HPIXMAP pixmap; | |
7967 DW_LOCAL_POOL_IN; | |
7968 char *ext = _dw_get_image_extension( filename ); | |
7969 | |
7970 if(!(pixmap = calloc(1,sizeof(struct _hpixmap)))) | |
7971 { | |
7972 DW_LOCAL_POOL_OUT; | |
7973 return NULL; | |
7974 } | |
7975 NSString *nstr = [ NSString stringWithUTF8String:filename ]; | |
7976 UIImage *tmpimage = [[[UIImage alloc] initWithContentsOfFile:nstr] autorelease]; | |
7977 if(!tmpimage && ext) | |
7978 { | |
7979 nstr = [nstr stringByAppendingString: [NSString stringWithUTF8String:ext]]; | |
7980 tmpimage = [[[UIImage alloc] initWithContentsOfFile:nstr] autorelease]; | |
7981 } | |
7982 if(!tmpimage) | |
7983 { | |
7984 DW_LOCAL_POOL_OUT; | |
7985 return NULL; | |
7986 } | |
7987 NSSize size = [tmpimage size]; | |
7988 NSBitmapImageRep *image = [[NSBitmapImageRep alloc] | |
7989 initWithBitmapDataPlanes:NULL | |
7990 pixelsWide:size.width | |
7991 pixelsHigh:size.height | |
7992 bitsPerSample:8 | |
7993 samplesPerPixel:4 | |
7994 hasAlpha:YES | |
7995 isPlanar:NO | |
7996 colorSpaceName:NSDeviceRGBColorSpace | |
7997 bytesPerRow:0 | |
7998 bitsPerPixel:0]; | |
7999 _flip_image(tmpimage, image, size); | |
8000 pixmap->width = size.width; | |
8001 pixmap->height = size.height; | |
8002 pixmap->image = image; | |
8003 pixmap->handle = handle; | |
8004 DW_LOCAL_POOL_OUT; | |
8005 return pixmap; | |
8006 } | |
8007 | |
8008 /* | |
8009 * Creates a pixmap from memory. | |
8010 * Parameters: | |
8011 * handle: Window handle the pixmap is associated with. | |
8012 * data: Source of the image data | |
8013 * (BMP on OS/2 or Windows, XPM on Unix) | |
8014 * le: length of data | |
8015 * Returns: | |
8016 * A handle to a pixmap or NULL on failure. | |
8017 */ | |
8018 HPIXMAP API dw_pixmap_new_from_data(HWND handle, const char *data, int len) | |
8019 { | |
8020 HPIXMAP pixmap; | |
8021 DW_LOCAL_POOL_IN; | |
8022 | |
8023 if(!(pixmap = calloc(1,sizeof(struct _hpixmap)))) | |
8024 { | |
8025 DW_LOCAL_POOL_OUT; | |
8026 return NULL; | |
8027 } | |
8028 NSData *thisdata = [NSData dataWithBytes:data length:len]; | |
8029 UIImage *tmpimage = [[[UIImage alloc] initWithData:thisdata] autorelease]; | |
8030 if(!tmpimage) | |
8031 { | |
8032 DW_LOCAL_POOL_OUT; | |
8033 return NULL; | |
8034 } | |
8035 NSSize size = [tmpimage size]; | |
8036 NSBitmapImageRep *image = [[NSBitmapImageRep alloc] | |
8037 initWithBitmapDataPlanes:NULL | |
8038 pixelsWide:size.width | |
8039 pixelsHigh:size.height | |
8040 bitsPerSample:8 | |
8041 samplesPerPixel:4 | |
8042 hasAlpha:YES | |
8043 isPlanar:NO | |
8044 colorSpaceName:NSDeviceRGBColorSpace | |
8045 bytesPerRow:0 | |
8046 bitsPerPixel:0]; | |
8047 _flip_image(tmpimage, image, size); | |
8048 pixmap->width = size.width; | |
8049 pixmap->height = size.height; | |
8050 pixmap->image = image; | |
8051 pixmap->handle = handle; | |
8052 DW_LOCAL_POOL_OUT; | |
8053 return pixmap; | |
8054 } | |
8055 | |
8056 /* | |
8057 * Sets the transparent color for a pixmap | |
8058 * Parameters: | |
8059 * pixmap: Handle to a pixmap returned by | |
8060 * dw_pixmap_new.. | |
8061 * color: transparent color | |
8062 * Note: This does nothing on Mac as transparency | |
8063 * is handled automatically | |
8064 */ | |
8065 void API dw_pixmap_set_transparent_color( HPIXMAP pixmap, ULONG color ) | |
8066 { | |
8067 /* Don't do anything */ | |
8068 } | |
8069 | |
8070 /* | |
8071 * Creates a pixmap from internal resource graphic specified by id. | |
8072 * Parameters: | |
8073 * handle: Window handle the pixmap is associated with. | |
8074 * id: Resource ID associated with requested pixmap. | |
8075 * Returns: | |
8076 * A handle to a pixmap or NULL on failure. | |
8077 */ | |
8078 HPIXMAP API dw_pixmap_grab(HWND handle, ULONG resid) | |
8079 { | |
8080 HPIXMAP pixmap; | |
8081 DW_LOCAL_POOL_IN; | |
8082 | |
8083 if(!(pixmap = calloc(1,sizeof(struct _hpixmap)))) | |
8084 { | |
8085 DW_LOCAL_POOL_OUT; | |
8086 return NULL; | |
8087 } | |
8088 | |
8089 NSBundle *bundle = [NSBundle mainBundle]; | |
8090 NSString *respath = [bundle resourcePath]; | |
8091 NSString *filepath = [respath stringByAppendingFormat:@"/%lu.png", resid]; | |
8092 UIImage *temp = [[UIImage alloc] initWithContentsOfFile:filepath]; | |
8093 | |
8094 if(temp) | |
8095 { | |
8096 NSSize size = [temp size]; | |
8097 NSBitmapImageRep *image = [[NSBitmapImageRep alloc] | |
8098 initWithBitmapDataPlanes:NULL | |
8099 pixelsWide:size.width | |
8100 pixelsHigh:size.height | |
8101 bitsPerSample:8 | |
8102 samplesPerPixel:4 | |
8103 hasAlpha:YES | |
8104 isPlanar:NO | |
8105 colorSpaceName:NSDeviceRGBColorSpace | |
8106 bytesPerRow:0 | |
8107 bitsPerPixel:0]; | |
8108 _flip_image(temp, image, size); | |
8109 pixmap->width = size.width; | |
8110 pixmap->height = size.height; | |
8111 pixmap->image = image; | |
8112 pixmap->handle = handle; | |
8113 [temp release]; | |
8114 return pixmap; | |
8115 } | |
8116 free(pixmap); | |
8117 DW_LOCAL_POOL_OUT; | |
8118 return NULL; | |
8119 } | |
8120 | |
8121 /* | |
8122 * Sets the font used by a specified pixmap. | |
8123 * Normally the pixmap font is obtained from the associated window handle. | |
8124 * However this can be used to override that, or for pixmaps with no window. | |
8125 * Parameters: | |
8126 * pixmap: Handle to a pixmap returned by dw_pixmap_new() or | |
8127 * passed to the application via a callback. | |
8128 * fontname: Name and size of the font in the form "size.fontname" | |
8129 * Returns: | |
8130 * DW_ERROR_NONE on success and DW_ERROR_GENERAL on failure. | |
8131 */ | |
8132 int API dw_pixmap_set_font(HPIXMAP pixmap, const char *fontname) | |
8133 { | |
8134 if(pixmap) | |
8135 { | |
8136 UIFont *font = _dw_font_by_name(fontname); | |
8137 | |
8138 if(font) | |
8139 { | |
8140 DW_LOCAL_POOL_IN; | |
8141 UIFont *oldfont = pixmap->font; | |
8142 [font retain]; | |
8143 pixmap->font = font; | |
8144 if(oldfont) | |
8145 [oldfont release]; | |
8146 DW_LOCAL_POOL_OUT; | |
8147 return DW_ERROR_NONE; | |
8148 } | |
8149 } | |
8150 return DW_ERROR_GENERAL; | |
8151 } | |
8152 | |
8153 /* | |
8154 * Destroys an allocated pixmap. | |
8155 * Parameters: | |
8156 * pixmap: Handle to a pixmap returned by | |
8157 * dw_pixmap_new.. | |
8158 */ | |
8159 void API dw_pixmap_destroy(HPIXMAP pixmap) | |
8160 { | |
8161 if(pixmap) | |
8162 { | |
8163 NSBitmapImageRep *image = (NSBitmapImageRep *)pixmap->image; | |
8164 UIFont *font = pixmap->font; | |
8165 DW_LOCAL_POOL_IN; | |
8166 [image release]; | |
8167 [font release]; | |
8168 free(pixmap); | |
8169 DW_LOCAL_POOL_OUT; | |
8170 } | |
8171 } | |
8172 | |
8173 /* | |
8174 * Copies from one item to another. | |
8175 * Parameters: | |
8176 * dest: Destination window handle. | |
8177 * destp: Destination pixmap. (choose only one). | |
8178 * xdest: X coordinate of destination. | |
8179 * ydest: Y coordinate of destination. | |
8180 * width: Width of area to copy. | |
8181 * height: Height of area to copy. | |
8182 * src: Source window handle. | |
8183 * srcp: Source pixmap. (choose only one). | |
8184 * xsrc: X coordinate of source. | |
8185 * ysrc: Y coordinate of source. | |
8186 */ | |
8187 void API dw_pixmap_bitblt(HWND dest, HPIXMAP destp, int xdest, int ydest, int width, int height, HWND src, HPIXMAP srcp, int xsrc, int ysrc) | |
8188 { | |
8189 dw_pixmap_stretch_bitblt(dest, destp, xdest, ydest, width, height, src, srcp, xsrc, ysrc, -1, -1); | |
8190 } | |
8191 | |
8192 /* | |
8193 * Copies from one surface to another allowing for stretching. | |
8194 * Parameters: | |
8195 * dest: Destination window handle. | |
8196 * destp: Destination pixmap. (choose only one). | |
8197 * xdest: X coordinate of destination. | |
8198 * ydest: Y coordinate of destination. | |
8199 * width: Width of the target area. | |
8200 * height: Height of the target area. | |
8201 * src: Source window handle. | |
8202 * srcp: Source pixmap. (choose only one). | |
8203 * xsrc: X coordinate of source. | |
8204 * ysrc: Y coordinate of source. | |
8205 * srcwidth: Width of area to copy. | |
8206 * srcheight: Height of area to copy. | |
8207 * Returns: | |
8208 * DW_ERROR_NONE on success and DW_ERROR_GENERAL on failure. | |
8209 */ | |
8210 int API dw_pixmap_stretch_bitblt(HWND dest, HPIXMAP destp, int xdest, int ydest, int width, int height, HWND src, HPIXMAP srcp, int xsrc, int ysrc, int srcwidth, int srcheight) | |
8211 { | |
8212 DWBitBlt *bltinfo; | |
8213 NSValue* bi; | |
8214 DW_LOCAL_POOL_IN; | |
8215 | |
8216 /* Sanity checks */ | |
8217 if((!dest && !destp) || (!src && !srcp) || | |
8218 ((srcwidth == -1 || srcheight == -1) && srcwidth != srcheight)) | |
8219 { | |
8220 DW_LOCAL_POOL_OUT; | |
8221 return DW_ERROR_GENERAL; | |
8222 } | |
8223 | |
8224 bltinfo = calloc(1, sizeof(DWBitBlt)); | |
8225 bi = [NSValue valueWithPointer:bltinfo]; | |
8226 | |
8227 /* Fill in the information */ | |
8228 bltinfo->dest = dest; | |
8229 bltinfo->src = src; | |
8230 bltinfo->xdest = xdest; | |
8231 bltinfo->ydest = ydest; | |
8232 bltinfo->width = width; | |
8233 bltinfo->height = height; | |
8234 bltinfo->xsrc = xsrc; | |
8235 bltinfo->ysrc = ysrc; | |
8236 bltinfo->srcwidth = srcwidth; | |
8237 bltinfo->srcheight = srcheight; | |
8238 | |
8239 if(destp) | |
8240 { | |
8241 bltinfo->dest = (id)destp->image; | |
8242 } | |
8243 if(srcp) | |
8244 { | |
8245 id object = bltinfo->src = (id)srcp->image; | |
8246 [object retain]; | |
8247 } | |
8248 [DWObj safeCall:@selector(doBitBlt:) withObject:bi]; | |
8249 DW_LOCAL_POOL_OUT; | |
8250 return DW_ERROR_NONE; | |
8251 } | |
8252 | |
8253 /* | |
8254 * Create a new static text window (widget) to be packed. | |
8255 * Not available under OS/2, eCS | |
8256 * Parameters: | |
8257 * text: The text to be display by the static text widget. | |
8258 * id: An ID to be used with dw_window_from_id() or 0L. | |
8259 */ | |
8260 HWND API dw_calendar_new(ULONG cid) | |
8261 { | |
8262 DWCalendar *calendar = [[DWCalendar alloc] init]; | |
8263 [calendar setDatePickerMode:DWDatePickerModeSingle]; | |
8264 [calendar setDatePickerStyle:DWDatePickerStyleClockAndCalendar]; | |
8265 [calendar setDatePickerElements:DWDatePickerElementFlagYearMonthDay]; | |
8266 [calendar setTag:cid]; | |
8267 [calendar setDateValue:[NSDate date]]; | |
8268 return calendar; | |
8269 } | |
8270 | |
8271 /* | |
8272 * Sets the current date of a calendar. | |
8273 * Parameters: | |
8274 * handle: The handle to the calendar returned by dw_calendar_new(). | |
8275 * year... | |
8276 */ | |
8277 void dw_calendar_set_date(HWND handle, unsigned int year, unsigned int month, unsigned int day) | |
8278 { | |
8279 DWCalendar *calendar = handle; | |
8280 NSDate *date; | |
8281 char buffer[101]; | |
8282 DW_LOCAL_POOL_IN; | |
8283 | |
8284 snprintf(buffer, 100, "%04d-%02d-%02d", year, month, day); | |
8285 | |
8286 NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; | |
8287 dateFormatter.dateFormat = @"yyyy-MM-dd"; | |
8288 | |
8289 date = [dateFormatter dateFromString:[NSString stringWithUTF8String:buffer]]; | |
8290 [calendar setDateValue:date]; | |
8291 [date release]; | |
8292 DW_LOCAL_POOL_OUT; | |
8293 } | |
8294 | |
8295 /* | |
8296 * Gets the current date of a calendar. | |
8297 * Parameters: | |
8298 * handle: The handle to the calendar returned by dw_calendar_new(). | |
8299 */ | |
8300 void dw_calendar_get_date(HWND handle, unsigned int *year, unsigned int *month, unsigned int *day) | |
8301 { | |
8302 DWCalendar *calendar = handle; | |
8303 DW_LOCAL_POOL_IN; | |
8304 NSCalendar *mycalendar = [[NSCalendar alloc] initWithCalendarIdentifier:DWCalendarIdentifierGregorian]; | |
8305 NSDate *date = [calendar dateValue]; | |
8306 NSDateComponents* components = [mycalendar components:DWCalendarUnitDay|DWCalendarUnitMonth|DWCalendarUnitYear fromDate:date]; | |
8307 *day = (unsigned int)[components day]; | |
8308 *month = (unsigned int)[components month]; | |
8309 *year = (unsigned int)[components year]; | |
8310 [mycalendar release]; | |
8311 DW_LOCAL_POOL_OUT; | |
8312 } | |
8313 | |
8314 /* | |
8315 * Causes the embedded HTML widget to take action. | |
8316 * Parameters: | |
8317 * handle: Handle to the window. | |
8318 * action: One of the DW_HTML_* constants. | |
8319 */ | |
8320 void API dw_html_action(HWND handle, int action) | |
8321 { | |
8322 DWWebView *html = handle; | |
8323 switch(action) | |
8324 { | |
8325 case DW_HTML_GOBACK: | |
8326 [html goBack]; | |
8327 break; | |
8328 case DW_HTML_GOFORWARD: | |
8329 [html goForward]; | |
8330 break; | |
8331 case DW_HTML_GOHOME: | |
8332 dw_html_url(handle, DW_HOME_URL); | |
8333 break; | |
8334 case DW_HTML_SEARCH: | |
8335 break; | |
8336 case DW_HTML_RELOAD: | |
8337 [html reload:html]; | |
8338 break; | |
8339 case DW_HTML_STOP: | |
8340 [html stopLoading:html]; | |
8341 break; | |
8342 case DW_HTML_PRINT: | |
8343 break; | |
8344 } | |
8345 } | |
8346 | |
8347 /* | |
8348 * Render raw HTML code in the embedded HTML widget.. | |
8349 * Parameters: | |
8350 * handle: Handle to the window. | |
8351 * string: String buffer containt HTML code to | |
8352 * be rendered. | |
8353 * Returns: | |
8354 * 0 on success. | |
8355 */ | |
8356 int API dw_html_raw(HWND handle, const char *string) | |
8357 { | |
8358 DWWebView *html = handle; | |
8359 [html loadHTMLString:[ NSString stringWithUTF8String:string ] baseURL:nil]; | |
8360 return DW_ERROR_NONE; | |
8361 } | |
8362 | |
8363 /* | |
8364 * Render file or web page in the embedded HTML widget.. | |
8365 * Parameters: | |
8366 * handle: Handle to the window. | |
8367 * url: Universal Resource Locator of the web or | |
8368 * file object to be rendered. | |
8369 * Returns: | |
8370 * 0 on success. | |
8371 */ | |
8372 int API dw_html_url(HWND handle, const char *url) | |
8373 { | |
8374 DWWebView *html = handle; | |
8375 [html loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[ NSString stringWithUTF8String:url ]]]]; | |
8376 return DW_ERROR_NONE; | |
8377 } | |
8378 | |
8379 /* | |
8380 * Executes the javascript contained in "script" in the HTML window. | |
8381 * Parameters: | |
8382 * handle: Handle to the HTML window. | |
8383 * script: Javascript code to execute. | |
8384 * scriptdata: Data passed to the signal handler. | |
8385 * Notes: A DW_SIGNAL_HTML_RESULT event will be raised with scriptdata. | |
8386 * Returns: | |
8387 * DW_ERROR_NONE (0) on success. | |
8388 */ | |
8389 int dw_html_javascript_run(HWND handle, const char *script, void *scriptdata) | |
8390 { | |
8391 DWWebView *html = handle; | |
8392 DW_LOCAL_POOL_IN; | |
8393 | |
8394 [html evaluateJavaScript:[NSString stringWithUTF8String:script] completionHandler:^(NSString *result, NSError *error) | |
8395 { | |
8396 void *params[2] = { result, scriptdata }; | |
8397 _event_handler(html, (NSEvent *)params, 18); | |
8398 }]; | |
8399 DW_LOCAL_POOL_OUT; | |
8400 return DW_ERROR_NONE; | |
8401 } | |
8402 | |
8403 /* | |
8404 * Create a new HTML window (widget) to be packed. | |
8405 * Not available under OS/2, eCS | |
8406 * Parameters: | |
8407 * text: The default text to be in the entryfield widget. | |
8408 * id: An ID to be used with dw_window_from_id() or 0L. | |
8409 */ | |
8410 DW_FUNCTION_DEFINITION(dw_html_new, HWND, ULONG cid) | |
8411 DW_FUNCTION_ADD_PARAM1(cid) | |
8412 DW_FUNCTION_RETURN(dw_html_new, HWND) | |
8413 DW_FUNCTION_RESTORE_PARAM1(DW_UNUSED(cid), ULONG) | |
8414 { | |
8415 DW_FUNCTION_INIT; | |
8416 DWWebView *web = [[DWWebView alloc] init]; | |
8417 web.navigationDelegate = web; | |
8418 /* [web setTag:cid]; Why doesn't this work? */ | |
8419 DW_FUNCTION_RETURN_THIS(web); | |
8420 } | |
8421 | |
8422 /* | |
8423 * Returns the current X and Y coordinates of the mouse pointer. | |
8424 * Parameters: | |
8425 * x: Pointer to variable to store X coordinate. | |
8426 * y: Pointer to variable to store Y coordinate. | |
8427 */ | |
8428 void API dw_pointer_query_pos(long *x, long *y) | |
8429 { | |
8430 NSPoint mouseLoc; | |
8431 mouseLoc = [NSEvent mouseLocation]; | |
8432 if(x) | |
8433 { | |
8434 *x = mouseLoc.x; | |
8435 } | |
8436 if(y) | |
8437 { | |
8438 *y = [[NSScreen mainScreen] frame].size.height - mouseLoc.y; | |
8439 } | |
8440 } | |
8441 | |
8442 /* | |
8443 * Sets the X and Y coordinates of the mouse pointer. | |
8444 * Parameters: | |
8445 * x: X coordinate. | |
8446 * y: Y coordinate. | |
8447 */ | |
8448 void API dw_pointer_set_pos(long x, long y) | |
8449 { | |
8450 /* From what I have read this isn't possible, agaist human interface rules */ | |
8451 } | |
8452 | |
8453 /* | |
8454 * Create a menu object to be popped up. | |
8455 * Parameters: | |
8456 * id: An ID to be used for getting the resource from the | |
8457 * resource file. | |
8458 */ | |
8459 HMENUI API dw_menu_new(ULONG cid) | |
8460 { | |
8461 NSMenu *menu = [[NSMenu alloc] init]; | |
8462 [menu setAutoenablesItems:NO]; | |
8463 /* [menu setTag:cid]; Why doesn't this work? */ | |
8464 return menu; | |
8465 } | |
8466 | |
8467 /* | |
8468 * Create a menubar on a window. | |
8469 * Parameters: | |
8470 * location: Handle of a window frame to be attached to. | |
8471 */ | |
8472 HMENUI API dw_menubar_new(HWND location) | |
8473 { | |
8474 UIWindow *window = location; | |
8475 NSMenu *windowmenu = _generate_main_menu(); | |
8476 [[window contentView] setMenu:windowmenu]; | |
8477 return (HMENUI)windowmenu; | |
8478 } | |
8479 | |
8480 /* | |
8481 * Destroys a menu created with dw_menubar_new or dw_menu_new. | |
8482 * Parameters: | |
8483 * menu: Handle of a menu. | |
8484 */ | |
8485 void API dw_menu_destroy(HMENUI *menu) | |
8486 { | |
8487 NSMenu *thismenu = *menu; | |
8488 DW_LOCAL_POOL_IN; | |
8489 [thismenu release]; | |
8490 DW_LOCAL_POOL_OUT; | |
8491 } | |
8492 | |
8493 /* Handle deprecation of convertScreenToBase in 10.10 yet still supporting | |
8494 * 10.6 and earlier since convertRectFromScreen was introduced in 10.7. | |
8495 */ | |
8496 NSPoint _windowPointFromScreen(id window, NSPoint p) | |
8497 { | |
8498 SEL crfs = NSSelectorFromString(@"convertRectFromScreen:"); | |
8499 | |
8500 if([window respondsToSelector:crfs]) | |
8501 { | |
8502 NSRect (* icrfs)(id, SEL, NSRect) = (NSRect (*)(id, SEL, NSRect))[window methodForSelector:crfs]; | |
8503 NSRect rect = icrfs(window, crfs, NSMakeRect(p.x, p.y, 1, 1)); | |
8504 return rect.origin; | |
8505 } | |
8506 else | |
8507 { | |
8508 SEL cstb = NSSelectorFromString(@"convertScreenToBase:"); | |
8509 | |
8510 if([window respondsToSelector:cstb]) | |
8511 { | |
8512 NSPoint (* icstb)(id, SEL, NSPoint) = (NSPoint (*)(id, SEL, NSPoint))[window methodForSelector:cstb]; | |
8513 return icstb(window, cstb, p); | |
8514 } | |
8515 } | |
8516 return NSMakePoint(0,0); | |
8517 } | |
8518 | |
8519 /* | |
8520 * Pops up a context menu at given x and y coordinates. | |
8521 * Parameters: | |
8522 * menu: The handle the the existing menu. | |
8523 * parent: Handle to the window initiating the popup. | |
8524 * x: X coordinate. | |
8525 * y: Y coordinate. | |
8526 */ | |
8527 void API dw_menu_popup(HMENUI *menu, HWND parent, int x, int y) | |
8528 { | |
8529 NSMenu *thismenu = (NSMenu *)*menu; | |
8530 id object = parent; | |
8531 UIView *view = [object isKindOfClass:[UIWindow class]] ? [object contentView] : parent; | |
8532 UIWindow *window = [view window]; | |
8533 NSEvent *event = [DWApp currentEvent]; | |
8534 if(!window) | |
8535 window = [event window]; | |
8536 [thismenu autorelease]; | |
8537 NSPoint p = NSMakePoint(x, [[NSScreen mainScreen] frame].size.height - y); | |
8538 NSEvent* fake = [NSEvent mouseEventWithType:DWEventTypeRightMouseDown | |
8539 location:_windowPointFromScreen(window, p) | |
8540 modifierFlags:0 | |
8541 timestamp:[event timestamp] | |
8542 windowNumber:[window windowNumber] | |
8543 context:[NSGraphicsContext currentContext] | |
8544 eventNumber:1 | |
8545 clickCount:1 | |
8546 pressure:0.0]; | |
8547 [NSMenu popUpContextMenu:thismenu withEvent:fake forView:view]; | |
8548 } | |
8549 | |
8550 char _removetilde(char *dest, const char *src) | |
8551 { | |
8552 int z, cur=0; | |
8553 char accel = '\0'; | |
8554 | |
8555 for(z=0;z<strlen(src);z++) | |
8556 { | |
8557 if(src[z] != '~') | |
8558 { | |
8559 dest[cur] = src[z]; | |
8560 cur++; | |
8561 } | |
8562 else | |
8563 { | |
8564 accel = src[z+1]; | |
8565 } | |
8566 } | |
8567 dest[cur] = 0; | |
8568 return accel; | |
8569 } | |
8570 | |
8571 /* | |
8572 * Adds a menuitem or submenu to an existing menu. | |
8573 * Parameters: | |
8574 * menu: The handle the the existing menu. | |
8575 * title: The title text on the menu item to be added. | |
8576 * id: An ID to be used for message passing. | |
8577 * flags: Extended attributes to set on the menu. | |
8578 * end: If TRUE memu is positioned at the end of the menu. | |
8579 * check: If TRUE menu is "check"able. | |
8580 * flags: Extended attributes to set on the menu. | |
8581 * submenu: Handle to an existing menu to be a submenu or NULL. | |
8582 */ | |
8583 HWND API dw_menu_append_item(HMENUI menux, const char *title, ULONG itemid, ULONG flags, int end, int check, HMENUI submenux) | |
8584 { | |
8585 NSMenu *menu = menux; | |
8586 NSMenu *submenu = submenux; | |
8587 DWMenuItem *item = NULL; | |
8588 if(strlen(title) == 0) | |
8589 { | |
8590 [menu addItem:[DWMenuItem separatorItem]]; | |
8591 } | |
8592 else | |
8593 { | |
8594 char accel[2]; | |
8595 char *newtitle = malloc(strlen(title)+1); | |
8596 NSString *nstr; | |
8597 | |
8598 accel[0] = _removetilde(newtitle, title); | |
8599 accel[1] = 0; | |
8600 | |
8601 nstr = [ NSString stringWithUTF8String:newtitle ]; | |
8602 free(newtitle); | |
8603 | |
8604 item = [[[DWMenuItem alloc] initWithTitle:nstr | |
8605 action:@selector(menuHandler:) | |
8606 keyEquivalent:[ NSString stringWithUTF8String:accel ]] autorelease]; | |
8607 [menu addItem:item]; | |
8608 | |
8609 [item setTag:itemid]; | |
8610 if(check) | |
8611 { | |
8612 [item setCheck:YES]; | |
8613 if(flags & DW_MIS_CHECKED) | |
8614 { | |
8615 [item setState:DWControlStateValueOn]; | |
8616 } | |
8617 } | |
8618 if(flags & DW_MIS_DISABLED) | |
8619 { | |
8620 [item setEnabled:NO]; | |
8621 } | |
8622 | |
8623 if(submenux) | |
8624 { | |
8625 [submenu setTitle:nstr]; | |
8626 [menu setSubmenu:submenu forItem:item]; | |
8627 } | |
8628 return item; | |
8629 } | |
8630 return item; | |
8631 } | |
8632 | |
8633 /* | |
8634 * Sets the state of a menu item check. | |
8635 * Deprecated; use dw_menu_item_set_state() | |
8636 * Parameters: | |
8637 * menu: The handle the the existing menu. | |
8638 * id: Menuitem id. | |
8639 * check: TRUE for checked FALSE for not checked. | |
8640 */ | |
8641 void API dw_menu_item_set_check(HMENUI menux, unsigned long itemid, int check) | |
8642 { | |
8643 id menu = menux; | |
8644 NSMenuItem *menuitem = (NSMenuItem *)[menu itemWithTag:itemid]; | |
8645 | |
8646 if(menuitem != nil) | |
8647 { | |
8648 if(check) | |
8649 { | |
8650 [menuitem setState:DWControlStateValueOn]; | |
8651 } | |
8652 else | |
8653 { | |
8654 [menuitem setState:DWControlStateValueOff]; | |
8655 } | |
8656 } | |
8657 } | |
8658 | |
8659 /* | |
8660 * Deletes the menu item specified. | |
8661 * Parameters: | |
8662 * menu: The handle to the menu in which the item was appended. | |
8663 * id: Menuitem id. | |
8664 * Returns: | |
8665 * DW_ERROR_NONE (0) on success or DW_ERROR_UNKNOWN on failure. | |
8666 */ | |
8667 int API dw_menu_delete_item(HMENUI menux, unsigned long itemid) | |
8668 { | |
8669 id menu = menux; | |
8670 NSMenuItem *menuitem = (NSMenuItem *)[menu itemWithTag:itemid]; | |
8671 | |
8672 if(menuitem != nil) | |
8673 { | |
8674 [menu removeItem:menuitem]; | |
8675 return DW_ERROR_NONE; | |
8676 } | |
8677 return DW_ERROR_UNKNOWN; | |
8678 } | |
8679 | |
8680 /* | |
8681 * Sets the state of a menu item. | |
8682 * Parameters: | |
8683 * menu: The handle to the existing menu. | |
8684 * id: Menuitem id. | |
8685 * flags: DW_MIS_ENABLED/DW_MIS_DISABLED | |
8686 * DW_MIS_CHECKED/DW_MIS_UNCHECKED | |
8687 */ | |
8688 void API dw_menu_item_set_state(HMENUI menux, unsigned long itemid, unsigned long state) | |
8689 { | |
8690 id menu = menux; | |
8691 NSMenuItem *menuitem = (NSMenuItem *)[menu itemWithTag:itemid]; | |
8692 | |
8693 if(menuitem != nil) | |
8694 { | |
8695 if(state & DW_MIS_CHECKED) | |
8696 { | |
8697 [menuitem setState:DWControlStateValueOn]; | |
8698 } | |
8699 else if(state & DW_MIS_UNCHECKED) | |
8700 { | |
8701 [menuitem setState:DWControlStateValueOff]; | |
8702 } | |
8703 if(state & DW_MIS_ENABLED) | |
8704 { | |
8705 [menuitem setEnabled:YES]; | |
8706 } | |
8707 else if(state & DW_MIS_DISABLED) | |
8708 { | |
8709 [menuitem setEnabled:NO]; | |
8710 } | |
8711 } | |
8712 } | |
8713 | |
8714 /* Gets the notebook page from associated ID */ | |
8715 DWNotebookPage *_notepage_from_id(DWNotebook *notebook, unsigned long pageid) | |
8716 { | |
8717 NSArray *pages = [notebook tabViewItems]; | |
8718 for(DWNotebookPage *notepage in pages) | |
8719 { | |
8720 if([notepage pageid] == pageid) | |
8721 { | |
8722 return notepage; | |
8723 } | |
8724 } | |
8725 return nil; | |
8726 } | |
8727 | |
8728 /* | |
8729 * Create a notebook object to be packed. | |
8730 * Parameters: | |
8731 * id: An ID to be used for getting the resource from the | |
8732 * resource file. | |
8733 */ | |
8734 HWND API dw_notebook_new(ULONG cid, int top) | |
8735 { | |
8736 DWNotebook *notebook = [[DWNotebook alloc] init]; | |
8737 [notebook setDelegate:notebook]; | |
8738 /* [notebook setTag:cid]; Why doesn't this work? */ | |
8739 return notebook; | |
8740 } | |
8741 | |
8742 /* | |
8743 * Adds a new page to specified notebook. | |
8744 * Parameters: | |
8745 * handle: Window (widget) handle. | |
8746 * flags: Any additional page creation flags. | |
8747 * front: If TRUE page is added at the beginning. | |
8748 */ | |
8749 unsigned long API dw_notebook_page_new(HWND handle, ULONG flags, int front) | |
8750 { | |
8751 DWNotebook *notebook = handle; | |
8752 NSInteger page = [notebook pageid]; | |
8753 DWNotebookPage *notepage = [[DWNotebookPage alloc] initWithIdentifier:[NSString stringWithFormat: @"pageid:%d", (int)page]]; | |
8754 [notepage setPageid:(int)page]; | |
8755 if(front) | |
8756 { | |
8757 [notebook insertTabViewItem:notepage atIndex:(NSInteger)0]; | |
8758 } | |
8759 else | |
8760 { | |
8761 [notebook addTabViewItem:notepage]; | |
8762 } | |
8763 [notepage autorelease]; | |
8764 [notebook setPageid:(int)(page+1)]; | |
8765 return (unsigned long)page; | |
8766 } | |
8767 | |
8768 /* | |
8769 * Remove a page from a notebook. | |
8770 * Parameters: | |
8771 * handle: Handle to the notebook widget. | |
8772 * pageid: ID of the page to be destroyed. | |
8773 */ | |
8774 void API dw_notebook_page_destroy(HWND handle, unsigned int pageid) | |
8775 { | |
8776 DWNotebook *notebook = handle; | |
8777 DWNotebookPage *notepage = _notepage_from_id(notebook, pageid); | |
8778 DW_LOCAL_POOL_IN; | |
8779 | |
8780 if(notepage != nil) | |
8781 { | |
8782 [notebook removeTabViewItem:notepage]; | |
8783 } | |
8784 DW_LOCAL_POOL_OUT; | |
8785 } | |
8786 | |
8787 /* | |
8788 * Queries the currently visible page ID. | |
8789 * Parameters: | |
8790 * handle: Handle to the notebook widget. | |
8791 */ | |
8792 unsigned long API dw_notebook_page_get(HWND handle) | |
8793 { | |
8794 DWNotebook *notebook = handle; | |
8795 DWNotebookPage *notepage = (DWNotebookPage *)[notebook selectedTabViewItem]; | |
8796 return [notepage pageid]; | |
8797 } | |
8798 | |
8799 /* | |
8800 * Sets the currently visibale page ID. | |
8801 * Parameters: | |
8802 * handle: Handle to the notebook widget. | |
8803 * pageid: ID of the page to be made visible. | |
8804 */ | |
8805 void API dw_notebook_page_set(HWND handle, unsigned int pageid) | |
8806 { | |
8807 DWNotebook *notebook = handle; | |
8808 DWNotebookPage *notepage = _notepage_from_id(notebook, pageid); | |
8809 | |
8810 if(notepage != nil) | |
8811 { | |
8812 [notebook selectTabViewItem:notepage]; | |
8813 } | |
8814 } | |
8815 | |
8816 /* | |
8817 * Sets the text on the specified notebook tab. | |
8818 * Parameters: | |
8819 * handle: Notebook handle. | |
8820 * pageid: Page ID of the tab to set. | |
8821 * text: Pointer to the text to set. | |
8822 */ | |
8823 void API dw_notebook_page_set_text(HWND handle, ULONG pageid, const char *text) | |
8824 { | |
8825 DWNotebook *notebook = handle; | |
8826 DWNotebookPage *notepage = _notepage_from_id(notebook, pageid); | |
8827 | |
8828 if(notepage != nil) | |
8829 { | |
8830 [notepage setLabel:[ NSString stringWithUTF8String:text ]]; | |
8831 } | |
8832 } | |
8833 | |
8834 /* | |
8835 * Sets the text on the specified notebook tab status area. | |
8836 * Parameters: | |
8837 * handle: Notebook handle. | |
8838 * pageid: Page ID of the tab to set. | |
8839 * text: Pointer to the text to set. | |
8840 */ | |
8841 void API dw_notebook_page_set_status_text(HWND handle, ULONG pageid, const char *text) | |
8842 { | |
8843 /* Note supported here... do nothing */ | |
8844 } | |
8845 | |
8846 /* | |
8847 * Packs the specified box into the notebook page. | |
8848 * Parameters: | |
8849 * handle: Handle to the notebook to be packed. | |
8850 * pageid: Page ID in the notebook which is being packed. | |
8851 * page: Box handle to be packed. | |
8852 */ | |
8853 void API dw_notebook_pack(HWND handle, ULONG pageid, HWND page) | |
8854 { | |
8855 DWNotebook *notebook = handle; | |
8856 DWNotebookPage *notepage = _notepage_from_id(notebook, pageid); | |
8857 | |
8858 if(notepage != nil) | |
8859 { | |
8860 HWND tmpbox = dw_box_new(DW_VERT, 0); | |
8861 DWBox *box = tmpbox; | |
8862 | |
8863 dw_box_pack_start(tmpbox, page, 0, 0, TRUE, TRUE, 0); | |
8864 [notepage setView:box]; | |
8865 [box autorelease]; | |
8866 } | |
8867 } | |
8868 | |
8869 /* | |
8870 * Create a new Window Frame. | |
8871 * Parameters: | |
8872 * owner: The Owner's window handle or HWND_DESKTOP. | |
8873 * title: The Window title. | |
8874 * flStyle: Style flags, see the PM reference. | |
8875 */ | |
8876 DW_FUNCTION_DEFINITION(dw_window_new, HWND, HWND hwndOwner, const char *title, ULONG flStyle) | |
8877 DW_FUNCTION_ADD_PARAM3(hwndOwner, title, flStyle) | |
8878 DW_FUNCTION_RETURN(dw_window_new, HWND) | |
8879 DW_FUNCTION_RESTORE_PARAM3(hwndOwner, HWND, title, char *, flStyle, ULONG) | |
8880 { | |
8881 DW_FUNCTION_INIT; | |
8882 NSRect frame = NSMakeRect(1,1,1,1); | |
8883 DWWindow *window = [[DWWindow alloc] | |
8884 initWithContentRect:frame | |
8885 styleMask:(flStyle) | |
8886 backing:NSBackingStoreBuffered | |
8887 defer:false]; | |
8888 | |
8889 [window setTitle:[ NSString stringWithUTF8String:title ]]; | |
8890 | |
8891 DWView *view = [[DWView alloc] init]; | |
8892 | |
8893 [window setContentView:view]; | |
8894 [window setDelegate:view]; | |
8895 [window setAutorecalculatesKeyViewLoop:YES]; | |
8896 [window setAcceptsMouseMovedEvents:YES]; | |
8897 [window setReleasedWhenClosed:YES]; | |
8898 [view autorelease]; | |
8899 | |
8900 /* Enable full screen mode on resizeable windows */ | |
8901 if(flStyle & DW_FCF_SIZEBORDER) | |
8902 { | |
8903 [window setCollectionBehavior:UIWindowCollectionBehaviorFullScreenPrimary]; | |
8904 } | |
8905 | |
8906 /* If it isn't a toplevel window... */ | |
8907 if(hwndOwner) | |
8908 { | |
8909 id object = hwndOwner; | |
8910 | |
8911 /* Check to see if the parent is an MDI window */ | |
8912 if([object isMemberOfClass:[DWMDI class]]) | |
8913 { | |
8914 /* Set the window level to be floating */ | |
8915 [window setLevel:NSFloatingWindowLevel]; | |
8916 [window setHidesOnDeactivate:YES]; | |
8917 } | |
8918 } | |
8919 DW_FUNCTION_RETURN_THIS(window); | |
8920 } | |
8921 | |
8922 /* | |
8923 * Call a function from the window (widget)'s context. | |
8924 * Parameters: | |
8925 * handle: Window handle of the widget. | |
8926 * function: Function pointer to be called. | |
8927 * data: Pointer to the data to be passed to the function. | |
8928 */ | |
8929 void API dw_window_function(HWND handle, void *function, void *data) | |
8930 { | |
8931 void **params = calloc(2, sizeof(void *)); | |
8932 NSValue *v; | |
8933 DW_LOCAL_POOL_IN; | |
8934 v = [NSValue valueWithPointer:params]; | |
8935 params[0] = function; | |
8936 params[1] = data; | |
8937 [DWObj performSelectorOnMainThread:@selector(doWindowFunc:) withObject:v waitUntilDone:YES]; | |
8938 free(params); | |
8939 DW_LOCAL_POOL_OUT; | |
8940 } | |
8941 | |
8942 | |
8943 /* | |
8944 * Changes the appearance of the mouse pointer. | |
8945 * Parameters: | |
8946 * handle: Handle to widget for which to change. | |
8947 * cursortype: ID of the pointer you want. | |
8948 */ | |
8949 void API dw_window_set_pointer(HWND handle, int pointertype) | |
8950 { | |
8951 id object = handle; | |
8952 | |
8953 if([ object isKindOfClass:[ UIView class ] ]) | |
8954 { | |
8955 UIView *view = handle; | |
8956 | |
8957 if(pointertype == DW_POINTER_DEFAULT) | |
8958 { | |
8959 [view discardCursorRects]; | |
8960 } | |
8961 else if(pointertype == DW_POINTER_ARROW) | |
8962 { | |
8963 NSRect rect = [view frame]; | |
8964 NSCursor *cursor = [NSCursor arrowCursor]; | |
8965 | |
8966 [view addCursorRect:rect cursor:cursor]; | |
8967 } | |
8968 /* No cursor for DW_POINTER_CLOCK? */ | |
8969 } | |
8970 } | |
8971 | |
8972 /* | |
8973 * Makes the window visible. | |
8974 * Parameters: | |
8975 * handle: The window handle to make visible. | |
8976 */ | |
8977 int API dw_window_show(HWND handle) | |
8978 { | |
8979 NSObject *object = handle; | |
8980 | |
8981 if([ object isMemberOfClass:[ DWWindow class ] ]) | |
8982 { | |
8983 DWWindow *window = handle; | |
8984 NSRect rect = [[window contentView] frame]; | |
8985 id defaultitem = [window initialFirstResponder]; | |
8986 | |
8987 if([window isMiniaturized]) | |
8988 { | |
8989 [window deminiaturize:nil]; | |
8990 } | |
8991 /* If we haven't been sized by a call.. */ | |
8992 if(rect.size.width <= 1 || rect.size.height <= 1) | |
8993 { | |
8994 /* Determine the contents size */ | |
8995 dw_window_set_size(handle, 0, 0); | |
8996 } | |
8997 /* If the position was not set... generate a default | |
8998 * default one in a similar pattern to SHELLPOSITION. | |
8999 */ | |
9000 if(![window shown]) | |
9001 { | |
9002 static int defaultx = 0, defaulty = 0; | |
9003 int cx = dw_screen_width(), cy = dw_screen_height(); | |
9004 int maxx = cx / 4, maxy = cy / 4; | |
9005 NSPoint point; | |
9006 | |
9007 rect = [window frame]; | |
9008 | |
9009 defaultx += 20; | |
9010 defaulty += 20; | |
9011 if(defaultx > maxx) | |
9012 defaultx = 20; | |
9013 if(defaulty > maxy) | |
9014 defaulty = 20; | |
9015 | |
9016 point.x = defaultx; | |
9017 /* Take into account menu bar and inverted Y */ | |
9018 point.y = cy - defaulty - (int)rect.size.height - 22; | |
9019 | |
9020 [window setFrameOrigin:point]; | |
9021 [window setShown:YES]; | |
9022 } | |
9023 [[window contentView] showWindow]; | |
9024 [window makeKeyAndOrderFront:nil]; | |
9025 | |
9026 if(!([window styleMask] & DWWindowStyleMaskResizable)) | |
9027 { | |
9028 /* Fix incorrect repeat in displaying textured windows */ | |
9029 [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMinYEdge]; | |
9030 [window setContentBorderThickness:0.0 forEdge:NSMinYEdge]; | |
9031 } | |
9032 if(defaultitem) | |
9033 { | |
9034 /* If there is a default item set, make it first responder */ | |
9035 [window makeFirstResponder:defaultitem]; | |
9036 } | |
9037 } | |
9038 return 0; | |
9039 } | |
9040 | |
9041 /* | |
9042 * Makes the window invisible. | |
9043 * Parameters: | |
9044 * handle: The window handle to make visible. | |
9045 */ | |
9046 int API dw_window_hide(HWND handle) | |
9047 { | |
9048 NSObject *object = handle; | |
9049 | |
9050 if([ object isKindOfClass:[ UIWindow class ] ]) | |
9051 { | |
9052 UIWindow *window = handle; | |
9053 | |
9054 [window orderOut:nil]; | |
9055 } | |
9056 return 0; | |
9057 } | |
9058 | |
9059 /* | |
9060 * Sets the colors used by a specified window (widget) handle. | |
9061 * Parameters: | |
9062 * handle: The window (widget) handle. | |
9063 * fore: Foreground color in DW_RGB format or a default color index. | |
9064 * back: Background color in DW_RGB format or a default color index. | |
9065 */ | |
9066 int API dw_window_set_color(HWND handle, ULONG fore, ULONG back) | |
9067 { | |
9068 id object = handle; | |
9069 unsigned long _fore = _get_color(fore); | |
9070 unsigned long _back = _get_color(back); | |
9071 UIColor *fg = NULL; | |
9072 UIColor *bg = NULL; | |
9073 | |
9074 /* Get the UIColor for non-default colors */ | |
9075 if(fore != DW_CLR_DEFAULT) | |
9076 { | |
9077 fg = [UIColor colorWithDeviceRed: DW_RED_VALUE(_fore)/255.0 green: DW_GREEN_VALUE(_fore)/255.0 blue: DW_BLUE_VALUE(_fore)/255.0 alpha: 1]; | |
9078 } | |
9079 if(back != DW_CLR_DEFAULT) | |
9080 { | |
9081 bg = [UIColor colorWithDeviceRed: DW_RED_VALUE(_back)/255.0 green: DW_GREEN_VALUE(_back)/255.0 blue: DW_BLUE_VALUE(_back)/255.0 alpha: 1]; | |
9082 } | |
9083 | |
9084 /* Get the textfield from the spinbutton */ | |
9085 if([object isMemberOfClass:[DWSpinButton class]]) | |
9086 { | |
9087 object = [object textfield]; | |
9088 } | |
9089 /* Get the cell on classes using NSCell */ | |
9090 if([object isKindOfClass:[UITextField class]]) | |
9091 { | |
9092 id cell = [object cell]; | |
9093 | |
9094 [object setTextColor:(fg ? fg : [UIColor controlTextColor])]; | |
9095 [cell setTextColor:(fg ? fg : [UIColor controlTextColor])]; | |
9096 } | |
9097 if([object isMemberOfClass:[DWButton class]]) | |
9098 { | |
9099 [object setTextColor:(fg ? fg : [UIColor controlTextColor])]; | |
9100 } | |
9101 if([object isKindOfClass:[UITextField class]] || [object isKindOfClass:[UIButton class]]) | |
9102 { | |
9103 id cell = [object cell]; | |
9104 | |
9105 [cell setBackgroundColor:(bg ? bg : [UIColor controlColor])]; | |
9106 } | |
9107 else if([object isMemberOfClass:[DWBox class]]) | |
9108 { | |
9109 DWBox *box = object; | |
9110 | |
9111 [box setColor:_back]; | |
9112 } | |
9113 else if([object isKindOfClass:[NSTableView class]]) | |
9114 { | |
9115 DWContainer *cont = handle; | |
9116 | |
9117 [cont setBackgroundColor:(bg ? bg : [UIColor controlBackgroundColor])]; | |
9118 [cont setForegroundColor:(fg ? fg : [UIColor controlTextColor])]; | |
9119 } | |
9120 else if([object isMemberOfClass:[DWMLE class]]) | |
9121 { | |
9122 DWMLE *mle = handle; | |
9123 [mle setBackgroundColor:(bg ? bg : [UIColor controlBackgroundColor])]; | |
9124 NSTextStorage *ts = [mle textStorage]; | |
9125 [ts setForegroundColor:(fg ? fg : [UIColor controlTextColor])]; | |
9126 } | |
9127 return 0; | |
9128 } | |
9129 | |
9130 /* | |
9131 * Sets the font used by a specified window (widget) handle. | |
9132 * Parameters: | |
9133 * handle: The window (widget) handle. | |
9134 * border: Size of the window border in pixels. | |
9135 */ | |
9136 int API dw_window_set_border(HWND handle, int border) | |
9137 { | |
9138 return 0; | |
9139 } | |
9140 | |
9141 /* | |
9142 * Sets the style of a given window (widget). | |
9143 * Parameters: | |
9144 * handle: Window (widget) handle. | |
9145 * width: New width in pixels. | |
9146 * height: New height in pixels. | |
9147 */ | |
9148 void API dw_window_set_style(HWND handle, ULONG style, ULONG mask) | |
9149 { | |
9150 id object = _text_handle(handle); | |
9151 | |
9152 if([object isMemberOfClass:[DWWindow class]]) | |
9153 { | |
9154 DWWindow *window = object; | |
9155 SEL sssm = NSSelectorFromString(@"setStyleMask"); | |
9156 | |
9157 if([window respondsToSelector:sssm]) | |
9158 { | |
9159 DWIMP issm = (DWIMP)[window methodForSelector:sssm]; | |
9160 int currentstyle = (int)[window styleMask]; | |
9161 int tmp; | |
9162 | |
9163 tmp = currentstyle | (int)mask; | |
9164 tmp ^= mask; | |
9165 tmp |= style; | |
9166 | |
9167 issm(window, sssm, tmp); | |
9168 } | |
9169 } | |
9170 else if([object isKindOfClass:[UITextField class]]) | |
9171 { | |
9172 UITextField *tf = object; | |
9173 DWTextFieldCell *cell = [tf cell]; | |
9174 | |
9175 [cell setAlignment:(style & 0xF)]; | |
9176 if(mask & DW_DT_VCENTER && [cell isMemberOfClass:[DWTextFieldCell class]]) | |
9177 { | |
9178 [cell setVCenter:(style & DW_DT_VCENTER ? YES : NO)]; | |
9179 } | |
9180 if(mask & DW_DT_WORDBREAK && [cell isMemberOfClass:[DWTextFieldCell class]]) | |
9181 { | |
9182 [cell setWraps:(style & DW_DT_WORDBREAK ? YES : NO)]; | |
9183 } | |
9184 } | |
9185 else if([object isMemberOfClass:[UITextView class]]) | |
9186 { | |
9187 UITextView *tv = handle; | |
9188 [tv setAlignment:(style & mask)]; | |
9189 } | |
9190 else if([object isMemberOfClass:[DWButton class]]) | |
9191 { | |
9192 DWButton *button = handle; | |
9193 | |
9194 if(mask & DW_BS_NOBORDER) | |
9195 { | |
9196 if(style & DW_BS_NOBORDER) | |
9197 [button setBordered:NO]; | |
9198 else | |
9199 [button setBordered:YES]; | |
9200 } | |
9201 } | |
9202 else if([object isMemberOfClass:[DWMenuItem class]]) | |
9203 { | |
9204 if(mask & (DW_MIS_CHECKED | DW_MIS_UNCHECKED)) | |
9205 { | |
9206 if(style & DW_MIS_CHECKED) | |
9207 [object setState:DWControlStateValueOn]; | |
9208 else if(style & DW_MIS_UNCHECKED) | |
9209 [object setState:DWControlStateValueOff]; | |
9210 } | |
9211 if(mask & (DW_MIS_ENABLED | DW_MIS_DISABLED)) | |
9212 { | |
9213 if(style & DW_MIS_ENABLED) | |
9214 [object setEnabled:YES]; | |
9215 else if(style & DW_MIS_DISABLED) | |
9216 [object setEnabled:NO]; | |
9217 } | |
9218 } | |
9219 } | |
9220 | |
9221 /* | |
9222 * Sets the current focus item for a window/dialog. | |
9223 * Parameters: | |
9224 * handle: Handle to the dialog item to be focused. | |
9225 * Remarks: | |
9226 * This is for use after showing the window/dialog. | |
9227 */ | |
9228 void API dw_window_set_focus(HWND handle) | |
9229 { | |
9230 id object = handle; | |
9231 | |
9232 [[object window] makeFirstResponder:object]; | |
9233 } | |
9234 | |
9235 /* | |
9236 * Sets the default focus item for a window/dialog. | |
9237 * Parameters: | |
9238 * window: Toplevel window or dialog. | |
9239 * defaultitem: Handle to the dialog item to be default. | |
9240 * Remarks: | |
9241 * This is for use before showing the window/dialog. | |
9242 */ | |
9243 void API dw_window_default(HWND handle, HWND defaultitem) | |
9244 { | |
9245 DWWindow *window = handle; | |
9246 id object = defaultitem; | |
9247 | |
9248 if([window isKindOfClass:[UIWindow class]] && [object isKindOfClass:[UIControl class]]) | |
9249 { | |
9250 [window setInitialFirstResponder:defaultitem]; | |
9251 } | |
9252 } | |
9253 | |
9254 /* | |
9255 * Sets window to click the default dialog item when an ENTER is pressed. | |
9256 * Parameters: | |
9257 * window: Window (widget) to look for the ENTER press. | |
9258 * next: Window (widget) to move to next (or click) | |
9259 */ | |
9260 void API dw_window_click_default(HWND handle, HWND next) | |
9261 { | |
9262 id object = handle; | |
9263 id control = next; | |
9264 | |
9265 if([object isMemberOfClass:[DWWindow class]]) | |
9266 { | |
9267 if([control isMemberOfClass:[DWButton class]]) | |
9268 { | |
9269 UIWindow *window = object; | |
9270 | |
9271 [window setDefaultButtonCell:[control cell]]; | |
9272 } | |
9273 } | |
9274 else | |
9275 { | |
9276 if([control isMemberOfClass:[DWSpinButton class]]) | |
9277 { | |
9278 control = [control textfield]; | |
9279 } | |
9280 else if([control isMemberOfClass:[DWComboBox class]]) | |
9281 { | |
9282 /* TODO: Figure out why the combobox can't be | |
9283 * focused using makeFirstResponder method. | |
9284 */ | |
9285 control = [control textfield]; | |
9286 } | |
9287 [object setClickDefault:control]; | |
9288 } | |
9289 } | |
9290 | |
9291 /* | |
9292 * Captures the mouse input to this window. | |
9293 * Parameters: | |
9294 * handle: Handle to receive mouse input. | |
9295 */ | |
9296 void API dw_window_capture(HWND handle) | |
9297 { | |
9298 /* Don't do anything for now */ | |
9299 } | |
9300 | |
9301 /* | |
9302 * Releases previous mouse capture. | |
9303 */ | |
9304 void API dw_window_release(void) | |
9305 { | |
9306 /* Don't do anything for now */ | |
9307 } | |
9308 | |
9309 /* | |
9310 * Changes a window's parent to newparent. | |
9311 * Parameters: | |
9312 * handle: The window handle to destroy. | |
9313 * newparent: The window's new parent window. | |
9314 */ | |
9315 void API dw_window_reparent(HWND handle, HWND newparent) | |
9316 { | |
9317 id object = handle; | |
9318 | |
9319 if([object isMemberOfClass:[DWWindow class]]) | |
9320 { | |
9321 /* We can't actually reparent on MacOS but if the | |
9322 * new parent is an MDI window, change to be a | |
9323 * floating window... otherwise set it to normal. | |
9324 */ | |
9325 UIWindow *window = handle; | |
9326 | |
9327 /* If it isn't a toplevel window... */ | |
9328 if(newparent) | |
9329 { | |
9330 object = newparent; | |
9331 | |
9332 /* Check to see if the parent is an MDI window */ | |
9333 if([object isMemberOfClass:[DWMDI class]]) | |
9334 { | |
9335 /* Set the window level to be floating */ | |
9336 [window setLevel:NSFloatingWindowLevel]; | |
9337 [window setHidesOnDeactivate:YES]; | |
9338 return; | |
9339 } | |
9340 } | |
9341 /* Set the window back to a normal window */ | |
9342 [window setLevel:NSNormalWindowLevel]; | |
9343 [window setHidesOnDeactivate:NO]; | |
9344 } | |
9345 } | |
9346 | |
9347 /* Allows the user to choose a font using the system's font chooser dialog. | |
9348 * Parameters: | |
9349 * currfont: current font | |
9350 * Returns: | |
9351 * A malloced buffer with the selected font or NULL on error. | |
9352 */ | |
9353 char * API dw_font_choose(const char *currfont) | |
9354 { | |
9355 /* Create the Font Chooser Dialog class. */ | |
9356 static DWFontChoose *fontDlg = nil; | |
9357 DWDialog *dialog; | |
9358 UIFont *font = nil; | |
9359 | |
9360 if(currfont) | |
9361 font = _dw_font_by_name(currfont); | |
9362 | |
9363 if(fontDlg) | |
9364 { | |
9365 dialog = [fontDlg dialog]; | |
9366 /* If someone is already waiting just return */ | |
9367 if(dialog) | |
9368 { | |
9369 return NULL; | |
9370 } | |
9371 } | |
9372 else | |
9373 { | |
9374 [UIFontManager setFontPanelFactory:[DWFontChoose class]]; | |
9375 fontDlg = (DWFontChoose *)[DWFontManager fontPanel:YES]; | |
9376 } | |
9377 | |
9378 dialog = dw_dialog_new(fontDlg); | |
9379 if(font) | |
9380 [DWFontManager setSelectedFont:font isMultiple:NO]; | |
9381 else | |
9382 [DWFontManager setSelectedFont:[UIFont fontWithName:@"Helvetica" size:9.0] isMultiple:NO]; | |
9383 [fontDlg setDialog:dialog]; | |
9384 [DWFontManager orderFrontFontPanel:DWFontManager]; | |
9385 | |
9386 | |
9387 /* Wait for them to pick a color */ | |
9388 font = (UIFont *)dw_dialog_wait(dialog); | |
9389 if(font) | |
9390 { | |
9391 NSString *fontname = [font displayName]; | |
9392 NSString *output = [NSString stringWithFormat:@"%d.%s", (int)[font pointSize], [fontname UTF8String]]; | |
9393 return strdup([output UTF8String]); | |
9394 } | |
9395 return NULL; | |
9396 } | |
9397 | |
9398 /* Internal function to return a pointer to an item struct | |
9399 * with information about the packing information regarding object. | |
9400 */ | |
9401 Item *_box_item(id object) | |
9402 { | |
9403 /* Find the item within the box it is packed into */ | |
9404 if([object isKindOfClass:[DWBox class]] || [object isKindOfClass:[DWGroupBox class]] || [object isKindOfClass:[UIControl class]]) | |
9405 { | |
9406 DWBox *parent = (DWBox *)[object superview]; | |
9407 | |
9408 /* Some controls are embedded in scrollviews... | |
9409 * so get the parent of the scrollview in that case. | |
9410 */ | |
9411 if([object isKindOfClass:[NSTableView class]] && [parent isMemberOfClass:[NSClipView class]]) | |
9412 { | |
9413 object = [parent superview]; | |
9414 parent = (DWBox *)[object superview]; | |
9415 } | |
9416 | |
9417 if([parent isKindOfClass:[DWBox class]] || [parent isKindOfClass:[DWGroupBox class]]) | |
9418 { | |
9419 Box *thisbox = [parent box]; | |
9420 Item *thisitem = thisbox->items; | |
9421 int z; | |
9422 | |
9423 for(z=0;z<thisbox->count;z++) | |
9424 { | |
9425 if(thisitem[z].hwnd == object) | |
9426 return &thisitem[z]; | |
9427 } | |
9428 } | |
9429 } | |
9430 return NULL; | |
9431 } | |
9432 | |
9433 /* | |
9434 * Sets the font used by a specified window (widget) handle. | |
9435 * Parameters: | |
9436 * handle: The window (widget) handle. | |
9437 * fontname: Name and size of the font in the form "size.fontname" | |
9438 */ | |
9439 int API dw_window_set_font(HWND handle, const char *fontname) | |
9440 { | |
9441 UIFont *font = fontname ? _dw_font_by_name(fontname) : | |
9442 (DWDefaultFont ? DWDefaultFont : [UIFont systemFontOfSize:[UIFont smallSystemFontSize]]); | |
9443 | |
9444 if(font) | |
9445 { | |
9446 id object = _text_handle(handle); | |
9447 if([object window]) | |
9448 { | |
9449 [object lockFocus]; | |
9450 [font set]; | |
9451 [object unlockFocus]; | |
9452 } | |
9453 if([object isMemberOfClass:[DWGroupBox class]]) | |
9454 { | |
9455 [object setTitleFont:font]; | |
9456 } | |
9457 else if([object isMemberOfClass:[DWMLE class]]) | |
9458 { | |
9459 DWMLE *mle = object; | |
9460 | |
9461 [[mle textStorage] setFont:font]; | |
9462 } | |
9463 else if([object isKindOfClass:[UIControl class]]) | |
9464 { | |
9465 [object setFont:font]; | |
9466 [[object cell] setFont:font]; | |
9467 } | |
9468 else if([object isMemberOfClass:[DWRender class]]) | |
9469 { | |
9470 DWRender *render = object; | |
9471 | |
9472 [render setFont:font]; | |
9473 } | |
9474 else | |
9475 return DW_ERROR_UNKNOWN; | |
9476 /* If we changed the text... */ | |
9477 Item *item = _box_item(handle); | |
9478 | |
9479 /* Check to see if any of the sizes need to be recalculated */ | |
9480 if(item && (item->origwidth == -1 || item->origheight == -1)) | |
9481 { | |
9482 _dw_control_size(handle, item->origwidth == -1 ? &item->width : NULL, item->origheight == -1 ? &item->height : NULL); | |
9483 /* Queue a redraw on the top-level window */ | |
9484 _dw_redraw([object window], TRUE); | |
9485 } | |
9486 return DW_ERROR_NONE; | |
9487 } | |
9488 return DW_ERROR_UNKNOWN; | |
9489 } | |
9490 | |
9491 /* | |
9492 * Returns the current font for the specified window | |
9493 * Parameters: | |
9494 * handle: The window handle from which to obtain the font. | |
9495 */ | |
9496 char * API dw_window_get_font(HWND handle) | |
9497 { | |
9498 id object = _text_handle(handle); | |
9499 UIFont *font = nil; | |
9500 | |
9501 if([object isMemberOfClass:[DWGroupBox class]]) | |
9502 { | |
9503 font = [object titleFont]; | |
9504 } | |
9505 else if([object isKindOfClass:[UIControl class]] || [object isMemberOfClass:[DWRender class]]) | |
9506 { | |
9507 font = [object font]; | |
9508 } | |
9509 if(font) | |
9510 { | |
9511 NSString *fontname = [font displayName]; | |
9512 NSString *output = [NSString stringWithFormat:@"%d.%s", (int)[font pointSize], [fontname UTF8String]]; | |
9513 return strdup([output UTF8String]); | |
9514 } | |
9515 return NULL; | |
9516 } | |
9517 | |
9518 /* | |
9519 * Destroys a window and all of it's children. | |
9520 * Parameters: | |
9521 * handle: The window handle to destroy. | |
9522 */ | |
9523 DW_FUNCTION_DEFINITION(dw_window_destroy, int, HWND handle) | |
9524 DW_FUNCTION_ADD_PARAM1(handle) | |
9525 DW_FUNCTION_RETURN(dw_window_destroy, int) | |
9526 DW_FUNCTION_RESTORE_PARAM1(handle, HWND) | |
9527 { | |
9528 DW_FUNCTION_INIT; | |
9529 DW_LOCAL_POOL_IN; | |
9530 id object = handle; | |
9531 int retval = 0; | |
9532 | |
9533 /* Handle destroying a top-level window */ | |
9534 if([ object isKindOfClass:[ UIWindow class ] ]) | |
9535 { | |
9536 DWWindow *window = handle; | |
9537 [window close]; | |
9538 } | |
9539 /* Handle removing menu items from menus */ | |
9540 else if([ object isKindOfClass:[NSMenuItem class]]) | |
9541 { | |
9542 NSMenu *menu = [object menu]; | |
9543 | |
9544 [menu removeItem:object]; | |
9545 } | |
9546 /* Handle destroying a control or box */ | |
9547 else if([object isKindOfClass:[UIView class]] || [object isKindOfClass:[UIControl class]]) | |
9548 { | |
9549 DWBox *parent = (DWBox *)[object superview]; | |
9550 | |
9551 /* Some controls are embedded in scrollviews... | |
9552 * so get the parent of the scrollview in that case. | |
9553 */ | |
9554 if(([object isKindOfClass:[NSTableView class]] || [object isMemberOfClass:[DWMLE class]]) | |
9555 && [parent isMemberOfClass:[NSClipView class]]) | |
9556 { | |
9557 object = [parent superview]; | |
9558 parent = (DWBox *)[object superview]; | |
9559 } | |
9560 | |
9561 if([parent isKindOfClass:[DWBox class]] || [parent isKindOfClass:[DWGroupBox class]]) | |
9562 { | |
9563 id window = [object window]; | |
9564 Box *thisbox = [parent box]; | |
9565 int z, index = -1; | |
9566 Item *tmpitem = NULL, *thisitem = thisbox->items; | |
9567 | |
9568 if(!thisitem) | |
9569 thisbox->count = 0; | |
9570 | |
9571 for(z=0;z<thisbox->count;z++) | |
9572 { | |
9573 if(thisitem[z].hwnd == object) | |
9574 index = z; | |
9575 } | |
9576 | |
9577 if(index != -1) | |
9578 { | |
9579 [object removeFromSuperview]; | |
9580 | |
9581 if(thisbox->count > 1) | |
9582 { | |
9583 tmpitem = calloc(sizeof(Item), (thisbox->count-1)); | |
9584 | |
9585 /* Copy all but the current entry to the new list */ | |
9586 for(z=0;z<index;z++) | |
9587 { | |
9588 tmpitem[z] = thisitem[z]; | |
9589 } | |
9590 for(z=index+1;z<thisbox->count;z++) | |
9591 { | |
9592 tmpitem[z-1] = thisitem[z]; | |
9593 } | |
9594 } | |
9595 | |
9596 thisbox->items = tmpitem; | |
9597 if(thisitem) | |
9598 free(thisitem); | |
9599 if(tmpitem) | |
9600 thisbox->count--; | |
9601 else | |
9602 thisbox->count = 0; | |
9603 | |
9604 /* Queue a redraw on the top-level window */ | |
9605 _dw_redraw(window, TRUE); | |
9606 } | |
9607 } | |
9608 } | |
9609 DW_LOCAL_POOL_OUT; | |
9610 DW_FUNCTION_RETURN_THIS(retval); | |
9611 } | |
9612 | |
9613 /* | |
9614 * Gets the text used for a given window. | |
9615 * Parameters: | |
9616 * handle: Handle to the window. | |
9617 * Returns: | |
9618 * text: The text associsated with a given window. | |
9619 */ | |
9620 DW_FUNCTION_DEFINITION(dw_window_get_text, char *, HWND handle) | |
9621 DW_FUNCTION_ADD_PARAM1(handle) | |
9622 DW_FUNCTION_RETURN(dw_window_get_text, char *) | |
9623 DW_FUNCTION_RESTORE_PARAM1(handle, HWND) | |
9624 { | |
9625 DW_FUNCTION_INIT; | |
9626 id object = _text_handle(handle); | |
9627 char *retval = NULL; | |
9628 | |
9629 if([ object isKindOfClass:[ UIWindow class ] ] || [ object isKindOfClass:[ UIButton class ] ]) | |
9630 { | |
9631 id window = object; | |
9632 NSString *nsstr = [ window title]; | |
9633 | |
9634 retval = strdup([ nsstr UTF8String ]); | |
9635 } | |
9636 else if([ object isKindOfClass:[ UIControl class ] ]) | |
9637 { | |
9638 UIControl *control = object; | |
9639 NSString *nsstr = [ control stringValue]; | |
9640 | |
9641 retval = strdup([ nsstr UTF8String ]); | |
9642 } | |
9643 DW_FUNCTION_RETURN_THIS(retval); | |
9644 } | |
9645 | |
9646 /* | |
9647 * Sets the text used for a given window. | |
9648 * Parameters: | |
9649 * handle: Handle to the window. | |
9650 * text: The text associsated with a given window. | |
9651 */ | |
9652 DW_FUNCTION_DEFINITION(dw_window_set_text, void, HWND handle, const char *text) | |
9653 DW_FUNCTION_ADD_PARAM2(handle, text) | |
9654 DW_FUNCTION_NO_RETURN(dw_window_set_text) | |
9655 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, text, char *) | |
9656 { | |
9657 DW_FUNCTION_INIT; | |
9658 id object = _text_handle(handle); | |
9659 | |
9660 if([ object isKindOfClass:[ UIWindow class ] ] || [ object isKindOfClass:[ UIButton class ] ]) | |
9661 [object setTitle:[ NSString stringWithUTF8String:text ]]; | |
9662 else if([ object isKindOfClass:[ UIControl class ] ]) | |
9663 { | |
9664 UIControl *control = object; | |
9665 [control setStringValue:[ NSString stringWithUTF8String:text ]]; | |
9666 } | |
9667 else if([object isMemberOfClass:[DWGroupBox class]]) | |
9668 { | |
9669 DWGroupBox *groupbox = object; | |
9670 [groupbox setTitle:[NSString stringWithUTF8String:text]]; | |
9671 } | |
9672 else | |
9673 return; | |
9674 /* If we changed the text... */ | |
9675 Item *item = _box_item(handle); | |
9676 | |
9677 /* Check to see if any of the sizes need to be recalculated */ | |
9678 if(item && (item->origwidth == -1 || item->origheight == -1)) | |
9679 { | |
9680 int newwidth, newheight; | |
9681 | |
9682 _dw_control_size(handle, &newwidth, &newheight); | |
9683 | |
9684 /* Only update the item and redraw the window if it changed */ | |
9685 if((item->origwidth == -1 && item->width != newwidth) || | |
9686 (item->origheight == -1 && item->height != newheight)) | |
9687 { | |
9688 if(item->origwidth == -1) | |
9689 item->width = newwidth; | |
9690 if(item->origheight == -1) | |
9691 item->height = newheight; | |
9692 /* Queue a redraw on the top-level window */ | |
9693 _dw_redraw([object window], TRUE); | |
9694 } | |
9695 } | |
9696 DW_FUNCTION_RETURN_NOTHING; | |
9697 } | |
9698 | |
9699 /* | |
9700 * Sets the text used for a given window's floating bubble help. | |
9701 * Parameters: | |
9702 * handle: Handle to the window (widget). | |
9703 * bubbletext: The text in the floating bubble tooltip. | |
9704 */ | |
9705 DW_FUNCTION_DEFINITION(dw_window_set_tooltip, void, HWND handle, const char *bubbletext) | |
9706 DW_FUNCTION_ADD_PARAM2(handle, bubbletext) | |
9707 DW_FUNCTION_NO_RETURN(dw_window_set_tooltip) | |
9708 DW_FUNCTION_RESTORE_PARAM2(handle, HWND, bubbletext, char *) | |
9709 { | |
9710 DW_FUNCTION_INIT; | |
9711 id object = handle; | |
9712 if(bubbletext && *bubbletext) | |
9713 [object setToolTip:[NSString stringWithUTF8String:bubbletext]]; | |
9714 else | |
9715 [object setToolTip:nil]; | |
9716 DW_FUNCTION_RETURN_NOTHING; | |
9717 } | |
9718 | |
9719 /* | |
9720 * Disables given window (widget). | |
9721 * Parameters: | |
9722 * handle: Handle to the window. | |
9723 */ | |
9724 DW_FUNCTION_DEFINITION(dw_window_disable, void, HWND handle) | |
9725 DW_FUNCTION_ADD_PARAM1(handle) | |
9726 DW_FUNCTION_NO_RETURN(dw_window_disable) | |
9727 DW_FUNCTION_RESTORE_PARAM1(handle, HWND) | |
9728 { | |
9729 DW_FUNCTION_INIT; | |
9730 id object = handle; | |
9731 | |
9732 if([object isMemberOfClass:[UIScrollView class]]) | |
9733 { | |
9734 UIScrollView *sv = handle; | |
9735 object = [sv documentView]; | |
9736 } | |
9737 if([object isKindOfClass:[UIControl class]] || [object isKindOfClass:[NSMenuItem class]]) | |
9738 { | |
9739 [object setEnabled:NO]; | |
9740 } | |
9741 if([object isKindOfClass:[UITextView class]]) | |
9742 { | |
9743 UITextView *mle = object; | |
9744 | |
9745 [mle setEditable:NO]; | |
9746 } | |
9747 DW_FUNCTION_RETURN_NOTHING; | |
9748 } | |
9749 | |
9750 /* | |
9751 * Enables given window (widget). | |
9752 * Parameters: | |
9753 * handle: Handle to the window. | |
9754 */ | |
9755 DW_FUNCTION_DEFINITION(dw_window_enable, void, HWND handle) | |
9756 DW_FUNCTION_ADD_PARAM1(handle) | |
9757 DW_FUNCTION_NO_RETURN(dw_window_enable) | |
9758 DW_FUNCTION_RESTORE_PARAM1(handle, HWND) | |
9759 { | |
9760 DW_FUNCTION_INIT; | |
9761 id object = handle; | |
9762 | |
9763 if([object isMemberOfClass:[UIScrollView class]]) | |
9764 { | |
9765 UIScrollView *sv = handle; | |
9766 object = [sv documentView]; | |
9767 } | |
9768 if([object isKindOfClass:[UIControl class]] || [object isKindOfClass:[NSMenuItem class]]) | |
9769 { | |
9770 [object setEnabled:YES]; | |
9771 } | |
9772 if([object isKindOfClass:[UITextView class]]) | |
9773 { | |
9774 UITextView *mle = object; | |
9775 | |
9776 [mle setEditable:YES]; | |
9777 } | |
9778 DW_FUNCTION_RETURN_NOTHING; | |
9779 } | |
9780 | |
9781 /* | |
9782 * Sets the bitmap used for a given static window. | |
9783 * Parameters: | |
9784 * handle: Handle to the window. | |
9785 * id: An ID to be used to specify the icon, | |
9786 * (pass 0 if you use the filename param) | |
9787 * filename: a path to a file (Bitmap on OS/2 or | |
9788 * Windows and a pixmap on Unix, pass | |
9789 * NULL if you use the id param) | |
9790 */ | |
9791 void API dw_window_set_bitmap_from_data(HWND handle, unsigned long cid, const char *data, int len) | |
9792 { | |
9793 id object = handle; | |
9794 | |
9795 if([ object isKindOfClass:[ UIImageView class ] ] || [ object isKindOfClass:[ UIButton class ]]) | |
9796 { | |
9797 if(data) | |
9798 { | |
9799 DW_LOCAL_POOL_IN; | |
9800 NSData *thisdata = [NSData dataWithBytes:data length:len]; | |
9801 UIImage *pixmap = [[[UIImage alloc] initWithData:thisdata] autorelease]; | |
9802 | |
9803 if(pixmap) | |
9804 { | |
9805 [object setImage:pixmap]; | |
9806 } | |
9807 /* If we changed the bitmap... */ | |
9808 Item *item = _box_item(handle); | |
9809 | |
9810 /* Check to see if any of the sizes need to be recalculated */ | |
9811 if(item && (item->origwidth == -1 || item->origheight == -1)) | |
9812 { | |
9813 _dw_control_size(handle, item->origwidth == -1 ? &item->width : NULL, item->origheight == -1 ? &item->height : NULL); | |
9814 /* Queue a redraw on the top-level window */ | |
9815 _dw_redraw([object window], TRUE); | |
9816 } | |
9817 DW_LOCAL_POOL_OUT; | |
9818 } | |
9819 else | |
9820 dw_window_set_bitmap(handle, cid, NULL); | |
9821 } | |
9822 } | |
9823 | |
9824 /* | |
9825 * Sets the bitmap used for a given static window. | |
9826 * Parameters: | |
9827 * handle: Handle to the window. | |
9828 * id: An ID to be used to specify the icon, | |
9829 * (pass 0 if you use the filename param) | |
9830 * filename: a path to a file (Bitmap on OS/2 or | |
9831 * Windows and a pixmap on Unix, pass | |
9832 * NULL if you use the id param) | |
9833 */ | |
9834 void API dw_window_set_bitmap(HWND handle, unsigned long resid, const char *filename) | |
9835 { | |
9836 id object = handle; | |
9837 DW_LOCAL_POOL_IN; | |
9838 | |
9839 if([ object isKindOfClass:[ UIImageView class ] ] || [ object isKindOfClass:[ UIButton class ]]) | |
9840 { | |
9841 UIImage *bitmap = nil; | |
9842 | |
9843 if(filename) | |
9844 { | |
9845 char *ext = _dw_get_image_extension( filename ); | |
9846 NSString *nstr = [ NSString stringWithUTF8String:filename ]; | |
9847 | |
9848 bitmap = [[[UIImage alloc] initWithContentsOfFile:nstr] autorelease]; | |
9849 | |
9850 if(!bitmap && ext) | |
9851 { | |
9852 nstr = [nstr stringByAppendingString: [NSString stringWithUTF8String:ext]]; | |
9853 bitmap = [[[UIImage alloc] initWithContentsOfFile:nstr] autorelease]; | |
9854 } | |
9855 } | |
9856 if(!bitmap && resid > 0 && resid < 65536) | |
9857 { | |
9858 bitmap = _dw_icon_load(resid); | |
9859 } | |
9860 | |
9861 if(bitmap) | |
9862 { | |
9863 [object setImage:bitmap]; | |
9864 | |
9865 /* If we changed the bitmap... */ | |
9866 Item *item = _box_item(handle); | |
9867 | |
9868 /* Check to see if any of the sizes need to be recalculated */ | |
9869 if(item && (item->origwidth == -1 || item->origheight == -1)) | |
9870 { | |
9871 _dw_control_size(handle, item->origwidth == -1 ? &item->width : NULL, item->origheight == -1 ? &item->height : NULL); | |
9872 /* Queue a redraw on the top-level window */ | |
9873 _dw_redraw([object window], TRUE); | |
9874 } | |
9875 } | |
9876 } | |
9877 DW_LOCAL_POOL_OUT; | |
9878 } | |
9879 | |
9880 /* | |
9881 * Sets the icon used for a given window. | |
9882 * Parameters: | |
9883 * handle: Handle to the window. | |
9884 * id: An ID to be used to specify the icon. | |
9885 */ | |
9886 void API dw_window_set_icon(HWND handle, HICN icon) | |
9887 { | |
9888 /* This isn't needed, it is loaded from the bundle */ | |
9889 } | |
9890 | |
9891 /* | |
9892 * Gets the child window handle with specified ID. | |
9893 * Parameters: | |
9894 * handle: Handle to the parent window. | |
9895 * id: Integer ID of the child. | |
9896 */ | |
9897 HWND API dw_window_from_id(HWND handle, int cid) | |
9898 { | |
9899 NSObject *object = handle; | |
9900 UIView *view = handle; | |
9901 if([ object isKindOfClass:[ UIWindow class ] ]) | |
9902 { | |
9903 UIWindow *window = handle; | |
9904 view = [window contentView]; | |
9905 } | |
9906 return [view viewWithTag:cid]; | |
9907 } | |
9908 | |
9909 /* | |
9910 * Minimizes or Iconifies a top-level window. | |
9911 * Parameters: | |
9912 * handle: The window handle to minimize. | |
9913 */ | |
9914 int API dw_window_minimize(HWND handle) | |
9915 { | |
9916 UIWindow *window = handle; | |
9917 [window miniaturize:nil]; | |
9918 return 0; | |
9919 } | |
9920 | |
9921 /* Causes entire window to be invalidated and redrawn. | |
9922 * Parameters: | |
9923 * handle: Toplevel window handle to be redrawn. | |
9924 */ | |
9925 void API dw_window_redraw(HWND handle) | |
9926 { | |
9927 DWWindow *window = handle; | |
9928 [window setRedraw:YES]; | |
9929 [[window contentView] showWindow]; | |
9930 [window setRedraw:NO]; | |
9931 } | |
9932 | |
9933 /* | |
9934 * Makes the window topmost. | |
9935 * Parameters: | |
9936 * handle: The window handle to make topmost. | |
9937 */ | |
9938 int API dw_window_raise(HWND handle) | |
9939 { | |
9940 UIWindow *window = handle; | |
9941 [window orderFront:nil]; | |
9942 return 0; | |
9943 } | |
9944 | |
9945 /* | |
9946 * Makes the window bottommost. | |
9947 * Parameters: | |
9948 * handle: The window handle to make bottommost. | |
9949 */ | |
9950 int API dw_window_lower(HWND handle) | |
9951 { | |
9952 UIWindow *window = handle; | |
9953 [window orderBack:nil]; | |
9954 return 0; | |
9955 } | |
9956 | |
9957 /* | |
9958 * Sets the size of a given window (widget). | |
9959 * Parameters: | |
9960 * handle: Window (widget) handle. | |
9961 * width: New width in pixels. | |
9962 * height: New height in pixels. | |
9963 */ | |
9964 DW_FUNCTION_DEFINITION(dw_window_set_size, void, HWND handle, ULONG width, ULONG height) | |
9965 DW_FUNCTION_ADD_PARAM3(handle, width, height) | |
9966 DW_FUNCTION_NO_RETURN(dw_window_set_size) | |
9967 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, width, ULONG, height, ULONG) | |
9968 { | |
9969 DW_FUNCTION_INIT; | |
9970 NSObject *object = handle; | |
9971 | |
9972 if([ object isMemberOfClass:[ DWWindow class ] ]) | |
9973 { | |
9974 DWWindow *window = handle; | |
9975 Box *thisbox; | |
9976 NSRect content, frame = NSMakeRect(0, 0, width, height); | |
9977 | |
9978 /* Convert the external frame size to internal content size */ | |
9979 content = [UIWindow contentRectForFrameRect:frame styleMask:[window styleMask]]; | |
9980 | |
9981 /* | |
9982 * The following is an attempt to dynamically size a window based on the size of its | |
9983 * children before realization. Only applicable when width or height is less than one. | |
9984 */ | |
9985 if((width < 1 || height < 1) && (thisbox = (Box *)[[window contentView] box])) | |
9986 { | |
9987 int depth = 0; | |
9988 | |
9989 /* Calculate space requirements */ | |
9990 _resize_box(thisbox, &depth, (int)width, (int)height, 1); | |
9991 | |
9992 /* Update components that need auto-sizing */ | |
9993 if(width < 1) content.size.width = thisbox->minwidth; | |
9994 if(height < 1) content.size.height = thisbox->minheight; | |
9995 } | |
9996 | |
9997 /* Finally set the size */ | |
9998 [window setContentSize:content.size]; | |
9999 } | |
10000 DW_FUNCTION_RETURN_NOTHING; | |
10001 } | |
10002 | |
10003 /* | |
10004 * Gets the size the system thinks the widget should be. | |
10005 * Parameters: | |
10006 * handle: Window handle of the item to be back. | |
10007 * width: Width in pixels of the item or NULL if not needed. | |
10008 * height: Height in pixels of the item or NULL if not needed. | |
10009 */ | |
10010 void API dw_window_get_preferred_size(HWND handle, int *width, int *height) | |
10011 { | |
10012 id object = handle; | |
10013 | |
10014 if([object isMemberOfClass:[DWWindow class]]) | |
10015 { | |
10016 Box *thisbox; | |
10017 | |
10018 if((thisbox = (Box *)[[object contentView] box])) | |
10019 { | |
10020 int depth = 0; | |
10021 NSRect frame; | |
10022 | |
10023 /* Calculate space requirements */ | |
10024 _resize_box(thisbox, &depth, 0, 0, 1); | |
10025 | |
10026 /* Figure out the border size */ | |
10027 frame = [UIWindow frameRectForContentRect:NSMakeRect(0, 0, thisbox->minwidth, thisbox->minheight) styleMask:[object styleMask]]; | |
10028 | |
10029 /* Return what was requested */ | |
10030 if(width) *width = frame.size.width; | |
10031 if(height) *height = frame.size.height; | |
10032 } | |
10033 } | |
10034 else if([object isMemberOfClass:[DWBox class]]) | |
10035 { | |
10036 Box *thisbox; | |
10037 | |
10038 if((thisbox = (Box *)[object box])) | |
10039 { | |
10040 int depth = 0; | |
10041 | |
10042 /* Calculate space requirements */ | |
10043 _resize_box(thisbox, &depth, 0, 0, 1); | |
10044 | |
10045 /* Return what was requested */ | |
10046 if(width) *width = thisbox->minwidth; | |
10047 if(height) *height = thisbox->minheight; | |
10048 } | |
10049 } | |
10050 else | |
10051 _dw_control_size(handle, width, height); | |
10052 } | |
10053 | |
10054 /* | |
10055 * Sets the gravity of a given window (widget). | |
10056 * Gravity controls which corner of the screen and window the position is relative to. | |
10057 * Parameters: | |
10058 * handle: Window (widget) handle. | |
10059 * horz: DW_GRAV_LEFT (default), DW_GRAV_RIGHT or DW_GRAV_CENTER. | |
10060 * vert: DW_GRAV_TOP (default), DW_GRAV_BOTTOM or DW_GRAV_CENTER. | |
10061 */ | |
10062 void API dw_window_set_gravity(HWND handle, int horz, int vert) | |
10063 { | |
10064 dw_window_set_data(handle, "_dw_grav_horz", DW_INT_TO_POINTER(horz)); | |
10065 dw_window_set_data(handle, "_dw_grav_vert", DW_INT_TO_POINTER(vert)); | |
10066 } | |
10067 | |
10068 /* Convert the coordinates based on gravity */ | |
10069 void _handle_gravity(HWND handle, long *x, long *y, unsigned long width, unsigned long height) | |
10070 { | |
10071 int horz = DW_POINTER_TO_INT(dw_window_get_data(handle, "_dw_grav_horz")); | |
10072 int vert = DW_POINTER_TO_INT(dw_window_get_data(handle, "_dw_grav_vert")); | |
10073 id object = handle; | |
10074 | |
10075 /* Do any gravity calculations */ | |
10076 if(horz || (vert & 0xf) != DW_GRAV_BOTTOM) | |
10077 { | |
10078 long newx = *x, newy = *y; | |
10079 | |
10080 /* Handle horizontal center gravity */ | |
10081 if((horz & 0xf) == DW_GRAV_CENTER) | |
10082 newx += ((dw_screen_width() / 2) - (width / 2)); | |
10083 /* Handle right gravity */ | |
10084 else if((horz & 0xf) == DW_GRAV_RIGHT) | |
10085 newx = dw_screen_width() - width - *x; | |
10086 /* Handle vertical center gravity */ | |
10087 if((vert & 0xf) == DW_GRAV_CENTER) | |
10088 newy += ((dw_screen_height() / 2) - (height / 2)); | |
10089 else if((vert & 0xf) == DW_GRAV_TOP) | |
10090 newy = dw_screen_height() - height - *y; | |
10091 | |
10092 /* Save the new values */ | |
10093 *x = newx; | |
10094 *y = newy; | |
10095 } | |
10096 /* Adjust the values to avoid Dock/Menubar if requested */ | |
10097 if((horz | vert) & DW_GRAV_OBSTACLES) | |
10098 { | |
10099 NSRect visiblerect = [[object screen] visibleFrame]; | |
10100 NSRect totalrect = [[object screen] frame]; | |
10101 | |
10102 if(horz & DW_GRAV_OBSTACLES) | |
10103 { | |
10104 if((horz & 0xf) == DW_GRAV_LEFT) | |
10105 *x += visiblerect.origin.x; | |
10106 else if((horz & 0xf) == DW_GRAV_RIGHT) | |
10107 *x -= (totalrect.origin.x + totalrect.size.width) - (visiblerect.origin.x + visiblerect.size.width); | |
10108 } | |
10109 if(vert & DW_GRAV_OBSTACLES) | |
10110 { | |
10111 if((vert & 0xf) == DW_GRAV_BOTTOM) | |
10112 *y += visiblerect.origin.y; | |
10113 else if((vert & 0xf) == DW_GRAV_TOP) | |
10114 *y -= (totalrect.origin.y + totalrect.size.height) - (visiblerect.origin.y + visiblerect.size.height); | |
10115 } | |
10116 } | |
10117 } | |
10118 | |
10119 /* | |
10120 * Sets the position of a given window (widget). | |
10121 * Parameters: | |
10122 * handle: Window (widget) handle. | |
10123 * x: X location from the bottom left. | |
10124 * y: Y location from the bottom left. | |
10125 */ | |
10126 DW_FUNCTION_DEFINITION(dw_window_set_pos, void, HWND handle, LONG x, LONG y) | |
10127 DW_FUNCTION_ADD_PARAM3(handle, x, y) | |
10128 DW_FUNCTION_NO_RETURN(dw_window_set_pos) | |
10129 DW_FUNCTION_RESTORE_PARAM3(handle, HWND, x, LONG, y, LONG) | |
10130 { | |
10131 DW_FUNCTION_INIT; | |
10132 NSObject *object = handle; | |
10133 | |
10134 if([ object isMemberOfClass:[ DWWindow class ] ]) | |
10135 { | |
10136 DWWindow *window = handle; | |
10137 NSPoint point; | |
10138 NSSize size = [[window contentView] frame].size; | |
10139 | |
10140 /* Can't position an unsized window, so attempt to auto-size */ | |
10141 if(size.width <= 1 || size.height <= 1) | |
10142 { | |
10143 /* Determine the contents size */ | |
10144 dw_window_set_size(handle, 0, 0); | |
10145 } | |
10146 | |
10147 size = [window frame].size; | |
10148 _handle_gravity(handle, &x, &y, (unsigned long)size.width, (unsigned long)size.height); | |
10149 | |
10150 point.x = x; | |
10151 point.y = y; | |
10152 | |
10153 [window setFrameOrigin:point]; | |
10154 /* Position set manually... don't auto-position */ | |
10155 [window setShown:YES]; | |
10156 } | |
10157 DW_FUNCTION_RETURN_NOTHING; | |
10158 } | |
10159 | |
10160 /* | |
10161 * Sets the position and size of a given window (widget). | |
10162 * Parameters: | |
10163 * handle: Window (widget) handle. | |
10164 * x: X location from the bottom left. | |
10165 * y: Y location from the bottom left. | |
10166 * width: Width of the widget. | |
10167 * height: Height of the widget. | |
10168 */ | |
10169 void API dw_window_set_pos_size(HWND handle, LONG x, LONG y, ULONG width, ULONG height) | |
10170 { | |
10171 dw_window_set_size(handle, width, height); | |
10172 dw_window_set_pos(handle, x, y); | |
10173 } | |
10174 | |
10175 /* | |
10176 * Gets the position and size of a given window (widget). | |
10177 * Parameters: | |
10178 * handle: Window (widget) handle. | |
10179 * x: X location from the bottom left. | |
10180 * y: Y location from the bottom left. | |
10181 * width: Width of the widget. | |
10182 * height: Height of the widget. | |
10183 */ | |
10184 void API dw_window_get_pos_size(HWND handle, LONG *x, LONG *y, ULONG *width, ULONG *height) | |
10185 { | |
10186 NSObject *object = handle; | |
10187 | |
10188 if([ object isKindOfClass:[ UIWindow class ] ]) | |
10189 { | |
10190 UIWindow *window = handle; | |
10191 NSRect rect = [window frame]; | |
10192 if(x) | |
10193 *x = rect.origin.x; | |
10194 if(y) | |
10195 *y = [[window screen] frame].size.height - rect.origin.y - rect.size.height; | |
10196 if(width) | |
10197 *width = rect.size.width; | |
10198 if(height) | |
10199 *height = rect.size.height; | |
10200 return; | |
10201 } | |
10202 else if([ object isKindOfClass:[ UIControl class ] ]) | |
10203 { | |
10204 UIControl *control = handle; | |
10205 NSRect rect = [control frame]; | |
10206 if(x) | |
10207 *x = rect.origin.x; | |
10208 if(y) | |
10209 *y = rect.origin.y; | |
10210 if(width) | |
10211 *width = rect.size.width; | |
10212 if(height) | |
10213 *height = rect.size.height; | |
10214 return; | |
10215 } | |
10216 } | |
10217 | |
10218 /* | |
10219 * Returns the width of the screen. | |
10220 */ | |
10221 int API dw_screen_width(void) | |
10222 { | |
10223 NSRect screenRect = [[NSScreen mainScreen] frame]; | |
10224 return screenRect.size.width; | |
10225 } | |
10226 | |
10227 /* | |
10228 * Returns the height of the screen. | |
10229 */ | |
10230 int API dw_screen_height(void) | |
10231 { | |
10232 NSRect screenRect = [[NSScreen mainScreen] frame]; | |
10233 return screenRect.size.height; | |
10234 } | |
10235 | |
10236 /* This should return the current color depth */ | |
10237 unsigned long API dw_color_depth_get(void) | |
10238 { | |
10239 UIWindowDepth screenDepth = [[NSScreen mainScreen] depth]; | |
10240 return NSBitsPerPixelFromDepth(screenDepth); | |
10241 } | |
10242 | |
10243 /* | |
10244 * Creates a new system notification if possible. | |
10245 * Parameters: | |
10246 * title: The short title of the notification. | |
10247 * imagepath: Path to an image to display or NULL if none. | |
10248 * description: A longer description of the notification, | |
10249 * or NULL if none is necessary. | |
10250 * Returns: | |
10251 * A handle to the notification which can be used to attach a "clicked" event if desired, | |
10252 * or NULL if it fails or notifications are not supported by the system. | |
10253 * Remarks: | |
10254 * This will create a system notification that will show in the notifaction panel | |
10255 * on supported systems, which may be clicked to perform another task. | |
10256 */ | |
10257 HWND dw_notification_new(const char *title, const char *imagepath, const char *description, ...) | |
10258 { | |
10259 char outbuf[1025] = {0}; | |
10260 HWND retval = NULL; | |
10261 | |
10262 if(description) | |
10263 { | |
10264 va_list args; | |
10265 | |
10266 va_start(args, description); | |
10267 vsnprintf(outbuf, 1024, description, args); | |
10268 va_end(args); | |
10269 } | |
10270 | |
10271 /* Configure the notification's payload. */ | |
10272 if (@available(iOS 10.0, *)) | |
10273 { | |
10274 if([[NSBundle mainBundle] bundleIdentifier] != nil) | |
10275 { | |
10276 UNMutableNotificationContent* notification = [[UNMutableNotificationContent alloc] init]; | |
10277 | |
10278 if(notification) | |
10279 { | |
10280 notification.title = [NSString stringWithUTF8String:title]; | |
10281 if(description) | |
10282 notification.body = [NSString stringWithUTF8String:outbuf]; | |
10283 if(imagepath) | |
10284 { | |
10285 NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:imagepath]]; | |
10286 NSError *error; | |
10287 UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:@"imageID" | |
10288 URL:url | |
10289 options:nil | |
10290 error:&error]; | |
10291 if(attachment) | |
10292 notification.attachments = @[attachment]; | |
10293 } | |
10294 retval = notification; | |
10295 } | |
10296 } | |
10297 } | |
10298 return retval; | |
10299 } | |
10300 | |
10301 /* | |
10302 * Sends a notification created by dw_notification_new() after attaching signal handler. | |
10303 * Parameters: | |
10304 * notification: The handle to the notification returned by dw_notification_new(). | |
10305 * Returns: | |
10306 * DW_ERROR_NONE on success, DW_ERROR_UNKNOWN on error or not supported. | |
10307 */ | |
10308 int dw_notification_send(HWND notification) | |
10309 { | |
10310 if(notification) | |
10311 { | |
10312 NSString *notid = [NSString stringWithFormat:@"dw-notification-%llu", DW_POINTER_TO_ULONGLONG(notification)]; | |
10313 | |
10314 /* Schedule the notification. */ | |
10315 if (@available(iOS 10.0, *)) | |
10316 { | |
10317 if([[NSBundle mainBundle] bundleIdentifier] != nil) | |
10318 { | |
10319 UNMutableNotificationContent* content = (UNMutableNotificationContent *)notification; | |
10320 UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:notid content:content trigger:nil]; | |
10321 | |
10322 UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter]; | |
10323 [center addNotificationRequest:request withCompletionHandler:nil]; | |
10324 } | |
10325 } | |
10326 return DW_ERROR_NONE; | |
10327 } | |
10328 return DW_ERROR_UNKNOWN; | |
10329 } | |
10330 | |
10331 | |
10332 /* | |
10333 * Returns some information about the current operating environment. | |
10334 * Parameters: | |
10335 * env: Pointer to a DWEnv struct. | |
10336 */ | |
10337 void dw_environment_query(DWEnv *env) | |
10338 { | |
10339 memset(env, '\0', sizeof(DWEnv)); | |
10340 strcpy(env->osName, "iOS"); | |
10341 | |
10342 strncpy(env->buildDate, __DATE__, sizeof(env->buildDate)-1); | |
10343 strncpy(env->buildTime, __TIME__, sizeof(env->buildTime)-1); | |
10344 strncpy(env->htmlEngine, "WEBKIT", sizeof(env->htmlEngine)-1); | |
10345 env->DWMajorVersion = DW_MAJOR_VERSION; | |
10346 env->DWMinorVersion = DW_MINOR_VERSION; | |
10347 #ifdef VER_REV | |
10348 env->DWSubVersion = VER_REV; | |
10349 #else | |
10350 env->DWSubVersion = DW_SUB_VERSION; | |
10351 #endif | |
10352 | |
10353 env->MajorVersion = DWOSMajor; | |
10354 env->MinorVersion = DWOSMinor; | |
10355 env->MajorBuild = DWOSBuild; | |
10356 } | |
10357 | |
10358 /* | |
10359 * Emits a beep. | |
10360 * Parameters: | |
10361 * freq: Frequency. | |
10362 * dur: Duration. | |
10363 */ | |
10364 void API dw_beep(int freq, int dur) | |
10365 { | |
10366 NSBeep(); | |
10367 } | |
10368 | |
10369 /* Call this after drawing to the screen to make sure | |
10370 * anything you have drawn is visible. | |
10371 */ | |
10372 void API dw_flush(void) | |
10373 { | |
10374 /* This may need to be thread specific */ | |
10375 [DWObj performSelectorOnMainThread:@selector(doFlush:) withObject:nil waitUntilDone:NO]; | |
10376 } | |
10377 | |
10378 /* Functions for managing the user data lists that are associated with | |
10379 * a given window handle. Used in dw_window_set_data() and | |
10380 * dw_window_get_data(). | |
10381 */ | |
10382 UserData *_find_userdata(UserData **root, const char *varname) | |
10383 { | |
10384 UserData *tmp = *root; | |
10385 | |
10386 while(tmp) | |
10387 { | |
10388 if(strcasecmp(tmp->varname, varname) == 0) | |
10389 return tmp; | |
10390 tmp = tmp->next; | |
10391 } | |
10392 return NULL; | |
10393 } | |
10394 | |
10395 int _new_userdata(UserData **root, const char *varname, void *data) | |
10396 { | |
10397 UserData *new = _find_userdata(root, varname); | |
10398 | |
10399 if(new) | |
10400 { | |
10401 new->data = data; | |
10402 return TRUE; | |
10403 } | |
10404 else | |
10405 { | |
10406 new = malloc(sizeof(UserData)); | |
10407 if(new) | |
10408 { | |
10409 new->varname = strdup(varname); | |
10410 new->data = data; | |
10411 | |
10412 new->next = NULL; | |
10413 | |
10414 if (!*root) | |
10415 *root = new; | |
10416 else | |
10417 { | |
10418 UserData *prev = *root, *tmp = prev->next; | |
10419 | |
10420 while(tmp) | |
10421 { | |
10422 prev = tmp; | |
10423 tmp = tmp->next; | |
10424 } | |
10425 prev->next = new; | |
10426 } | |
10427 return TRUE; | |
10428 } | |
10429 } | |
10430 return FALSE; | |
10431 } | |
10432 | |
10433 int _remove_userdata(UserData **root, const char *varname, int all) | |
10434 { | |
10435 UserData *prev = NULL, *tmp = *root; | |
10436 | |
10437 while(tmp) | |
10438 { | |
10439 if(all || strcasecmp(tmp->varname, varname) == 0) | |
10440 { | |
10441 if(!prev) | |
10442 { | |
10443 *root = tmp->next; | |
10444 free(tmp->varname); | |
10445 free(tmp); | |
10446 if(!all) | |
10447 return 0; | |
10448 tmp = *root; | |
10449 } | |
10450 else | |
10451 { | |
10452 /* If all is true we should | |
10453 * never get here. | |
10454 */ | |
10455 prev->next = tmp->next; | |
10456 free(tmp->varname); | |
10457 free(tmp); | |
10458 return 0; | |
10459 } | |
10460 } | |
10461 else | |
10462 { | |
10463 prev = tmp; | |
10464 tmp = tmp->next; | |
10465 } | |
10466 } | |
10467 return 0; | |
10468 } | |
10469 | |
10470 /* | |
10471 * Add a named user data item to a window handle. | |
10472 * Parameters: | |
10473 * window: Window handle of signal to be called back. | |
10474 * dataname: A string pointer identifying which signal to be hooked. | |
10475 * data: User data to be passed to the handler function. | |
10476 */ | |
10477 void dw_window_set_data(HWND window, const char *dataname, void *data) | |
10478 { | |
10479 id object = window; | |
10480 if([object isMemberOfClass:[DWWindow class]]) | |
10481 { | |
10482 UIWindow *win = window; | |
10483 object = [win contentView]; | |
10484 } | |
10485 else if([object isMemberOfClass:[UIScrollView class]]) | |
10486 { | |
10487 UIScrollView *sv = window; | |
10488 object = [sv documentView]; | |
10489 } | |
10490 WindowData *blah = (WindowData *)[object userdata]; | |
10491 | |
10492 if(!blah) | |
10493 { | |
10494 if(!dataname) | |
10495 return; | |
10496 | |
10497 blah = calloc(1, sizeof(WindowData)); | |
10498 [object setUserdata:blah]; | |
10499 } | |
10500 | |
10501 if(data) | |
10502 _new_userdata(&(blah->root), dataname, data); | |
10503 else | |
10504 { | |
10505 if(dataname) | |
10506 _remove_userdata(&(blah->root), dataname, FALSE); | |
10507 else | |
10508 _remove_userdata(&(blah->root), NULL, TRUE); | |
10509 } | |
10510 } | |
10511 | |
10512 /* | |
10513 * Gets a named user data item to a window handle. | |
10514 * Parameters: | |
10515 * window: Window handle of signal to be called back. | |
10516 * dataname: A string pointer identifying which signal to be hooked. | |
10517 * data: User data to be passed to the handler function. | |
10518 */ | |
10519 void *dw_window_get_data(HWND window, const char *dataname) | |
10520 { | |
10521 id object = window; | |
10522 if([object isMemberOfClass:[DWWindow class]]) | |
10523 { | |
10524 UIWindow *win = window; | |
10525 object = [win contentView]; | |
10526 } | |
10527 else if([object isMemberOfClass:[UIScrollView class]]) | |
10528 { | |
10529 UIScrollView *sv = window; | |
10530 object = [sv documentView]; | |
10531 } | |
10532 WindowData *blah = (WindowData *)[object userdata]; | |
10533 | |
10534 if(blah && blah->root && dataname) | |
10535 { | |
10536 UserData *ud = _find_userdata(&(blah->root), dataname); | |
10537 if(ud) | |
10538 return ud->data; | |
10539 } | |
10540 return NULL; | |
10541 } | |
10542 | |
10543 #define DW_TIMER_MAX 64 | |
10544 NSTimer *DWTimers[DW_TIMER_MAX]; | |
10545 | |
10546 /* | |
10547 * Add a callback to a timer event. | |
10548 * Parameters: | |
10549 * interval: Milliseconds to delay between calls. | |
10550 * sigfunc: The pointer to the function to be used as the callback. | |
10551 * data: User data to be passed to the handler function. | |
10552 * Returns: | |
10553 * Timer ID for use with dw_timer_disconnect(), 0 on error. | |
10554 */ | |
10555 int API dw_timer_connect(int interval, void *sigfunc, void *data) | |
10556 { | |
10557 int z; | |
10558 | |
10559 for(z=0;z<DW_TIMER_MAX;z++) | |
10560 { | |
10561 if(!DWTimers[z]) | |
10562 { | |
10563 break; | |
10564 } | |
10565 } | |
10566 | |
10567 if(sigfunc && !DWTimers[z]) | |
10568 { | |
10569 NSTimeInterval seconds = (double)interval / 1000.0; | |
10570 NSTimer *thistimer = DWTimers[z] = [NSTimer scheduledTimerWithTimeInterval:seconds target:DWHandler selector:@selector(runTimer:) userInfo:nil repeats:YES]; | |
10571 _new_signal(0, thistimer, z+1, sigfunc, NULL, data); | |
10572 return z+1; | |
10573 } | |
10574 return 0; | |
10575 } | |
10576 | |
10577 /* | |
10578 * Removes timer callback. | |
10579 * Parameters: | |
10580 * id: Timer ID returned by dw_timer_connect(). | |
10581 */ | |
10582 void API dw_timer_disconnect(int timerid) | |
10583 { | |
10584 SignalHandler *prev = NULL, *tmp = Root; | |
10585 NSTimer *thistimer; | |
10586 | |
10587 /* 0 is an invalid timer ID */ | |
10588 if(timerid < 1 || !DWTimers[timerid-1]) | |
10589 return; | |
10590 | |
10591 thistimer = DWTimers[timerid-1]; | |
10592 DWTimers[timerid-1] = nil; | |
10593 | |
10594 [thistimer invalidate]; | |
10595 | |
10596 while(tmp) | |
10597 { | |
10598 if(tmp->id == timerid && tmp->window == thistimer) | |
10599 { | |
10600 if(prev) | |
10601 { | |
10602 prev->next = tmp->next; | |
10603 free(tmp); | |
10604 tmp = prev->next; | |
10605 } | |
10606 else | |
10607 { | |
10608 Root = tmp->next; | |
10609 free(tmp); | |
10610 tmp = Root; | |
10611 } | |
10612 } | |
10613 else | |
10614 { | |
10615 prev = tmp; | |
10616 tmp = tmp->next; | |
10617 } | |
10618 } | |
10619 } | |
10620 | |
10621 /* | |
10622 * Add a callback to a window event. | |
10623 * Parameters: | |
10624 * window: Window handle of signal to be called back. | |
10625 * signame: A string pointer identifying which signal to be hooked. | |
10626 * sigfunc: The pointer to the function to be used as the callback. | |
10627 * data: User data to be passed to the handler function. | |
10628 */ | |
10629 void API dw_signal_connect(HWND window, const char *signame, void *sigfunc, void *data) | |
10630 { | |
10631 dw_signal_connect_data(window, signame, sigfunc, NULL, data); | |
10632 } | |
10633 | |
10634 /* | |
10635 * Add a callback to a window event with a closure callback. | |
10636 * Parameters: | |
10637 * window: Window handle of signal to be called back. | |
10638 * signame: A string pointer identifying which signal to be hooked. | |
10639 * sigfunc: The pointer to the function to be used as the callback. | |
10640 * discfunc: The pointer to the function called when this handler is removed. | |
10641 * data: User data to be passed to the handler function. | |
10642 */ | |
10643 void API dw_signal_connect_data(HWND window, const char *signame, void *sigfunc, void *discfunc, void *data) | |
10644 { | |
10645 ULONG message = 0, msgid = 0; | |
10646 | |
10647 /* Handle special case of application delete signal */ | |
10648 if(!window && signame && strcmp(signame, DW_SIGNAL_DELETE) == 0) | |
10649 { | |
10650 window = DWApp; | |
10651 } | |
10652 | |
10653 if(window && signame && sigfunc) | |
10654 { | |
10655 if((message = _findsigmessage(signame)) != 0) | |
10656 { | |
10657 _new_signal(message, window, (int)msgid, sigfunc, discfunc, data); | |
10658 } | |
10659 } | |
10660 } | |
10661 | |
10662 /* | |
10663 * Removes callbacks for a given window with given name. | |
10664 * Parameters: | |
10665 * window: Window handle of callback to be removed. | |
10666 */ | |
10667 void API dw_signal_disconnect_by_name(HWND window, const char *signame) | |
10668 { | |
10669 SignalHandler *prev = NULL, *tmp = Root; | |
10670 ULONG message; | |
10671 | |
10672 if(!window || !signame || (message = _findsigmessage(signame)) == 0) | |
10673 return; | |
10674 | |
10675 while(tmp) | |
10676 { | |
10677 if(tmp->window == window && tmp->message == message) | |
10678 { | |
10679 void (*discfunc)(HWND, void *) = tmp->discfunction; | |
10680 | |
10681 if(discfunc) | |
10682 { | |
10683 discfunc(tmp->window, tmp->data); | |
10684 } | |
10685 | |
10686 if(prev) | |
10687 { | |
10688 prev->next = tmp->next; | |
10689 free(tmp); | |
10690 tmp = prev->next; | |
10691 } | |
10692 else | |
10693 { | |
10694 Root = tmp->next; | |
10695 free(tmp); | |
10696 tmp = Root; | |
10697 } | |
10698 } | |
10699 else | |
10700 { | |
10701 prev = tmp; | |
10702 tmp = tmp->next; | |
10703 } | |
10704 } | |
10705 } | |
10706 | |
10707 /* | |
10708 * Removes all callbacks for a given window. | |
10709 * Parameters: | |
10710 * window: Window handle of callback to be removed. | |
10711 */ | |
10712 void API dw_signal_disconnect_by_window(HWND window) | |
10713 { | |
10714 SignalHandler *prev = NULL, *tmp = Root; | |
10715 | |
10716 while(tmp) | |
10717 { | |
10718 if(tmp->window == window) | |
10719 { | |
10720 void (*discfunc)(HWND, void *) = tmp->discfunction; | |
10721 | |
10722 if(discfunc) | |
10723 { | |
10724 discfunc(tmp->window, tmp->data); | |
10725 } | |
10726 | |
10727 if(prev) | |
10728 { | |
10729 prev->next = tmp->next; | |
10730 free(tmp); | |
10731 tmp = prev->next; | |
10732 } | |
10733 else | |
10734 { | |
10735 Root = tmp->next; | |
10736 free(tmp); | |
10737 tmp = Root; | |
10738 } | |
10739 } | |
10740 else | |
10741 { | |
10742 prev = tmp; | |
10743 tmp = tmp->next; | |
10744 } | |
10745 } | |
10746 } | |
10747 | |
10748 /* | |
10749 * Removes all callbacks for a given window with specified data. | |
10750 * Parameters: | |
10751 * window: Window handle of callback to be removed. | |
10752 * data: Pointer to the data to be compared against. | |
10753 */ | |
10754 void API dw_signal_disconnect_by_data(HWND window, void *data) | |
10755 { | |
10756 SignalHandler *prev = NULL, *tmp = Root; | |
10757 | |
10758 while(tmp) | |
10759 { | |
10760 if(tmp->window == window && tmp->data == data) | |
10761 { | |
10762 void (*discfunc)(HWND, void *) = tmp->discfunction; | |
10763 | |
10764 if(discfunc) | |
10765 { | |
10766 discfunc(tmp->window, tmp->data); | |
10767 } | |
10768 | |
10769 if(prev) | |
10770 { | |
10771 prev->next = tmp->next; | |
10772 free(tmp); | |
10773 tmp = prev->next; | |
10774 } | |
10775 else | |
10776 { | |
10777 Root = tmp->next; | |
10778 free(tmp); | |
10779 tmp = Root; | |
10780 } | |
10781 } | |
10782 else | |
10783 { | |
10784 prev = tmp; | |
10785 tmp = tmp->next; | |
10786 } | |
10787 } | |
10788 } | |
10789 | |
10790 void _my_strlwr(char *buf) | |
10791 { | |
10792 int z, len = (int)strlen(buf); | |
10793 | |
10794 for(z=0;z<len;z++) | |
10795 { | |
10796 if(buf[z] >= 'A' && buf[z] <= 'Z') | |
10797 buf[z] -= 'A' - 'a'; | |
10798 } | |
10799 } | |
10800 | |
10801 /* Open a shared library and return a handle. | |
10802 * Parameters: | |
10803 * name: Base name of the shared library. | |
10804 * handle: Pointer to a module handle, | |
10805 * will be filled in with the handle. | |
10806 */ | |
10807 int dw_module_load(const char *name, HMOD *handle) | |
10808 { | |
10809 int len; | |
10810 char *newname; | |
10811 char errorbuf[1025]; | |
10812 | |
10813 | |
10814 if(!handle) | |
10815 return -1; | |
10816 | |
10817 if((len = (int)strlen(name)) == 0) | |
10818 return -1; | |
10819 | |
10820 /* Lenth + "lib" + ".dylib" + NULL */ | |
10821 newname = malloc(len + 10); | |
10822 | |
10823 if(!newname) | |
10824 return -1; | |
10825 | |
10826 sprintf(newname, "lib%s.dylib", name); | |
10827 _my_strlwr(newname); | |
10828 | |
10829 *handle = dlopen(newname, RTLD_NOW); | |
10830 if(*handle == NULL) | |
10831 { | |
10832 strncpy(errorbuf, dlerror(), 1024); | |
10833 printf("%s\n", errorbuf); | |
10834 sprintf(newname, "lib%s.dylib", name); | |
10835 *handle = dlopen(newname, RTLD_NOW); | |
10836 } | |
10837 | |
10838 free(newname); | |
10839 | |
10840 return (NULL == *handle) ? -1 : 0; | |
10841 } | |
10842 | |
10843 /* Queries the address of a symbol within open handle. | |
10844 * Parameters: | |
10845 * handle: Module handle returned by dw_module_load() | |
10846 * name: Name of the symbol you want the address of. | |
10847 * func: A pointer to a function pointer, to obtain | |
10848 * the address. | |
10849 */ | |
10850 int dw_module_symbol(HMOD handle, const char *name, void**func) | |
10851 { | |
10852 if(!func || !name) | |
10853 return -1; | |
10854 | |
10855 if(strlen(name) == 0) | |
10856 return -1; | |
10857 | |
10858 *func = (void*)dlsym(handle, name); | |
10859 return (NULL == *func); | |
10860 } | |
10861 | |
10862 /* Frees the shared library previously opened. | |
10863 * Parameters: | |
10864 * handle: Module handle returned by dw_module_load() | |
10865 */ | |
10866 int dw_module_close(HMOD handle) | |
10867 { | |
10868 if(handle) | |
10869 return dlclose(handle); | |
10870 return 0; | |
10871 } | |
10872 | |
10873 /* | |
10874 * Returns the handle to an unnamed mutex semaphore. | |
10875 */ | |
10876 HMTX dw_mutex_new(void) | |
10877 { | |
10878 HMTX mutex = malloc(sizeof(pthread_mutex_t)); | |
10879 | |
10880 pthread_mutex_init(mutex, NULL); | |
10881 return mutex; | |
10882 } | |
10883 | |
10884 /* | |
10885 * Closes a semaphore created by dw_mutex_new(). | |
10886 * Parameters: | |
10887 * mutex: The handle to the mutex returned by dw_mutex_new(). | |
10888 */ | |
10889 void dw_mutex_close(HMTX mutex) | |
10890 { | |
10891 if(mutex) | |
10892 { | |
10893 pthread_mutex_destroy(mutex); | |
10894 free(mutex); | |
10895 } | |
10896 } | |
10897 | |
10898 /* | |
10899 * Tries to gain access to the semaphore, if it can't it blocks. | |
10900 * Parameters: | |
10901 * mutex: The handle to the mutex returned by dw_mutex_new(). | |
10902 */ | |
10903 void dw_mutex_lock(HMTX mutex) | |
10904 { | |
10905 /* We need to handle locks from the main thread differently... | |
10906 * since we can't stop message processing... otherwise we | |
10907 * will deadlock... so try to acquire the lock and continue | |
10908 * processing messages in between tries. | |
10909 */ | |
10910 if(DWThread == pthread_self()) | |
10911 { | |
10912 while(pthread_mutex_trylock(mutex) != 0) | |
10913 { | |
10914 /* Process any pending events */ | |
10915 while(_dw_main_iteration([NSDate dateWithTimeIntervalSinceNow:0.01])) | |
10916 { | |
10917 /* Just loop */ | |
10918 } | |
10919 } | |
10920 } | |
10921 else | |
10922 { | |
10923 pthread_mutex_lock(mutex); | |
10924 } | |
10925 } | |
10926 | |
10927 /* | |
10928 * Tries to gain access to the semaphore. | |
10929 * Parameters: | |
10930 * mutex: The handle to the mutex returned by dw_mutex_new(). | |
10931 * Returns: | |
10932 * DW_ERROR_NONE on success, DW_ERROR_TIMEOUT if it is already locked. | |
10933 */ | |
10934 int API dw_mutex_trylock(HMTX mutex) | |
10935 { | |
10936 if(pthread_mutex_trylock(mutex) == 0) | |
10937 return DW_ERROR_NONE; | |
10938 return DW_ERROR_TIMEOUT; | |
10939 } | |
10940 | |
10941 /* | |
10942 * Reliquishes the access to the semaphore. | |
10943 * Parameters: | |
10944 * mutex: The handle to the mutex returned by dw_mutex_new(). | |
10945 */ | |
10946 void dw_mutex_unlock(HMTX mutex) | |
10947 { | |
10948 pthread_mutex_unlock(mutex); | |
10949 } | |
10950 | |
10951 /* | |
10952 * Returns the handle to an unnamed event semaphore. | |
10953 */ | |
10954 HEV dw_event_new(void) | |
10955 { | |
10956 HEV eve = (HEV)malloc(sizeof(struct _dw_unix_event)); | |
10957 | |
10958 if(!eve) | |
10959 return NULL; | |
10960 | |
10961 /* We need to be careful here, mutexes on Linux are | |
10962 * FAST by default but are error checking on other | |
10963 * systems such as FreeBSD and OS/2, perhaps others. | |
10964 */ | |
10965 pthread_mutex_init (&(eve->mutex), NULL); | |
10966 pthread_mutex_lock (&(eve->mutex)); | |
10967 pthread_cond_init (&(eve->event), NULL); | |
10968 | |
10969 pthread_mutex_unlock (&(eve->mutex)); | |
10970 eve->alive = 1; | |
10971 eve->posted = 0; | |
10972 | |
10973 return eve; | |
10974 } | |
10975 | |
10976 /* | |
10977 * Resets a semaphore created by dw_event_new(). | |
10978 * Parameters: | |
10979 * eve: The handle to the event returned by dw_event_new(). | |
10980 */ | |
10981 int dw_event_reset (HEV eve) | |
10982 { | |
10983 if(!eve) | |
10984 return DW_ERROR_NON_INIT; | |
10985 | |
10986 pthread_mutex_lock (&(eve->mutex)); | |
10987 pthread_cond_broadcast (&(eve->event)); | |
10988 pthread_cond_init (&(eve->event), NULL); | |
10989 eve->posted = 0; | |
10990 pthread_mutex_unlock (&(eve->mutex)); | |
10991 return DW_ERROR_NONE; | |
10992 } | |
10993 | |
10994 /* | |
10995 * Posts a semaphore created by dw_event_new(). Causing all threads | |
10996 * waiting on this event in dw_event_wait to continue. | |
10997 * Parameters: | |
10998 * eve: The handle to the event returned by dw_event_new(). | |
10999 */ | |
11000 int dw_event_post (HEV eve) | |
11001 { | |
11002 if(!eve) | |
11003 return FALSE; | |
11004 | |
11005 pthread_mutex_lock (&(eve->mutex)); | |
11006 pthread_cond_broadcast (&(eve->event)); | |
11007 eve->posted = 1; | |
11008 pthread_mutex_unlock (&(eve->mutex)); | |
11009 return 0; | |
11010 } | |
11011 | |
11012 /* | |
11013 * Waits on a semaphore created by dw_event_new(), until the | |
11014 * event gets posted or until the timeout expires. | |
11015 * Parameters: | |
11016 * eve: The handle to the event returned by dw_event_new(). | |
11017 */ | |
11018 int dw_event_wait(HEV eve, unsigned long timeout) | |
11019 { | |
11020 int rc; | |
11021 | |
11022 if(!eve) | |
11023 return DW_ERROR_NON_INIT; | |
11024 | |
11025 pthread_mutex_lock (&(eve->mutex)); | |
11026 | |
11027 if(eve->posted) | |
11028 { | |
11029 pthread_mutex_unlock (&(eve->mutex)); | |
11030 return DW_ERROR_NONE; | |
11031 } | |
11032 | |
11033 if(timeout != -1) | |
11034 { | |
11035 struct timeval now; | |
11036 struct timespec timeo; | |
11037 | |
11038 gettimeofday(&now, 0); | |
11039 timeo.tv_sec = now.tv_sec + (timeout / 1000); | |
11040 timeo.tv_nsec = now.tv_usec * 1000; | |
11041 rc = pthread_cond_timedwait(&(eve->event), &(eve->mutex), &timeo); | |
11042 } | |
11043 else | |
11044 rc = pthread_cond_wait(&(eve->event), &(eve->mutex)); | |
11045 pthread_mutex_unlock (&(eve->mutex)); | |
11046 if(!rc) | |
11047 return DW_ERROR_NONE; | |
11048 if(rc == ETIMEDOUT) | |
11049 return DW_ERROR_TIMEOUT; | |
11050 return DW_ERROR_GENERAL; | |
11051 } | |
11052 | |
11053 /* | |
11054 * Closes a semaphore created by dw_event_new(). | |
11055 * Parameters: | |
11056 * eve: The handle to the event returned by dw_event_new(). | |
11057 */ | |
11058 int dw_event_close(HEV *eve) | |
11059 { | |
11060 if(!eve || !(*eve)) | |
11061 return DW_ERROR_NON_INIT; | |
11062 | |
11063 pthread_mutex_lock (&((*eve)->mutex)); | |
11064 pthread_cond_destroy (&((*eve)->event)); | |
11065 pthread_mutex_unlock (&((*eve)->mutex)); | |
11066 pthread_mutex_destroy (&((*eve)->mutex)); | |
11067 free(*eve); | |
11068 *eve = NULL; | |
11069 | |
11070 return DW_ERROR_NONE; | |
11071 } | |
11072 | |
11073 struct _seminfo { | |
11074 int fd; | |
11075 int waiting; | |
11076 }; | |
11077 | |
11078 static void _handle_sem(int *tmpsock) | |
11079 { | |
11080 fd_set rd; | |
11081 struct _seminfo *array = (struct _seminfo *)malloc(sizeof(struct _seminfo)); | |
11082 int listenfd = tmpsock[0]; | |
11083 int bytesread, connectcount = 1, maxfd, z, posted = 0; | |
11084 char command; | |
11085 sigset_t mask; | |
11086 | |
11087 sigfillset(&mask); /* Mask all allowed signals */ | |
11088 pthread_sigmask(SIG_BLOCK, &mask, NULL); | |
11089 | |
11090 /* problems */ | |
11091 if(tmpsock[1] == -1) | |
11092 { | |
11093 free(array); | |
11094 return; | |
11095 } | |
11096 | |
11097 array[0].fd = tmpsock[1]; | |
11098 array[0].waiting = 0; | |
11099 | |
11100 /* Free the memory allocated in dw_named_event_new. */ | |
11101 free(tmpsock); | |
11102 | |
11103 while(1) | |
11104 { | |
11105 FD_ZERO(&rd); | |
11106 FD_SET(listenfd, &rd); | |
11107 | |
11108 maxfd = listenfd; | |
11109 | |
11110 /* Added any connections to the named event semaphore */ | |
11111 for(z=0;z<connectcount;z++) | |
11112 { | |
11113 if(array[z].fd > maxfd) | |
11114 maxfd = array[z].fd; | |
11115 | |
11116 FD_SET(array[z].fd, &rd); | |
11117 } | |
11118 | |
11119 if(select(maxfd+1, &rd, NULL, NULL, NULL) == -1) | |
11120 { | |
11121 free(array); | |
11122 return; | |
11123 } | |
11124 | |
11125 if(FD_ISSET(listenfd, &rd)) | |
11126 { | |
11127 struct _seminfo *newarray; | |
11128 int newfd = accept(listenfd, 0, 0); | |
11129 | |
11130 if(newfd > -1) | |
11131 { | |
11132 /* Add new connections to the set */ | |
11133 newarray = (struct _seminfo *)malloc(sizeof(struct _seminfo)*(connectcount+1)); | |
11134 memcpy(newarray, array, sizeof(struct _seminfo)*(connectcount)); | |
11135 | |
11136 newarray[connectcount].fd = newfd; | |
11137 newarray[connectcount].waiting = 0; | |
11138 | |
11139 connectcount++; | |
11140 | |
11141 /* Replace old array with new one */ | |
11142 free(array); | |
11143 array = newarray; | |
11144 } | |
11145 } | |
11146 | |
11147 /* Handle any events posted to the semaphore */ | |
11148 for(z=0;z<connectcount;z++) | |
11149 { | |
11150 if(FD_ISSET(array[z].fd, &rd)) | |
11151 { | |
11152 if((bytesread = (int)read(array[z].fd, &command, 1)) < 1) | |
11153 { | |
11154 struct _seminfo *newarray = NULL; | |
11155 | |
11156 /* Remove this connection from the set */ | |
11157 if(connectcount > 1) | |
11158 { | |
11159 newarray = (struct _seminfo *)malloc(sizeof(struct _seminfo)*(connectcount-1)); | |
11160 if(!z) | |
11161 memcpy(newarray, &array[1], sizeof(struct _seminfo)*(connectcount-1)); | |
11162 else | |
11163 { | |
11164 memcpy(newarray, array, sizeof(struct _seminfo)*z); | |
11165 if(z!=(connectcount-1)) | |
11166 memcpy(&newarray[z], &array[z+1], sizeof(struct _seminfo)*(z-connectcount-1)); | |
11167 } | |
11168 } | |
11169 connectcount--; | |
11170 | |
11171 /* Replace old array with new one */ | |
11172 free(array); | |
11173 array = newarray; | |
11174 } | |
11175 else if(bytesread == 1) | |
11176 { | |
11177 switch(command) | |
11178 { | |
11179 case 0: | |
11180 { | |
11181 /* Reset */ | |
11182 posted = 0; | |
11183 } | |
11184 break; | |
11185 case 1: | |
11186 /* Post */ | |
11187 { | |
11188 int s; | |
11189 char tmp = (char)0; | |
11190 | |
11191 posted = 1; | |
11192 | |
11193 for(s=0;s<connectcount;s++) | |
11194 { | |
11195 /* The semaphore has been posted so | |
11196 * we tell all the waiting threads to | |
11197 * continue. | |
11198 */ | |
11199 if(array[s].waiting) | |
11200 write(array[s].fd, &tmp, 1); | |
11201 } | |
11202 } | |
11203 break; | |
11204 case 2: | |
11205 /* Wait */ | |
11206 { | |
11207 char tmp = (char)0; | |
11208 | |
11209 array[z].waiting = 1; | |
11210 | |
11211 /* If we are posted exit immeditately */ | |
11212 if(posted) | |
11213 write(array[z].fd, &tmp, 1); | |
11214 } | |
11215 break; | |
11216 case 3: | |
11217 { | |
11218 /* Done Waiting */ | |
11219 array[z].waiting = 0; | |
11220 } | |
11221 break; | |
11222 } | |
11223 } | |
11224 } | |
11225 } | |
11226 } | |
11227 } | |
11228 | |
11229 /* Using domain sockets on unix for IPC */ | |
11230 /* Create a named event semaphore which can be | |
11231 * opened from other processes. | |
11232 * Parameters: | |
11233 * eve: Pointer to an event handle to receive handle. | |
11234 * name: Name given to semaphore which can be opened | |
11235 * by other processes. | |
11236 */ | |
11237 HEV dw_named_event_new(const char *name) | |
11238 { | |
11239 struct sockaddr_un un; | |
11240 int ev, *tmpsock = (int *)malloc(sizeof(int)*2); | |
11241 HEV eve; | |
11242 DWTID dwthread; | |
11243 | |
11244 if(!tmpsock) | |
11245 return NULL; | |
11246 | |
11247 eve = (HEV)malloc(sizeof(struct _dw_unix_event)); | |
11248 | |
11249 if(!eve) | |
11250 { | |
11251 free(tmpsock); | |
11252 return NULL; | |
11253 } | |
11254 | |
11255 tmpsock[0] = socket(AF_UNIX, SOCK_STREAM, 0); | |
11256 ev = socket(AF_UNIX, SOCK_STREAM, 0); | |
11257 memset(&un, 0, sizeof(un)); | |
11258 un.sun_family=AF_UNIX; | |
11259 mkdir("/tmp/.dw", S_IWGRP|S_IWOTH); | |
11260 strcpy(un.sun_path, "/tmp/.dw/"); | |
11261 strcat(un.sun_path, name); | |
11262 | |
11263 /* just to be safe, this should be changed | |
11264 * to support multiple instances. | |
11265 */ | |
11266 remove(un.sun_path); | |
11267 | |
11268 bind(tmpsock[0], (struct sockaddr *)&un, sizeof(un)); | |
11269 listen(tmpsock[0], 0); | |
11270 connect(ev, (struct sockaddr *)&un, sizeof(un)); | |
11271 tmpsock[1] = accept(tmpsock[0], 0, 0); | |
11272 | |
11273 if(tmpsock[0] < 0 || tmpsock[1] < 0 || ev < 0) | |
11274 { | |
11275 if(tmpsock[0] > -1) | |
11276 close(tmpsock[0]); | |
11277 if(tmpsock[1] > -1) | |
11278 close(tmpsock[1]); | |
11279 if(ev > -1) | |
11280 close(ev); | |
11281 free(tmpsock); | |
11282 free(eve); | |
11283 return NULL; | |
11284 } | |
11285 | |
11286 /* Create a thread to handle this event semaphore */ | |
11287 pthread_create(&dwthread, NULL, (void *)_handle_sem, (void *)tmpsock); | |
11288 eve->alive = ev; | |
11289 return eve; | |
11290 } | |
11291 | |
11292 /* Open an already existing named event semaphore. | |
11293 * Parameters: | |
11294 * eve: Pointer to an event handle to receive handle. | |
11295 * name: Name given to semaphore which can be opened | |
11296 * by other processes. | |
11297 */ | |
11298 HEV dw_named_event_get(const char *name) | |
11299 { | |
11300 struct sockaddr_un un; | |
11301 HEV eve; | |
11302 int ev = socket(AF_UNIX, SOCK_STREAM, 0); | |
11303 if(ev < 0) | |
11304 return NULL; | |
11305 | |
11306 eve = (HEV)malloc(sizeof(struct _dw_unix_event)); | |
11307 | |
11308 if(!eve) | |
11309 { | |
11310 close(ev); | |
11311 return NULL; | |
11312 } | |
11313 | |
11314 un.sun_family=AF_UNIX; | |
11315 mkdir("/tmp/.dw", S_IWGRP|S_IWOTH); | |
11316 strcpy(un.sun_path, "/tmp/.dw/"); | |
11317 strcat(un.sun_path, name); | |
11318 connect(ev, (struct sockaddr *)&un, sizeof(un)); | |
11319 eve->alive = ev; | |
11320 return eve; | |
11321 } | |
11322 | |
11323 /* Resets the event semaphore so threads who call wait | |
11324 * on this semaphore will block. | |
11325 * Parameters: | |
11326 * eve: Handle to the semaphore obtained by | |
11327 * an open or create call. | |
11328 */ | |
11329 int dw_named_event_reset(HEV eve) | |
11330 { | |
11331 /* signal reset */ | |
11332 char tmp = (char)0; | |
11333 | |
11334 if(!eve || eve->alive < 0) | |
11335 return 0; | |
11336 | |
11337 if(write(eve->alive, &tmp, 1) == 1) | |
11338 return 0; | |
11339 return 1; | |
11340 } | |
11341 | |
11342 /* Sets the posted state of an event semaphore, any threads | |
11343 * waiting on the semaphore will no longer block. | |
11344 * Parameters: | |
11345 * eve: Handle to the semaphore obtained by | |
11346 * an open or create call. | |
11347 */ | |
11348 int dw_named_event_post(HEV eve) | |
11349 { | |
11350 | |
11351 /* signal post */ | |
11352 char tmp = (char)1; | |
11353 | |
11354 if(!eve || eve->alive < 0) | |
11355 return 0; | |
11356 | |
11357 if(write(eve->alive, &tmp, 1) == 1) | |
11358 return 0; | |
11359 return 1; | |
11360 } | |
11361 | |
11362 /* Waits on the specified semaphore until it becomes | |
11363 * posted, or returns immediately if it already is posted. | |
11364 * Parameters: | |
11365 * eve: Handle to the semaphore obtained by | |
11366 * an open or create call. | |
11367 * timeout: Number of milliseconds before timing out | |
11368 * or -1 if indefinite. | |
11369 */ | |
11370 int dw_named_event_wait(HEV eve, unsigned long timeout) | |
11371 { | |
11372 fd_set rd; | |
11373 struct timeval tv, *useme = NULL; | |
11374 int retval = 0; | |
11375 char tmp; | |
11376 | |
11377 if(!eve || eve->alive < 0) | |
11378 return DW_ERROR_NON_INIT; | |
11379 | |
11380 /* Set the timout or infinite */ | |
11381 if(timeout != -1) | |
11382 { | |
11383 tv.tv_sec = timeout / 1000; | |
11384 tv.tv_usec = (int)timeout % 1000; | |
11385 | |
11386 useme = &tv; | |
11387 } | |
11388 | |
11389 FD_ZERO(&rd); | |
11390 FD_SET(eve->alive, &rd); | |
11391 | |
11392 /* Signal wait */ | |
11393 tmp = (char)2; | |
11394 write(eve->alive, &tmp, 1); | |
11395 | |
11396 retval = select(eve->alive+1, &rd, NULL, NULL, useme); | |
11397 | |
11398 /* Signal done waiting. */ | |
11399 tmp = (char)3; | |
11400 write(eve->alive, &tmp, 1); | |
11401 | |
11402 if(retval == 0) | |
11403 return DW_ERROR_TIMEOUT; | |
11404 else if(retval == -1) | |
11405 return DW_ERROR_INTERRUPT; | |
11406 | |
11407 /* Clear the entry from the pipe so | |
11408 * we don't loop endlessly. :) | |
11409 */ | |
11410 read(eve->alive, &tmp, 1); | |
11411 return 0; | |
11412 } | |
11413 | |
11414 /* Release this semaphore, if there are no more open | |
11415 * handles on this semaphore the semaphore will be destroyed. | |
11416 * Parameters: | |
11417 * eve: Handle to the semaphore obtained by | |
11418 * an open or create call. | |
11419 */ | |
11420 int dw_named_event_close(HEV eve) | |
11421 { | |
11422 /* Finally close the domain socket, | |
11423 * cleanup will continue in _handle_sem. | |
11424 */ | |
11425 if(eve) | |
11426 { | |
11427 close(eve->alive); | |
11428 free(eve); | |
11429 } | |
11430 return 0; | |
11431 } | |
11432 | |
11433 /* Mac specific function to cause garbage collection */ | |
11434 void _dw_pool_drain(void) | |
11435 { | |
11436 NSAutoreleasePool *pool = pthread_getspecific(_dw_pool_key); | |
11437 [pool drain]; | |
11438 pool = [[NSAutoreleasePool alloc] init]; | |
11439 pthread_setspecific(_dw_pool_key, pool); | |
11440 } | |
11441 | |
11442 /* | |
11443 * Generally an internal function called from a newly created | |
11444 * thread to setup the Dynamic Windows environment for the thread. | |
11445 * However it is exported so language bindings can call it when | |
11446 * they create threads that require access to Dynamic Windows. | |
11447 */ | |
11448 void API _dw_init_thread(void) | |
11449 { | |
11450 /* If we aren't using garbage collection we need autorelease pools */ | |
11451 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
11452 pthread_setspecific(_dw_pool_key, pool); | |
11453 _init_colors(); | |
11454 } | |
11455 | |
11456 /* | |
11457 * Generally an internal function called from a terminating | |
11458 * thread to cleanup the Dynamic Windows environment for the thread. | |
11459 * However it is exported so language bindings can call it when | |
11460 * they exit threads that require access to Dynamic Windows. | |
11461 */ | |
11462 void API _dw_deinit_thread(void) | |
11463 { | |
11464 UIColor *color; | |
11465 | |
11466 /* Release the pool when we are done so we don't leak */ | |
11467 color = pthread_getspecific(_dw_fg_color_key); | |
11468 [color release]; | |
11469 color = pthread_getspecific(_dw_bg_color_key); | |
11470 [color release]; | |
11471 pool = pthread_getspecific(_dw_pool_key); | |
11472 [pool drain]; | |
11473 } | |
11474 | |
11475 /* | |
11476 * Setup thread independent pools. | |
11477 */ | |
11478 void _dwthreadstart(void *data) | |
11479 { | |
11480 void (*threadfunc)(void *) = NULL; | |
11481 void **tmp = (void **)data; | |
11482 | |
11483 _dw_init_thread(); | |
11484 | |
11485 threadfunc = (void (*)(void *))tmp[0]; | |
11486 | |
11487 /* Start our thread function */ | |
11488 threadfunc(tmp[1]); | |
11489 | |
11490 free(tmp); | |
11491 | |
11492 _dw_deinit_thread(); | |
11493 } | |
11494 | |
11495 /* | |
11496 * Sets the default font used on text based widgets. | |
11497 * Parameters: | |
11498 * fontname: Font name in Dynamic Windows format. | |
11499 */ | |
11500 void API dw_font_set_default(const char *fontname) | |
11501 { | |
11502 UIFont *oldfont = DWDefaultFont; | |
11503 DWDefaultFont = nil; | |
11504 if(fontname) | |
11505 { | |
11506 DWDefaultFont = _dw_font_by_name(fontname); | |
11507 [DWDefaultFont retain]; | |
11508 } | |
11509 [oldfont release]; | |
11510 } | |
11511 | |
11512 /* If DWApp is uninitialized, initialize it */ | |
11513 void _dw_app_init(void) | |
11514 { | |
11515 if(!DWApp) | |
11516 { | |
11517 DWApp = [NSApplication sharedApplication]; | |
11518 DWAppDel *del = [[DWAppDel alloc] init]; | |
11519 [DWApp setDelegate:del]; | |
11520 } | |
11521 } | |
11522 | |
11523 /* | |
11524 * Initializes the Dynamic Windows engine. | |
11525 * Parameters: | |
11526 * newthread: True if this is the only thread. | |
11527 * False if there is already a message loop running. | |
11528 */ | |
11529 int API dw_init(int newthread, int argc, char *argv[]) | |
11530 { | |
11531 char *lang = getenv("LANG"); | |
11532 | |
11533 /* Correct the startup path if run from a bundle */ | |
11534 if(argc > 0 && argv[0]) | |
11535 { | |
11536 char *pathcopy = strdup(argv[0]); | |
11537 char *app = strstr(pathcopy, ".app/"); | |
11538 char *binname = strrchr(pathcopy, '/'); | |
11539 | |
11540 if(binname && (binname++) && !_dw_app_id[0]) | |
11541 { | |
11542 /* If we have a binary name, use that for the Application ID instead. */ | |
11543 snprintf(_dw_app_id, _DW_APP_ID_SIZE, "%s.%s", DW_APP_DOMAIN_DEFAULT, binname); | |
11544 } | |
11545 if(app) | |
11546 { | |
11547 char pathbuf[PATH_MAX+1] = { 0 }; | |
11548 size_t len = (size_t)(app - pathcopy); | |
11549 | |
11550 if(len > 0) | |
11551 { | |
11552 strncpy(_dw_bundle_path, pathcopy, len + 4); | |
11553 strcat(_dw_bundle_path, "/Contents/Resources"); | |
11554 } | |
11555 *app = 0; | |
11556 | |
11557 getcwd(pathbuf, PATH_MAX); | |
11558 | |
11559 /* If run from a bundle the path seems to be / */ | |
11560 if(strcmp(pathbuf, "/") == 0) | |
11561 { | |
11562 char *pos = strrchr(pathcopy, '/'); | |
11563 | |
11564 if(pos) | |
11565 { | |
11566 strncpy(pathbuf, pathcopy, (size_t)(pos - pathcopy)); | |
11567 chdir(pathbuf); | |
11568 } | |
11569 } | |
11570 } | |
11571 if(pathcopy) | |
11572 free(pathcopy); | |
11573 } | |
11574 | |
11575 /* Just in case we can't obtain a path */ | |
11576 if(!_dw_bundle_path[0]) | |
11577 getcwd(_dw_bundle_path, PATH_MAX); | |
11578 | |
11579 /* Get the operating system version */ | |
11580 NSString *version = [[NSProcessInfo processInfo] operatingSystemVersionString]; | |
11581 const char *versionstr = [version UTF8String]; | |
11582 sscanf(versionstr, "Version %d.%d.%d", &DWOSMajor, &DWOSMinor, &DWOSBuild); | |
11583 /* Set the locale... if it is UTF-8 pass it | |
11584 * directly, otherwise specify UTF-8 explicitly. | |
11585 */ | |
11586 setlocale(LC_ALL, lang && strstr(lang, ".UTF-8") ? lang : "UTF-8"); | |
11587 /* Create the application object */ | |
11588 _dw_app_init(); | |
11589 /* Create object for handling timers */ | |
11590 DWHandler = [[DWTimerHandler alloc] init]; | |
11591 pthread_key_create(&_dw_pool_key, NULL); | |
11592 pool = [[NSAutoreleasePool alloc] init]; | |
11593 pthread_setspecific(_dw_pool_key, pool); | |
11594 pthread_key_create(&_dw_fg_color_key, NULL); | |
11595 pthread_key_create(&_dw_bg_color_key, NULL); | |
11596 _init_colors(); | |
11597 /* Create a default main menu, with just the application menu */ | |
11598 DWMainMenu = _generate_main_menu(); | |
11599 [DWMainMenu retain]; | |
11600 [DWApp setMainMenu:DWMainMenu]; | |
11601 DWObj = [[DWObject alloc] init]; | |
11602 DWDefaultFont = nil; | |
11603 DWFontManager = [UIFontManager sharedFontManager]; | |
11604 if (@available(iOS 10.0, *)) | |
11605 { | |
11606 if([[NSBundle mainBundle] bundleIdentifier] != nil) | |
11607 { | |
11608 UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; | |
11609 if(center) | |
11610 { | |
11611 [center requestAuthorizationWithOptions:UNAuthorizationOptionAlert|UNAuthorizationOptionSound | |
11612 completionHandler:^(BOOL granted, NSError * _Nullable error) { | |
11613 if (granted) | |
11614 { | |
11615 center.delegate = [[DWUserNotificationCenterDelegate alloc] init]; | |
11616 } | |
11617 else | |
11618 { | |
11619 NSLog(@"WARNING: Unable to get notification permission. %@", error.localizedDescription); | |
11620 } | |
11621 }]; | |
11622 } | |
11623 } | |
11624 } | |
11625 _DWDirtyDrawables = [[NSMutableArray alloc] init]; | |
11626 /* Use NSThread to start a dummy thread to initialize the threading subsystem */ | |
11627 NSThread *thread = [[ NSThread alloc] initWithTarget:DWObj selector:@selector(uselessThread:) object:nil]; | |
11628 [thread start]; | |
11629 [thread release]; | |
11630 [UITextField setCellClass:[DWTextFieldCell class]]; | |
11631 if(!_dw_app_id[0]) | |
11632 { | |
11633 /* Generate an Application ID based on the PID if all else fails. */ | |
11634 snprintf(_dw_app_id, _DW_APP_ID_SIZE, "%s.pid.%d", DW_APP_DOMAIN_DEFAULT, getpid()); | |
11635 } | |
11636 return DW_ERROR_NONE; | |
11637 } | |
11638 | |
11639 /* | |
11640 * Allocates a shared memory region with a name. | |
11641 * Parameters: | |
11642 * handle: A pointer to receive a SHM identifier. | |
11643 * dest: A pointer to a pointer to receive the memory address. | |
11644 * size: Size in bytes of the shared memory region to allocate. | |
11645 * name: A string pointer to a unique memory name. | |
11646 */ | |
11647 HSHM dw_named_memory_new(void **dest, int size, const char *name) | |
11648 { | |
11649 char namebuf[1025] = {0}; | |
11650 struct _dw_unix_shm *handle = malloc(sizeof(struct _dw_unix_shm)); | |
11651 | |
11652 mkdir("/tmp/.dw", S_IWGRP|S_IWOTH); | |
11653 snprintf(namebuf, 1024, "/tmp/.dw/%s", name); | |
11654 | |
11655 if((handle->fd = open(namebuf, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) | |
11656 { | |
11657 free(handle); | |
11658 return NULL; | |
11659 } | |
11660 | |
11661 ftruncate(handle->fd, size); | |
11662 | |
11663 /* attach the shared memory segment to our process's address space. */ | |
11664 *dest = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, handle->fd, 0); | |
11665 | |
11666 if(*dest == MAP_FAILED) | |
11667 { | |
11668 close(handle->fd); | |
11669 *dest = NULL; | |
11670 free(handle); | |
11671 return NULL; | |
11672 } | |
11673 | |
11674 handle->size = size; | |
11675 handle->sid = getsid(0); | |
11676 handle->path = strdup(namebuf); | |
11677 | |
11678 return handle; | |
11679 } | |
11680 | |
11681 /* | |
11682 * Aquires shared memory region with a name. | |
11683 * Parameters: | |
11684 * dest: A pointer to a pointer to receive the memory address. | |
11685 * size: Size in bytes of the shared memory region to requested. | |
11686 * name: A string pointer to a unique memory name. | |
11687 */ | |
11688 HSHM dw_named_memory_get(void **dest, int size, const char *name) | |
11689 { | |
11690 char namebuf[1025]; | |
11691 struct _dw_unix_shm *handle = malloc(sizeof(struct _dw_unix_shm)); | |
11692 | |
11693 mkdir("/tmp/.dw", S_IWGRP|S_IWOTH); | |
11694 snprintf(namebuf, 1024, "/tmp/.dw/%s", name); | |
11695 | |
11696 if((handle->fd = open(namebuf, O_RDWR)) < 0) | |
11697 { | |
11698 free(handle); | |
11699 return NULL; | |
11700 } | |
11701 | |
11702 /* attach the shared memory segment to our process's address space. */ | |
11703 *dest = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, handle->fd, 0); | |
11704 | |
11705 if(*dest == MAP_FAILED) | |
11706 { | |
11707 close(handle->fd); | |
11708 *dest = NULL; | |
11709 free(handle); | |
11710 return NULL; | |
11711 } | |
11712 | |
11713 handle->size = size; | |
11714 handle->sid = -1; | |
11715 handle->path = NULL; | |
11716 | |
11717 return handle; | |
11718 } | |
11719 | |
11720 /* | |
11721 * Frees a shared memory region previously allocated. | |
11722 * Parameters: | |
11723 * handle: Handle obtained from DB_named_memory_allocate. | |
11724 * ptr: The memory address aquired with DB_named_memory_allocate. | |
11725 */ | |
11726 int dw_named_memory_free(HSHM handle, void *ptr) | |
11727 { | |
11728 struct _dw_unix_shm *h = handle; | |
11729 int rc = munmap(ptr, h->size); | |
11730 | |
11731 close(h->fd); | |
11732 if(h->path) | |
11733 { | |
11734 /* Only remove the actual file if we are the | |
11735 * creator of the file. | |
11736 */ | |
11737 if(h->sid != -1 && h->sid == getsid(0)) | |
11738 remove(h->path); | |
11739 free(h->path); | |
11740 } | |
11741 return rc; | |
11742 } | |
11743 | |
11744 /* | |
11745 * Creates a new thread with a starting point of func. | |
11746 * Parameters: | |
11747 * func: Function which will be run in the new thread. | |
11748 * data: Parameter(s) passed to the function. | |
11749 * stack: Stack size of new thread (OS/2 and Windows only). | |
11750 */ | |
11751 DWTID dw_thread_new(void *func, void *data, int stack) | |
11752 { | |
11753 DWTID thread; | |
11754 void **tmp = malloc(sizeof(void *) * 2); | |
11755 int rc; | |
11756 | |
11757 tmp[0] = func; | |
11758 tmp[1] = data; | |
11759 | |
11760 rc = pthread_create(&thread, NULL, (void *)_dwthreadstart, (void *)tmp); | |
11761 if(rc == 0) | |
11762 return thread; | |
11763 return (DWTID)-1; | |
11764 } | |
11765 | |
11766 /* | |
11767 * Ends execution of current thread immediately. | |
11768 */ | |
11769 void dw_thread_end(void) | |
11770 { | |
11771 pthread_exit(NULL); | |
11772 } | |
11773 | |
11774 /* | |
11775 * Returns the current thread's ID. | |
11776 */ | |
11777 DWTID dw_thread_id(void) | |
11778 { | |
11779 return (DWTID)pthread_self(); | |
11780 } | |
11781 | |
11782 NSURL *_dw_url_from_program(NSString *nsprogram, NSWorkspace *ws) | |
11783 { | |
11784 NSURL *retval = [ws URLForApplicationWithBundleIdentifier:nsprogram]; | |
11785 return retval; | |
11786 } | |
11787 | |
11788 /* | |
11789 * Execute and external program in a seperate session. | |
11790 * Parameters: | |
11791 * program: Program name with optional path. | |
11792 * type: Either DW_EXEC_CON or DW_EXEC_GUI. | |
11793 * params: An array of pointers to string arguements. | |
11794 * Returns: | |
11795 * DW_ERROR_UNKNOWN (-1) on error. | |
11796 */ | |
11797 int dw_exec(const char *program, int type, char **params) | |
11798 { | |
11799 int ret = DW_ERROR_UNKNOWN; | |
11800 | |
11801 if(type == DW_EXEC_GUI) | |
11802 { | |
11803 NSString *nsprogram = [NSString stringWithUTF8String:program]; | |
11804 NSWorkspace *ws = [NSWorkspace sharedWorkspace]; | |
11805 | |
11806 if(params && params[0] && params[1]) | |
11807 { | |
11808 NSURL *url = _dw_url_from_program(nsprogram, ws); | |
11809 NSMutableArray *array = [[NSMutableArray alloc] init]; | |
11810 __block DWDialog *dialog = dw_dialog_new(NULL); | |
11811 int z = 1; | |
11812 | |
11813 while(params[z]) | |
11814 { | |
11815 NSString *thisfile = [NSString stringWithUTF8String:params[z]]; | |
11816 NSURL *nsfile = [NSURL fileURLWithPath:thisfile]; | |
11817 | |
11818 [array addObject:nsfile]; | |
11819 z++; | |
11820 } | |
11821 | |
11822 [ws openURLs:array withApplicationAtURL:url | |
11823 configuration:[NSWorkspaceOpenConfiguration configuration] | |
11824 completionHandler:^(NSRunningApplication *app, NSError *error) { | |
11825 int pid = DW_ERROR_UNKNOWN; | |
11826 | |
11827 if(error) | |
11828 NSLog(@"openURLs: %@", [error localizedDescription]); | |
11829 else | |
11830 pid = [app processIdentifier]; | |
11831 dw_dialog_dismiss(dialog, DW_INT_TO_POINTER(pid)); | |
11832 }]; | |
11833 ret = DW_POINTER_TO_INT(dw_dialog_wait(dialog)); | |
11834 } | |
11835 else | |
11836 { | |
11837 NSURL *url = _dw_url_from_program(nsprogram, ws); | |
11838 __block DWDialog *dialog = dw_dialog_new(NULL); | |
11839 | |
11840 [ws openApplicationAtURL:url | |
11841 configuration:[NSWorkspaceOpenConfiguration configuration] | |
11842 completionHandler:^(NSRunningApplication *app, NSError *error) { | |
11843 int pid = DW_ERROR_UNKNOWN; | |
11844 | |
11845 if(error) | |
11846 NSLog(@"openApplicationAtURL: %@", [error localizedDescription]); | |
11847 else | |
11848 pid = [app processIdentifier]; | |
11849 dw_dialog_dismiss(dialog, DW_INT_TO_POINTER(pid)); | |
11850 }]; | |
11851 ret = DW_POINTER_TO_INT(dw_dialog_wait(dialog)); | |
11852 } | |
11853 } | |
11854 return ret; | |
11855 } | |
11856 | |
11857 /* | |
11858 * Loads a web browser pointed at the given URL. | |
11859 * Parameters: | |
11860 * url: Uniform resource locator. | |
11861 */ | |
11862 int dw_browse(const char *url) | |
11863 { | |
11864 NSURL *myurl = [NSURL URLWithString:[NSString stringWithUTF8String:url]]; | |
11865 [[NSWorkspace sharedWorkspace] openURL:myurl]; | |
11866 return DW_ERROR_NONE; | |
11867 } | |
11868 | |
11869 typedef struct _dwprint | |
11870 { | |
11871 NSPrintInfo *pi; | |
11872 int (*drawfunc)(HPRINT, HPIXMAP, int, void *); | |
11873 void *drawdata; | |
11874 unsigned long flags; | |
11875 } DWPrint; | |
11876 | |
11877 /* | |
11878 * Creates a new print object. | |
11879 * Parameters: | |
11880 * jobname: Name of the print job to show in the queue. | |
11881 * flags: Flags to initially configure the print object. | |
11882 * pages: Number of pages to print. | |
11883 * drawfunc: The pointer to the function to be used as the callback. | |
11884 * drawdata: User data to be passed to the handler function. | |
11885 * Returns: | |
11886 * A handle to the print object or NULL on failure. | |
11887 */ | |
11888 HPRINT API dw_print_new(const char *jobname, unsigned long flags, unsigned int pages, void *drawfunc, void *drawdata) | |
11889 { | |
11890 DWPrint *print; | |
11891 NSPrintPanel *panel; | |
11892 PMPrintSettings settings; | |
11893 NSPrintInfo *pi; | |
11894 | |
11895 if(!drawfunc || !(print = calloc(1, sizeof(DWPrint)))) | |
11896 { | |
11897 return NULL; | |
11898 } | |
11899 | |
11900 if(!jobname) | |
11901 jobname = "Dynamic Windows Print Job"; | |
11902 | |
11903 print->drawfunc = drawfunc; | |
11904 print->drawdata = drawdata; | |
11905 print->flags = flags; | |
11906 | |
11907 /* Get the page range */ | |
11908 pi = [NSPrintInfo sharedPrintInfo]; | |
11909 [pi setHorizontalPagination:DWPrintingPaginationModeFit]; | |
11910 [pi setHorizontallyCentered:YES]; | |
11911 [pi setVerticalPagination:DWPrintingPaginationModeFit]; | |
11912 [pi setVerticallyCentered:YES]; | |
11913 [pi setOrientation:DWPaperOrientationPortrait]; | |
11914 [pi setLeftMargin:0.0]; | |
11915 [pi setRightMargin:0.0]; | |
11916 [pi setTopMargin:0.0]; | |
11917 [pi setBottomMargin:0.0]; | |
11918 | |
11919 settings = [pi PMPrintSettings]; | |
11920 PMSetPageRange(settings, 1, pages); | |
11921 PMSetFirstPage(settings, 1, true); | |
11922 PMSetLastPage(settings, pages, true); | |
11923 PMPrintSettingsSetJobName(settings, (CFStringRef)[NSString stringWithUTF8String:jobname]); | |
11924 [pi updateFromPMPrintSettings]; | |
11925 | |
11926 /* Create and show the print panel */ | |
11927 panel = [NSPrintPanel printPanel]; | |
11928 if(!panel || [panel runModalWithPrintInfo:pi] == DWModalResponseCancel) | |
11929 { | |
11930 free(print); | |
11931 return NULL; | |
11932 } | |
11933 /* Put the print info from the panel into the operation */ | |
11934 print->pi = pi; | |
11935 | |
11936 return print; | |
11937 } | |
11938 | |
11939 /* | |
11940 * Runs the print job, causing the draw page callbacks to fire. | |
11941 * Parameters: | |
11942 * print: Handle to the print object returned by dw_print_new(). | |
11943 * flags: Flags to run the print job. | |
11944 * Returns: | |
11945 * DW_ERROR_UNKNOWN on error or DW_ERROR_NONE on success. | |
11946 */ | |
11947 int API dw_print_run(HPRINT print, unsigned long flags) | |
11948 { | |
11949 DWPrint *p = print; | |
11950 NSBitmapImageRep *rep, *rep2; | |
11951 NSPrintInfo *pi; | |
11952 NSPrintOperation *po; | |
11953 HPIXMAP pixmap, pixmap2; | |
11954 UIImage *image, *flipped; | |
11955 UIImageView *iv; | |
11956 NSSize size; | |
11957 PMPrintSettings settings; | |
11958 int x, result = DW_ERROR_UNKNOWN; | |
11959 UInt32 start, end; | |
11960 | |
11961 if(!p) | |
11962 return result; | |
11963 | |
11964 DW_LOCAL_POOL_IN; | |
11965 | |
11966 /* Figure out the printer/paper size */ | |
11967 pi = p->pi; | |
11968 size = [pi paperSize]; | |
11969 | |
11970 /* Get the page range */ | |
11971 settings = [pi PMPrintSettings]; | |
11972 PMGetFirstPage(settings, &start); | |
11973 if(start > 0) | |
11974 start--; | |
11975 PMGetLastPage(settings, &end); | |
11976 PMSetPageRange(settings, 1, 1); | |
11977 PMSetFirstPage(settings, 1, true); | |
11978 PMSetLastPage(settings, 1, true); | |
11979 [pi updateFromPMPrintSettings]; | |
11980 | |
11981 /* Create an image view to print and a pixmap to draw into */ | |
11982 iv = [[UIImageView alloc] init]; | |
11983 pixmap = dw_pixmap_new(iv, (int)size.width, (int)size.height, 8); | |
11984 rep = pixmap->image; | |
11985 pixmap2 = dw_pixmap_new(iv, (int)size.width, (int)size.height, 8); | |
11986 rep2 = pixmap2->image; | |
11987 | |
11988 /* Create an image with the data from the pixmap | |
11989 * to go into the image view. | |
11990 */ | |
11991 image = [[UIImage alloc] initWithSize:[rep size]]; | |
11992 flipped = [[UIImage alloc] initWithSize:[rep size]]; | |
11993 [image addRepresentation:rep]; | |
11994 [flipped addRepresentation:rep2]; | |
11995 [iv setImage:flipped]; | |
11996 [iv setImageScaling:UIImageScaleProportionallyDown]; | |
11997 [iv setFrameOrigin:NSMakePoint(0,0)]; | |
11998 [iv setFrameSize:size]; | |
11999 | |
12000 /* Create the print operation using the image view and | |
12001 * print info obtained from the panel in the last call. | |
12002 */ | |
12003 po = [NSPrintOperation printOperationWithView:iv printInfo:pi]; | |
12004 [po setShowsPrintPanel:NO]; | |
12005 | |
12006 /* Cycle through each page */ | |
12007 for(x=start; x<end && p->drawfunc; x++) | |
12008 { | |
12009 /* Call the application's draw function */ | |
12010 p->drawfunc(print, pixmap, x, p->drawdata); | |
12011 if(p->drawfunc) | |
12012 { | |
12013 /* Internal representation is flipped... so flip again so we can print */ | |
12014 _flip_image(image, rep2, size); | |
12015 #ifdef DEBUG_PRINT | |
12016 /* Save it to file to see what we have */ | |
12017 NSData *data = [rep2 representationUsingType: NSPNGFileType properties: nil]; | |
12018 [data writeToFile: @"print.png" atomically: NO]; | |
12019 #endif | |
12020 /* Print the image view */ | |
12021 [po runOperation]; | |
12022 /* Fill the pixmap with white in case we are printing more pages */ | |
12023 dw_color_foreground_set(DW_CLR_WHITE); | |
12024 dw_draw_rect(0, pixmap, TRUE, 0, 0, (int)size.width, (int)size.height); | |
12025 } | |
12026 } | |
12027 if(p->drawfunc) | |
12028 result = DW_ERROR_NONE; | |
12029 /* Free memory */ | |
12030 [image release]; | |
12031 [flipped release]; | |
12032 dw_pixmap_destroy(pixmap); | |
12033 dw_pixmap_destroy(pixmap2); | |
12034 free(p); | |
12035 [iv release]; | |
12036 DW_LOCAL_POOL_OUT; | |
12037 return result; | |
12038 } | |
12039 | |
12040 /* | |
12041 * Cancels the print job, typically called from a draw page callback. | |
12042 * Parameters: | |
12043 * print: Handle to the print object returned by dw_print_new(). | |
12044 */ | |
12045 void API dw_print_cancel(HPRINT print) | |
12046 { | |
12047 DWPrint *p = print; | |
12048 | |
12049 if(p) | |
12050 p->drawfunc = NULL; | |
12051 } | |
12052 | |
12053 /* | |
12054 * Converts a UTF-8 encoded string into a wide string. | |
12055 * Parameters: | |
12056 * utf8string: UTF-8 encoded source string. | |
12057 * Returns: | |
12058 * Wide string that needs to be freed with dw_free() | |
12059 * or NULL on failure. | |
12060 */ | |
12061 wchar_t * API dw_utf8_to_wchar(const char *utf8string) | |
12062 { | |
12063 size_t buflen = strlen(utf8string) + 1; | |
12064 wchar_t *temp = malloc(buflen * sizeof(wchar_t)); | |
12065 if(temp) | |
12066 mbstowcs(temp, utf8string, buflen); | |
12067 return temp; | |
12068 } | |
12069 | |
12070 /* | |
12071 * Converts a wide string into a UTF-8 encoded string. | |
12072 * Parameters: | |
12073 * wstring: Wide source string. | |
12074 * Returns: | |
12075 * UTF-8 encoded string that needs to be freed with dw_free() | |
12076 * or NULL on failure. | |
12077 */ | |
12078 char * API dw_wchar_to_utf8(const wchar_t *wstring) | |
12079 { | |
12080 size_t bufflen = 8 * wcslen(wstring) + 1; | |
12081 char *temp = malloc(bufflen); | |
12082 if(temp) | |
12083 wcstombs(temp, wstring, bufflen); | |
12084 return temp; | |
12085 } | |
12086 | |
12087 /* | |
12088 * Gets the state of the requested library feature. | |
12089 * Parameters: | |
12090 * feature: The requested feature for example DW_FEATURE_DARK_MODE | |
12091 * Returns: | |
12092 * DW_FEATURE_UNSUPPORTED if the library or OS does not support the feature. | |
12093 * DW_FEATURE_DISABLED if the feature is supported but disabled. | |
12094 * DW_FEATURE_ENABLED if the feature is supported and enabled. | |
12095 * Other value greater than 1, same as enabled but with extra info. | |
12096 */ | |
12097 int API dw_feature_get(DWFEATURE feature) | |
12098 { | |
12099 switch(feature) | |
12100 { | |
12101 case DW_FEATURE_NOTIFICATION: | |
12102 case DW_FEATURE_MLE_AUTO_COMPLETE: | |
12103 case DW_FEATURE_HTML: | |
12104 case DW_FEATURE_HTML_RESULT: | |
12105 case DW_FEATURE_CONTAINER_STRIPE: | |
12106 case DW_FEATURE_MLE_WORD_WRAP: | |
12107 case DW_FEATURE_UTF8_UNICODE: | |
12108 return DW_FEATURE_ENABLED; | |
12109 default: | |
12110 return DW_FEATURE_UNSUPPORTED; | |
12111 } | |
12112 } | |
12113 | |
12114 /* | |
12115 * Sets the state of the requested library feature. | |
12116 * Parameters: | |
12117 * feature: The requested feature for example DW_FEATURE_DARK_MODE | |
12118 * state: DW_FEATURE_DISABLED, DW_FEATURE_ENABLED or any value greater than 1. | |
12119 * Returns: | |
12120 * DW_FEATURE_UNSUPPORTED if the library or OS does not support the feature. | |
12121 * DW_ERROR_NONE if the feature is supported and successfully configured. | |
12122 * DW_ERROR_GENERAL if the feature is supported but could not be configured. | |
12123 * Remarks: | |
12124 * These settings are typically used during dw_init() so issue before | |
12125 * setting up the library with dw_init(). | |
12126 */ | |
12127 int API dw_feature_set(DWFEATURE feature, int state) | |
12128 { | |
12129 switch(feature) | |
12130 { | |
12131 /* These features are supported but not configurable */ | |
12132 case DW_FEATURE_NOTIFICATION: | |
12133 case DW_FEATURE_MLE_AUTO_COMPLETE: | |
12134 case DW_FEATURE_HTML: | |
12135 case DW_FEATURE_HTML_RESULT: | |
12136 case DW_FEATURE_CONTAINER_STRIPE: | |
12137 case DW_FEATURE_MLE_WORD_WRAP: | |
12138 case DW_FEATURE_UTF8_UNICODE: | |
12139 return DW_ERROR_GENERAL; | |
12140 default: | |
12141 return DW_FEATURE_UNSUPPORTED; | |
12142 } | |
12143 } |