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 *)&param1];
32 #define DW_FUNCTION_ADD_PARAM2(param1, param2) [_args addPointer:(void *)&param1]; \
33 [_args addPointer:(void *)&param2];
34 #define DW_FUNCTION_ADD_PARAM3(param1, param2, param3) [_args addPointer:(void *)&param1]; \
35 [_args addPointer:(void *)&param2]; \
36 [_args addPointer:(void *)&param3];
37 #define DW_FUNCTION_ADD_PARAM4(param1, param2, param3, param4) [_args addPointer:(void *)&param1]; \
38 [_args addPointer:(void *)&param2]; \
39 [_args addPointer:(void *)&param3]; \
40 [_args addPointer:(void *)&param4];
41 #define DW_FUNCTION_ADD_PARAM5(param1, param2, param3, param4, param5) [_args addPointer:(void *)&param1]; \
42 [_args addPointer:(void *)&param2]; \
43 [_args addPointer:(void *)&param3]; \
44 [_args addPointer:(void *)&param4]; \
45 [_args addPointer:(void *)&param5];
46 #define DW_FUNCTION_ADD_PARAM6(param1, param2, param3, param4, param5, param6) \
47 [_args addPointer:(void *)&param1]; \
48 [_args addPointer:(void *)&param2]; \
49 [_args addPointer:(void *)&param3]; \
50 [_args addPointer:(void *)&param4]; \
51 [_args addPointer:(void *)&param5]; \
52 [_args addPointer:(void *)&param6];
53 #define DW_FUNCTION_ADD_PARAM7(param1, param2, param3, param4, param5, param6, param7) \
54 [_args addPointer:(void *)&param1]; \
55 [_args addPointer:(void *)&param2]; \
56 [_args addPointer:(void *)&param3]; \
57 [_args addPointer:(void *)&param4]; \
58 [_args addPointer:(void *)&param5]; \
59 [_args addPointer:(void *)&param6]; \
60 [_args addPointer:(void *)&param7];
61 #define DW_FUNCTION_ADD_PARAM8(param1, param2, param3, param4, param5, param6, param7, param8) \
62 [_args addPointer:(void *)&param1]; \
63 [_args addPointer:(void *)&param2]; \
64 [_args addPointer:(void *)&param3]; \
65 [_args addPointer:(void *)&param4]; \
66 [_args addPointer:(void *)&param5]; \
67 [_args addPointer:(void *)&param6]; \
68 [_args addPointer:(void *)&param7]; \
69 [_args addPointer:(void *)&param8];
70 #define DW_FUNCTION_ADD_PARAM9(param1, param2, param3, param4, param5, param6, param7, param8, param9) \
71 [_args addPointer:(void *)&param1]; \
72 [_args addPointer:(void *)&param2]; \
73 [_args addPointer:(void *)&param3]; \
74 [_args addPointer:(void *)&param4]; \
75 [_args addPointer:(void *)&param5]; \
76 [_args addPointer:(void *)&param6]; \
77 [_args addPointer:(void *)&param7]; \
78 [_args addPointer:(void *)&param8]; \
79 [_args addPointer:(void *)&param9];
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 }