update plists MACOSX_DEPLOYMENT_TARGET = 10.7.0
[wdl/wdl-ol.git] / WDL / swell / swell-wnd.mm
blob56ae8c2a5358f7f0bd5a3063b27e657e2a50137f
1 /* Cockos SWELL (Simple/Small Win32 Emulation Layer for Linux/OSX)
2    Copyright (C) 2006 and later, Cockos, Inc.
4     This software is provided 'as-is', without any express or implied
5     warranty.  In no event will the authors be held liable for any damages
6     arising from the use of this software.
8     Permission is granted to anyone to use this software for any purpose,
9     including commercial applications, and to alter it and redistribute it
10     freely, subject to the following restrictions:
12     1. The origin of this software must not be misrepresented; you must not
13        claim that you wrote the original software. If you use this software
14        in a product, an acknowledgment in the product documentation would be
15        appreciated but is not required.
16     2. Altered source versions must be plainly marked as such, and must not be
17        misrepresented as being the original software.
18     3. This notice may not be removed or altered from any source distribution.
19   
21     This file provides basic windows APIs for handling windows, as well as the stubs to enable swell-dlggen to work.
23   */
26 #ifndef SWELL_PROVIDED_BY_APP
28 #import <Cocoa/Cocoa.h>
29 #import <objc/objc-runtime.h>
30 #include "swell.h"
31 #include "../mutex.h"
32 #include "../ptrlist.h"
33 #include "../queue.h"
34 #include "../wdlcstring.h"
36 #include "swell-dlggen.h"
38 #define SWELL_INTERNAL_MERGESORT_IMPL
39 #define SWELL_INTERNAL_HTREEITEM_IMPL
40 #include "swell-internal.h"
42 static bool SWELL_NeedModernListViewHacks()
44 #ifdef __LP64__
45   return false;
46 #else
47   // only needed on 32 bit yosemite as of 10.10.3, but who knows when it will be necessary elsewhere
48   return SWELL_GetOSXVersion() >= 0x10a0;
49 #endif
52 static LRESULT sendSwellMessage(id obj, UINT uMsg, WPARAM wParam, LPARAM lParam)
54   if (obj && [obj respondsToSelector:@selector(onSwellMessage:p1:p2:)])
55     return [(SWELL_hwndChild *)obj onSwellMessage:uMsg p1:wParam p2:lParam];
56   return 0;
58 static void InvalidateSuperViews(NSView *view);
59 #define STANDARD_CONTROL_NEEDSDISPLAY_IMPL \
60   - (void)setNeedsDisplay:(BOOL)flag \
61   { \
62   [super setNeedsDisplay:flag]; \
63   if (flag) InvalidateSuperViews(self); \
64   } \
65   - (void)setNeedsDisplayInRect:(NSRect)rect \
66   { \
67   [super setNeedsDisplayInRect:rect]; \
68   InvalidateSuperViews(self); \
69   }
72 int g_swell_want_nice_style = 1;
73 static void *SWELL_CStringToCFString_FilterPrefix(const char *str)
75   int c=0;
76   while (str[c] && str[c] != '&' && c++<1024);
77   if (!str[c] || c>=1024 || strlen(str)>=1024) return SWELL_CStringToCFString(str);
78   char buf[1500];
79   const char *p=str;
80   char *op=buf;
81   while (*p)
82   {
83     if (*p == '&')  p++;
84     if (!*p) break;
85     *op++=*p++;
86   }
87   *op=0;
88   return SWELL_CStringToCFString(buf);
92 static int _nsStringSearchProc(const void *_a, const void *_b)
94   NSString *a=(NSString *)_a;
95   NSString *b = (NSString *)_b;
96   return (int)[a compare:b];
98 static int _nsMenuSearchProc(const void *_a, const void *_b)
100   NSString *a=(NSString *)_a;
101   NSMenuItem *b = (NSMenuItem *)_b;
102   return (int)[a compare:[b title]];
104 static int _listviewrowSearchFunc(const void *_a, const void *_b, const void *ctx)
106   const char *a = (const char *)_a;
107   SWELL_ListView_Row *row = (SWELL_ListView_Row *)_b;
108   const char *b="";
109   if (!row || !(b=row->m_vals.Get(0))) b="";
110   return strcmp(a,b);
112 static int _listviewrowSearchFunc2(const void *_a, const void *_b, const void *ctx)
114   const char *a = (const char *)_a;
115   SWELL_ListView_Row *row = (SWELL_ListView_Row *)_b;
116   const char *b="";
117   if (!row || !(b=row->m_vals.Get(0))) b="";
118   return strcmp(b,a);
121 // modified bsearch: returns place item SHOULD be in if it's not found
122 static NSInteger arr_bsearch_mod(void *key, NSArray *arr, int (*compar)(const void *, const void *))
124   const NSInteger nmemb = [arr count];
125   NSInteger p,lim,base=0;
126   
127         for (lim = nmemb; lim != 0; lim >>= 1) {
128                 p = base + (lim >> 1);
129                 int cmp = compar(key, [arr objectAtIndex:p]);
130                 if (cmp == 0) return (p);
131                 if (cmp > 0) {  /* key > p: move right */
132       // check to see if key is less than p+1, if it is, we're done
133                         base = p + 1;
134       if (base >= nmemb || compar(key,[arr objectAtIndex:base])<=0) return base;
135                         lim--;
136                 } /* else move left */
137         }
138         return 0;
142 template<class T> static int ptrlist_bsearch_mod(void *key, WDL_PtrList<T> *arr, int (*compar)(const void *, const void *, const void *ctx), void *ctx)
144   const int nmemb = arr->GetSize();
145   int base=0, lim, p;
146   
147         for (lim = nmemb; lim != 0; lim >>= 1) {
148                 p = base + (lim >> 1);
149                 int cmp = compar(key, arr->Get(p),ctx);
150                 if (cmp == 0) return (p);
151                 if (cmp > 0) {  /* key > p: move right */
152       // check to see if key is less than p+1, if it is, we're done
153                         base = p + 1;
154       if (base >= nmemb || compar(key,arr->Get(base),ctx)<=0) return base;
155                         lim--;
156                 } /* else move left */
157         }
158         return 0;
162 @implementation SWELL_TabView
163 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
165 -(void)setNotificationWindow:(id)dest
167   m_dest=dest;
169 -(id)getNotificationWindow
171   return m_dest;
173 -(NSInteger) tag
175   return m_tag;
177 -(void) setTag:(NSInteger)tag
179   m_tag=tag;
181 - (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
183   if (m_dest)
184   {
185     NMHDR nm={(HWND)self,(UINT_PTR)[self tag],TCN_SELCHANGE};
186     SendMessage((HWND)m_dest,WM_NOTIFY,nm.idFrom,(LPARAM)&nm);
187   }
189 @end
192 @implementation SWELL_ProgressView
193 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
195 -(NSInteger) tag
197   return m_tag;
199 -(void) setTag:(NSInteger)tag
201   m_tag=tag;
203 -(LRESULT)onSwellMessage:(UINT)msg p1:(WPARAM)wParam p2:(LPARAM)lParam
205   if (msg == PBM_SETRANGE)
206   {
207     [self setMinValue:LOWORD(lParam)];
208     [self setMaxValue:HIWORD(lParam)];
209   }
210   else if (msg==PBM_SETPOS)
211   {
212     [self setDoubleValue:(double)wParam];
213     [self stopAnimation:self];    
214   }
215   else if (msg==PBM_DELTAPOS)
216   {
217     [self incrementBy:(double)wParam];
218   }
219   return 0;
222 @end
224 @implementation SWELL_ListViewCell
225 -(NSColor *)highlightColorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView 
227   if ([controlView isKindOfClass:[SWELL_ListView class]] && ((SWELL_ListView *)controlView)->m_selColors) return nil;
228   if ([controlView isKindOfClass:[SWELL_TreeView class]] && ((SWELL_TreeView *)controlView)->m_selColors) return nil;
229   return [super highlightColorWithFrame:cellFrame inView:controlView];
231 @end
233 @implementation SWELL_StatusCell
234 -(id)initNewCell
236   if ((self=[super initTextCell:@""]))
237   {
238     status=0;
239   }
240   return self;
242 -(void)setStatusImage:(NSImage *)img
244   status=img;
246 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
248   if (status)
249   {
250 //    [controlView lockFocus];
251     int w=wdl_min(cellFrame.size.width, cellFrame.size.height);
252     [status drawInRect:NSMakeRect(cellFrame.origin.x,cellFrame.origin.y,w,cellFrame.size.height) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
253  //   [controlView unlockFocus];
254   }
255   cellFrame.origin.x += cellFrame.size.height + 2.0;
256   cellFrame.size.width -= cellFrame.size.height + 2.0;
257   [super drawWithFrame:cellFrame inView:controlView];
260 -(NSColor *)highlightColorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView 
262   if ([controlView isKindOfClass:[SWELL_ListView class]] && ((SWELL_ListView *)controlView)->m_selColors) return nil;
263   return [super highlightColorWithFrame:cellFrame inView:controlView];
266 @end
268 @implementation SWELL_TreeView
269 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
271 -(id) init
273   if ((self = [super init]))
274   {
275     m_fakerightmouse=false;
276     m_items=new WDL_PtrList<HTREEITEM__>;
277     m_fgColor=0;
278     m_selColors=0;
279   }
280   return self;
282 -(void) dealloc
284   if (m_items) m_items->Empty(true);
285   delete m_items;
286   m_items=0;
287   [m_fgColor release];
288   [m_selColors release];
289   [super dealloc];
292 -(bool) findItem:(HTREEITEM)item parOut:(HTREEITEM__ **)par idxOut:(int *)idx
294   if (!m_items||!item) return false;
295   int x=m_items->Find((HTREEITEM__*)item);
296   if (x>=0)
297   {
298     *par=NULL;
299     *idx=x;
300     return true;
301   }
302   for (x = 0; x < m_items->GetSize(); x++)
303   {
304     if (m_items->Get(x)->FindItem(item,par,idx)) return true;
305   }
307   return false;
310 -(NSInteger) outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
312   if (item == nil) return m_items ? m_items->GetSize() : 0;
313   return ((HTREEITEM__*)[item getValue])->m_children.GetSize();
316 - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
318   if (item==nil) return YES;
319   HTREEITEM__ *it=(HTREEITEM__ *)[item getValue];
320   
321   return it && it->m_haschildren;
324 - (id)outlineView:(NSOutlineView *)outlineView
325             child:(NSInteger)index
326            ofItem:(id)item
328   HTREEITEM__ *row=item ? ((HTREEITEM__*)[item getValue])->m_children.Get(index) : m_items ? m_items->Get(index) : 0;
330   return (id)(row ? row->m_dh : NULL);
333 - (id)outlineView:(NSOutlineView *)outlineView
334     objectValueForTableColumn:(NSTableColumn *)tableColumn
335            byItem:(id)item
337   if (!item) return @"";
338   HTREEITEM__ *it=(HTREEITEM__ *)[item getValue];
339   
340   if (!it || !it->m_value) return @"";
342   NSString *str=(NSString *)SWELL_CStringToCFString(it->m_value);    
343   
344   return [str autorelease];
349 -(void)mouseDown:(NSEvent *)theEvent
351   if (([theEvent modifierFlags] & NSControlKeyMask) && IsRightClickEmulateEnabled())
352   {
353     m_fakerightmouse=1;  
354   }
355   else 
356   {
357     
358     NMCLICK nmlv={{(HWND)self,(UINT_PTR)[self tag], NM_CLICK},};
359     SendMessage((HWND)[self target],WM_NOTIFY,nmlv.hdr.idFrom,(LPARAM)&nmlv);
360     
361     m_fakerightmouse=0;
362     [super mouseDown:theEvent];
363   }
366 -(void)mouseDragged:(NSEvent *)theEvent
370 -(void)mouseUp:(NSEvent *)theEvent
371 {   
372   if (m_fakerightmouse||([theEvent modifierFlags] & NSControlKeyMask)) [self rightMouseUp:theEvent];
373   else [super mouseUp:theEvent];
375 - (void)rightMouseUp:(NSEvent *)theEvent
377   bool wantContext=true;
379   NMCLICK nmlv={{(HWND)self,(UINT_PTR)[self tag], NM_RCLICK},};
380   if (SendMessage((HWND)[self target],WM_NOTIFY,nmlv.hdr.idFrom,(LPARAM)&nmlv)) wantContext=false;
381   
382   if (wantContext)
383   {
384     POINT p;
385     GetCursorPos(&p);
386     SendMessage((HWND)[self target],WM_CONTEXTMENU,(WPARAM)self,(p.x&0xffff)|(p.y<<16));
387   }
388   
389   m_fakerightmouse=0;
392 - (void)highlightSelectionInClipRect:(NSRect)theClipRect
394   if (m_selColors)
395   {
396     int a = GetFocus() == (HWND)self ? 0 : 2;
397     if ([m_selColors count] >= a)
398     {
399       NSColor *c=[m_selColors objectAtIndex:a];
400       if (c)
401       {
402         // calculate rect of selected items, combine with theClipRect, and fill these areas with our background (phew!)
404         NSInteger x = [self selectedRow];
405         if (x>=0)
406         {
407           NSRect r = [self rectOfRow:x];
408           r = NSIntersectionRect(r,theClipRect);
409           if (r.size.height>0 && r.size.width>0)
410           {
411             [c setFill];      
412             NSRectFill(r);
413           }
414         }
415         return ;
416       }
417     }
418   }
419   return [super highlightSelectionInClipRect:theClipRect];
425 @end
431 @implementation SWELL_ListView
432 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
434 -(LONG)getSwellStyle { return style; }
436 -(void)setSwellStyle:(LONG)st 
438   bool hdrchg= ((style&LVS_NOCOLUMNHEADER) != (st&LVS_NOCOLUMNHEADER));
439   style=st;
440   if ((style&LVS_REPORT) && hdrchg)
441   {
442     // todo some crap with NSTableView::setHeaderView, but it's complicated
443   }
446 -(id) init
448   if ((self = [super init]))
449   {
450     m_selColors=0;
451     m_fgColor = 0;
452     ownermode_cnt=0;
453     m_status_imagelist_type=-1;
454     m_status_imagelist=0;
455     m_leftmousemovecnt=0;
456     m_fakerightmouse=false;
457     m_lbMode=0;
458     m_fastClickMask=0;
459     m_last_shift_clicked_item = m_last_plainly_clicked_item=-1;
460     m_start_item=-1;
461     m_start_subitem=-1;
462     m_start_item_clickmode=0; // 0=clicked item, 1=clicked image, &2=sent drag message, &4=quickclick mode
463     m_cols = new WDL_PtrList<NSTableColumn>;
464     m_items=new WDL_PtrList<SWELL_ListView_Row>;
465   }
466   return self;
468 -(void) dealloc
470   if (m_items) m_items->Empty(true);
471   delete m_items;
472   delete m_cols;
473   m_cols=0;
474   m_items=0;
475   [m_fgColor release];
476   [m_selColors release];
477   [super dealloc];
480 -(int)getColumnPos:(int)idx // get current position of column that was originally at idx
482   int pos=idx;
483   if (m_cols)
484   {
485     NSTableColumn* col=m_cols->Get(idx);
486     if (col)
487     {
488       NSArray* arr=[self tableColumns];
489       if (arr)
490       {
491         pos=(int)[arr indexOfObject:col];
492       }
493     }
494   }
495   return pos;
498 - (void)highlightSelectionInClipRect:(NSRect)theClipRect
500   if (m_selColors)
501   {
502     int a = GetFocus() == (HWND)self ? 0 : 2;
503     if ([m_selColors count] >= a)
504     {
505       NSColor *c=[m_selColors objectAtIndex:a];
506       if (c)
507       {
508         // calculate rect of selected items, combine with theClipRect, and fill these areas with our background (phew!)
509         bool needfillset=true;
510         NSInteger x = [self rowAtPoint:NSMakePoint(0,theClipRect.origin.y)];
511         if (x<0)x=0;
512         const NSInteger n = [self numberOfRows];
513         for (;x <n;x++)
514         {
515           NSRect r = [self rectOfRow:x];
516           if (r.origin.y >= theClipRect.origin.y + theClipRect.size.height) break;
517           
518           if ([self isRowSelected:x])
519           {
520             r = NSIntersectionRect(r,theClipRect);
521             if (r.size.height>0 && r.size.width>0)
522             {
523               if (needfillset) { needfillset=false; [c setFill]; }
524               NSRectFill(r);
525             }
526           }
527         }
528         return ;
529       }
530     }
531   }
532   return [super highlightSelectionInClipRect:theClipRect];
534 -(int)getColumnIdx:(int)pos // get original index of column that is currently at position
536   int idx=pos;
537   NSArray* arr=[self tableColumns];
538   if (arr && pos>=0 && pos < [arr count])
539   {
540     NSTableColumn* col=[arr objectAtIndex:pos];
541     if (col && m_cols)
542     {
543       idx=m_cols->Find(col);
544     }
545   }
546   return idx;
549 -(NSInteger)columnAtPoint:(NSPoint)pt
551   int pos=(int)[super columnAtPoint:pt];
552   return (NSInteger) [self getColumnIdx:pos];
556 - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
558   return (!m_lbMode && (style & LVS_OWNERDATA)) ? ownermode_cnt : (m_items ? m_items->GetSize():0);
561 - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
563   NSString *str=NULL;
564   int image_idx=0;
565   
566   if (!m_lbMode && (style & LVS_OWNERDATA))
567   {
568     HWND tgt=(HWND)[self target];
570     char buf[1024];
571     NMLVDISPINFO nm={{(HWND)self, (UINT_PTR)[self tag], LVN_GETDISPINFO}};
572     nm.item.mask=LVIF_TEXT;
573     if (m_status_imagelist_type==LVSIL_STATE) nm.item.mask |= LVIF_STATE;
574     else if (m_status_imagelist_type == LVSIL_SMALL) nm.item.mask |= LVIF_IMAGE;
575     nm.item.iImage = -1;
576     nm.item.iItem=(int)rowIndex;
577     nm.item.iSubItem=m_cols->Find(aTableColumn);
578     nm.item.pszText=buf;
579     nm.item.cchTextMax=sizeof(buf)-1;
580     buf[0]=0;
581     SendMessage(tgt,WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
582     
583     if (m_status_imagelist_type == LVSIL_STATE) image_idx=(nm.item.state>>16)&0xff;
584     else if (m_status_imagelist_type == LVSIL_SMALL) image_idx = nm.item.iImage + 1;
585     str=(NSString *)SWELL_CStringToCFString(nm.item.pszText); 
586   }
587   else
588   {
589     char *p=NULL;
590     SWELL_ListView_Row *r=0;
591     if (m_items && m_cols && (r=m_items->Get(rowIndex))) 
592     {
593       p=r->m_vals.Get(m_cols->Find(aTableColumn));
594       if (m_status_imagelist_type == LVSIL_STATE || m_status_imagelist_type == LVSIL_SMALL)
595       {
596         image_idx=r->m_imageidx;
597       }
598     }
599     
600     str=(NSString *)SWELL_CStringToCFString(p);    
601     
602     if (style & LBS_OWNERDRAWFIXED)
603     {
604       SWELL_ODListViewCell *cell=[aTableColumn dataCell];
605       if ([cell isKindOfClass:[SWELL_ODListViewCell class]]) [cell setItemIdx:(int)rowIndex];
606     }
607   }
608   
609   if (!m_lbMode && m_status_imagelist)
610   {
611     SWELL_StatusCell *cell=(SWELL_StatusCell*)[aTableColumn dataCell];
612     if ([cell isKindOfClass:[SWELL_StatusCell class]])
613     {
614       HICON icon=m_status_imagelist->Get(image_idx-1);      
615       NSImage *img=NULL;
616       if (icon)  img=(NSImage *)GetNSImageFromHICON(icon);
617       [cell setStatusImage:img];
618     }
619   }
620   
621   return [str autorelease];
626 -(void)mouseDown:(NSEvent *)theEvent
628   if (([theEvent modifierFlags] & NSControlKeyMask) && IsRightClickEmulateEnabled())
629   {
630     m_fakerightmouse=1;  
631     m_start_item=-1;
632     m_start_subitem=-1;
633   }
634   else 
635   {
636     if ([theEvent clickCount]>1 && SWELL_NeedModernListViewHacks())
637     {
638       [super mouseDown:theEvent];
639       return;
640     }
641     m_leftmousemovecnt=0;
642     m_fakerightmouse=0;
643     
644     NSPoint pt=[theEvent locationInWindow];
645     pt=[self convertPoint:pt fromView:nil];
646     m_start_item=(int)[self rowAtPoint:pt];
647     m_start_subitem=(int)[self columnAtPoint:pt];
648     
649     
650     
651     m_start_item_clickmode=0;
652     if (m_start_item >=0 && (m_fastClickMask&(1<<m_start_subitem)))
653     {
654       NMLISTVIEW nmlv={{(HWND)self,(UINT_PTR)[self tag], NM_CLICK}, m_start_item, m_start_subitem, 0, 0, 0, {(int)floor(pt.x), (int)floor(pt.y)}, };
655       SWELL_ListView_Row *row=m_items->Get(nmlv.iItem);
656       if (row)
657         nmlv.lParam = row->m_param;
658       SendMessage((HWND)[self target],WM_NOTIFY,nmlv.hdr.idFrom,(LPARAM)&nmlv);
659       m_start_item_clickmode=4;
660     }
661     else
662     {
663       if (m_start_item>=0 && m_status_imagelist && LVSIL_STATE == m_status_imagelist_type && pt.x <= [self rowHeight]) // in left area
664       {
665         m_start_item_clickmode=1;
666       }
667     }
668   }
671 -(void)mouseDragged:(NSEvent *)theEvent
673   if (++m_leftmousemovecnt==4)
674   {
675     if (m_start_item>=0 && !(m_start_item_clickmode&3))
676     {
677       if (!m_lbMode)
678       {
679         // if m_start_item isnt selected, change selection to it now
680         if (!(m_start_item_clickmode&4) && ![self isRowSelected:m_start_item]) 
681         {
682           [self selectRowIndexes:[NSIndexSet indexSetWithIndex:m_start_item] byExtendingSelection:!!(GetAsyncKeyState(VK_CONTROL)&0x8000)];
683         }
684         NMLISTVIEW hdr={{(HWND)self,(UINT_PTR)[self tag],LVN_BEGINDRAG},m_start_item,m_start_subitem,0,};
685         SendMessage((HWND)[self target],WM_NOTIFY,hdr.hdr.idFrom, (LPARAM) &hdr);
686         m_start_item_clickmode |= 2;
687       }
688     }
689   }
690   else if (m_leftmousemovecnt > 4 && !(m_start_item_clickmode&1))
691   {
692     HWND tgt=(HWND)[self target];
693     POINT p;
694     GetCursorPos(&p);
695     ScreenToClient(tgt,&p);
696     
697     SendMessage(tgt,WM_MOUSEMOVE,0,(p.x&0xffff) + (((int)p.y)<<16));
698   }
701 -(void)mouseUp:(NSEvent *)theEvent
703   if ((m_fakerightmouse||([theEvent modifierFlags] & NSControlKeyMask)) && IsRightClickEmulateEnabled())
704   {
705     [self rightMouseUp:theEvent];
706   }
707   else 
708   {
709     if ([theEvent clickCount]>1 && SWELL_NeedModernListViewHacks())
710     {
711       [super mouseUp:theEvent];
712       return;
713     }
714     if (!(m_start_item_clickmode&1))
715     {
716       if (m_leftmousemovecnt>=0 && m_leftmousemovecnt<4 && !(m_start_item_clickmode&4))
717       {
718         const bool msel = [self allowsMultipleSelection];
719         if (m_lbMode && !msel) // listboxes --- allow clicking to reset the selection
720         {
721           [self deselectAll:self];
722         }
724         if (SWELL_NeedModernListViewHacks())
725         {
726           if (m_start_item>=0)
727           {
728             NSMutableIndexSet *m = [[NSMutableIndexSet alloc] init];
729             if (GetAsyncKeyState(VK_CONTROL)&0x8000)
730             {
731               [m addIndexes:[self selectedRowIndexes]];
732               if ([m containsIndex:m_start_item]) [m removeIndex:m_start_item];
733               else 
734               {
735                 if (!msel) [m removeAllIndexes];
736                 [m addIndex:m_start_item];
737               }
738               m_last_plainly_clicked_item = m_start_item;
739             }
740             else if (msel && (GetAsyncKeyState(VK_SHIFT)&0x8000))
741             {
742               [m addIndexes:[self selectedRowIndexes]];
743               const int n = ListView_GetItemCount((HWND)self);
744               if (m_last_plainly_clicked_item<0 || m_last_plainly_clicked_item>=n)
745                 m_last_plainly_clicked_item=m_start_item;
746   
747               if (m_last_shift_clicked_item>=0 && 
748                   m_last_shift_clicked_item<n && 
749                   m_last_plainly_clicked_item != m_last_shift_clicked_item)
750               {
751                 int a1 = m_last_shift_clicked_item;
752                 int a2 = m_last_plainly_clicked_item;
753                 if (a2<a1) { int tmp=a1; a1=a2; a2=tmp; }
754                 [m removeIndexesInRange:NSMakeRange(a1,a2-a1 + 1)];
755               }
756               
757               int a1 = m_start_item;
758               int a2 = m_last_plainly_clicked_item;
759               if (a2<a1) { int tmp=a1; a1=a2; a2=tmp; }
760               [m addIndexesInRange:NSMakeRange(a1,a2-a1 + 1)];
762               m_last_shift_clicked_item = m_start_item;
763             }
764             else
765             {
766               m_last_plainly_clicked_item = m_start_item;
767               [m addIndex:m_start_item];
768             }
769   
770             [self selectRowIndexes:m byExtendingSelection:NO];
771   
772             [m release];
773   
774           }
775           else [self deselectAll:self];
776         }
777         else
778         {
779           [super mouseDown:theEvent];
780           [super mouseUp:theEvent];
781         }
782       }
783       else if (m_leftmousemovecnt>=4)
784       {
785         HWND tgt=(HWND)[self target];
786         POINT p;
787         GetCursorPos(&p);
788         ScreenToClient(tgt,&p);      
789         SendMessage(tgt,WM_LBUTTONUP,0,(p.x&0xffff) + (((int)p.y)<<16));      
790       }
791     }
792   }
793   
794   if (!m_lbMode && !(m_start_item_clickmode&(2|4)))
795   {
796     NSPoint pt=[theEvent locationInWindow];
797     pt=[self convertPoint:pt fromView:nil];    
798     int col = (int)[self columnAtPoint:pt];
799     NMLISTVIEW nmlv={{(HWND)self,(UINT_PTR)[self tag], NM_CLICK}, (int)[self rowAtPoint:pt], col, 0, 0, 0, {(int)floor(pt.x), (int)floor(pt.y)}, };
800     SWELL_ListView_Row *row=m_items->Get(nmlv.iItem);
801     if (row) nmlv.lParam = row->m_param;
802     SendMessage((HWND)[self target],WM_NOTIFY,nmlv.hdr.idFrom,(LPARAM)&nmlv);
803   }  
806 - (void)rightMouseUp:(NSEvent *)theEvent
808   bool wantContext=true;
809   
810   if (!m_lbMode) 
811   {
812     NSPoint pt=[theEvent locationInWindow];
813     pt=[self convertPoint:pt fromView:nil];
814     
815     // note, windows selects on right mousedown    
816     NSInteger row =[self rowAtPoint:pt];
817     if (row >= 0 && ![self isRowSelected:row])
818     {
819       NSIndexSet* rows=[NSIndexSet indexSetWithIndex:row];
820       [self deselectAll:self];
821       [self selectRowIndexes:rows byExtendingSelection:NO];
822     }       
823     
824     NMLISTVIEW nmlv={{(HWND)self,(UINT_PTR)[self tag], NM_RCLICK}, (int)row, (int)[self columnAtPoint:pt], 0, 0, 0, {(int)floor(pt.x), (int)floor(pt.y)}, };
825     if (SendMessage((HWND)[self target],WM_NOTIFY,nmlv.hdr.idFrom,(LPARAM)&nmlv)) wantContext=false;
826   }
827   if (wantContext)
828   {
829     POINT p;
830     GetCursorPos(&p);
831     SendMessage((HWND)[self target],WM_CONTEXTMENU,(WPARAM)self,(p.x&0xffff)|(p.y<<16));
832   }
833   m_fakerightmouse=0;
836 -(LRESULT)onSwellMessage:(UINT)msg p1:(WPARAM)wParam p2:(LPARAM)lParam
838   HWND hwnd=(HWND)self;
839     switch (msg)
840     {
841       case LB_RESETCONTENT:
842           ownermode_cnt=0;
843           if (m_items) 
844           {
845             m_items->Empty(true);
846             [self reloadData];
847           }
848       return 0;
849       case LB_ADDSTRING:
850       case LB_INSERTSTRING:
851       {
852         int cnt=ListView_GetItemCount(hwnd);
853         if (msg == LB_ADDSTRING && (style & LBS_SORT))
854         {
855           SWELL_ListView *tv=(SWELL_ListView*)hwnd;
856           if (tv->m_lbMode && tv->m_items)
857           {            
858             cnt=ptrlist_bsearch_mod((char *)lParam,tv->m_items,_listviewrowSearchFunc,NULL);
859           }
860         }
861         if (msg==LB_ADDSTRING) wParam=cnt;
862         else if (wParam > cnt) wParam=cnt;
863         LVITEM lvi={LVIF_TEXT,(int)wParam,0,0,0,(char *)lParam};
864         ListView_InsertItem(hwnd,&lvi);
865       }
866       return wParam;
867       case LB_GETCOUNT: return ListView_GetItemCount(hwnd);
868       case LB_SETSEL:
869         ListView_SetItemState(hwnd, (int)lParam,wParam ? LVIS_SELECTED : 0,LVIS_SELECTED);
870         return 0;
871       case LB_GETTEXT:
872         if (lParam)
873         {
874           SWELL_ListView_Row *row=self->m_items ? self->m_items->Get(wParam) : NULL;
875           *(char *)lParam = 0;
876           if (row && row->m_vals.Get(0))
877           {
878             strcpy((char *)lParam, row->m_vals.Get(0));
879             return (LRESULT)strlen(row->m_vals.Get(0));
880           }
881         }
882       return LB_ERR;
883       case LB_GETTEXTLEN:
884         {
885           SWELL_ListView_Row *row=self->m_items ? self->m_items->Get(wParam) : NULL;
886           if (row) 
887           {
888             const char *p=row->m_vals.Get(0);
889             return p?strlen(p):0;
890           }
891         }
892       return LB_ERR;
893       case LB_GETSEL:
894         return !!(ListView_GetItemState(hwnd,(int)wParam,LVIS_SELECTED)&LVIS_SELECTED);
895       case LB_GETCURSEL:
896         return [self selectedRow];
897       case LB_SETCURSEL:
898       {
899         if (wParam<ListView_GetItemCount(hwnd))
900         {
901           [self selectRowIndexes:[NSIndexSet indexSetWithIndex:wParam] byExtendingSelection:NO];        
902           [self scrollRowToVisible:wParam];
903         }
904         else
905         {
906           [self deselectAll:self];
907         }
908       }
909         return 0;
910       case LB_GETITEMDATA:
911       {
912         if (m_items)
913         {
914           SWELL_ListView_Row *row=m_items->Get(wParam);
915           if (row) return row->m_param;
916         }
917       }
918         return 0;
919       case LB_SETITEMDATA:
920       {
921         if (m_items)
922         {
923           SWELL_ListView_Row *row=m_items->Get(wParam);
924           if (row) row->m_param=lParam;
925         }
926       }
927         return 0;
928       case LB_GETSELCOUNT:
929         return [[self selectedRowIndexes] count];
930       case LB_DELETESTRING:
931         ListView_DeleteItem((HWND)self, (int)wParam);
932         return 0;
933     }
934   return 0;
937 -(int)getSwellNotificationMode
939   return m_lbMode;
941 -(void)setSwellNotificationMode:(int)lbMode
943   m_lbMode=lbMode;
946 -(void)onSwellCommand:(int)cmd
948   // ignore commands
951 @end
953 @implementation SWELL_ImageButtonCell
954 - (NSRect)drawTitle:(NSAttributedString *)title withFrame:(NSRect)frame inView:(NSView *)controlView
956   return NSMakeRect(0,0,0,0);
958 @end
960 @implementation SWELL_ODButtonCell
961 - (BOOL)isTransparent
963   return YES;
965 - (BOOL)isOpaque
967   return NO;
970 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
972   NSView *ctl=[self controlView];
973   if (!ctl) { [super drawWithFrame:cellFrame inView:controlView]; return; }
974   
975   HDC hdc=GetDC((HWND)controlView);
976   if (hdc)
977   {
978     HWND notWnd = GetParent((HWND)ctl);
979     RECT r={(int)(cellFrame.origin.x+0.5),(int)(cellFrame.origin.y+0.5)};
980     r.right=r.left+(int)(cellFrame.size.width+0.5);
981     r.bottom=r.top+(int)(cellFrame.size.height+0.5);
982     DRAWITEMSTRUCT dis={ODT_BUTTON,(UINT)[ctl tag],0,0,0,(HWND)ctl,hdc,{0,},0};
983     dis.rcItem = r;
984     SendMessage(notWnd,WM_DRAWITEM,dis.CtlID,(LPARAM)&dis);
985   
986     ReleaseDC((HWND)controlView,hdc);
987   }
988   
990 @end
992 @implementation SWELL_ODListViewCell
993 -(void)setOwnerControl:(SWELL_ListView *)t { m_ownctl=t; m_lastidx=0; }
994 -(void)setItemIdx:(int)idx
996   m_lastidx=idx;
998 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
1000   if (!m_ownctl) { [super drawInteriorWithFrame:cellFrame inView:controlView]; return; }
1001   
1002   int itemidx=m_lastidx;
1003   LPARAM itemData=0;
1004   SWELL_ListView_Row *row=m_ownctl->m_items->Get(itemidx);
1005   if (row) itemData=row->m_param;
1007   HDC hdc=GetDC((HWND)controlView);
1008   if (hdc)
1009   {
1010     HWND notWnd = GetParent((HWND)m_ownctl);
1011     RECT r={(int)(cellFrame.origin.x+0.5),(int)(cellFrame.origin.y+0.5)};
1012     r.right=r.left+(int)(cellFrame.size.width+0.5);
1013     r.bottom=r.top+(int)(cellFrame.size.height+0.5);
1014     DRAWITEMSTRUCT dis={ODT_LISTBOX,(UINT)[m_ownctl tag],(UINT)itemidx,0,0,(HWND)m_ownctl,hdc,{0,},(DWORD_PTR)itemData};
1015     dis.rcItem = r;
1016     SendMessage(notWnd,WM_DRAWITEM,dis.CtlID,(LPARAM)&dis);
1017   
1018     ReleaseDC((HWND)controlView,hdc);
1019   }
1023 @end
1029 HWND GetDlgItem(HWND hwnd, int idx)
1031   if (!hwnd) return 0;
1033   NSView *v=0;
1034   id pid=(id)hwnd;
1035   if ([pid isKindOfClass:[NSWindow class]]) v=[((NSWindow *)pid) contentView];
1036   else if ([pid isKindOfClass:[NSView class]]) v=(NSView *)pid;
1037   
1038   if (!idx || !v) return (HWND)v;
1039   
1040   SWELL_BEGIN_TRY
1042   NSArray *ar = [v subviews];
1043   const NSInteger n=[ar count];
1044   for (NSInteger x=0;x<n;x++)
1045   {
1046     NSView *sv = [ar objectAtIndex:x];
1047     if (sv)
1048     {
1049       if ([sv respondsToSelector:@selector(tag)] && [sv tag] == idx) return (HWND)sv;
1051       if (sv && [sv isKindOfClass:[NSScrollView class]])
1052       {
1053         sv=[(NSScrollView *)sv documentView];
1054         if (sv && [sv respondsToSelector:@selector(tag)] && [sv tag] == idx) return (HWND)sv;
1055       }
1056       if (sv && [sv isKindOfClass:[NSClipView class]]) 
1057       {
1058         sv = [(NSClipView *)sv documentView];
1059         if (sv && [sv respondsToSelector:@selector(tag)] && [sv tag] == idx) return (HWND)sv;
1060       }
1061     }
1062   }
1063   // we might want to enable this for max compat with old code, but hopefully not:  return [v viewWithTag:idx]; 
1064   SWELL_END_TRY(;)
1065   return NULL;
1069 LONG_PTR SetWindowLong(HWND hwnd, int idx, LONG_PTR val)
1071   if (!hwnd) return 0;
1073   SWELL_BEGIN_TRY
1074   id pid=(id)hwnd;
1075   if (idx==GWL_EXSTYLE && [pid respondsToSelector:@selector(swellSetExtendedStyle:)])
1076   {
1077     LONG ret=(LONG) [(SWELL_hwndChild*)pid swellGetExtendedStyle];
1078     [(SWELL_hwndChild*)pid swellSetExtendedStyle:(LONG)val];
1079     return ret;
1080   }
1081   if (idx==GWL_USERDATA && [pid respondsToSelector:@selector(setSwellUserData:)])
1082   {
1083     LONG_PTR ret=(LONG_PTR)[(SWELL_hwndChild*)pid getSwellUserData];
1084     [(SWELL_hwndChild*)pid setSwellUserData:(LONG_PTR)val];
1085     return ret;
1086   }
1087     
1088   if (idx==GWL_ID && [pid respondsToSelector:@selector(tag)] && [pid respondsToSelector:@selector(setTag:)])
1089   {
1090     int ret= (int) [pid tag];
1091     [pid setTag:(int)val];
1092     return (LONG_PTR)ret;
1093   }
1094   
1095   if (idx==GWL_WNDPROC && [pid respondsToSelector:@selector(setSwellWindowProc:)])
1096   {
1097     WNDPROC ov=(WNDPROC)[pid getSwellWindowProc];
1098     [pid setSwellWindowProc:(WNDPROC)val];
1099     return (LONG_PTR)ov;
1100   }
1101   if (idx==DWL_DLGPROC && [pid respondsToSelector:@selector(setSwellDialogProc:)])
1102   {
1103     DLGPROC ov=(DLGPROC)[pid getSwellDialogProc];
1104     [pid setSwellDialogProc:(DLGPROC)val];
1105     return (LONG_PTR)ov;
1106   }
1107   
1108   if (idx==GWL_STYLE)
1109   {
1110     if ([pid respondsToSelector:@selector(setSwellStyle:)])
1111     {
1112       LONG ov=[pid getSwellStyle];
1113       [pid setSwellStyle:(LONG)val];
1114       return ov;
1115     }
1116     else if ([pid isKindOfClass:[NSButton class]]) 
1117     {
1118       int ret=(int)GetWindowLong(hwnd,idx);
1119       
1120       if ((val&0xf) == BS_AUTO3STATE)
1121       {
1122         [pid setButtonType:NSSwitchButton];
1123         [pid setAllowsMixedState:YES];
1124         if ([pid isKindOfClass:[SWELL_Button class]]) [pid swellSetRadioFlags:0];
1125       }    
1126       else if ((val & 0xf) == BS_AUTOCHECKBOX)
1127       {
1128         [pid setButtonType:NSSwitchButton];
1129         [pid setAllowsMixedState:NO];
1130         if ([pid isKindOfClass:[SWELL_Button class]]) [pid swellSetRadioFlags:0];
1131       }
1132       else if ((val &  0xf) == BS_AUTORADIOBUTTON)
1133       {
1134         [pid setButtonType:NSRadioButton];
1135         if ([pid isKindOfClass:[SWELL_Button class]]) [pid swellSetRadioFlags:(val&WS_GROUP)?3:1];
1136       }               
1137       
1138       return ret;
1139     }
1140     else 
1141     {
1142       if ([[pid window] contentView] == pid)
1143       {
1144         NSView *tv=(NSView *)pid;
1145         NSWindow *oldw = [tv window];
1146         NSUInteger smask = [oldw styleMask];
1147         int mf=0;
1148         if (smask & NSTitledWindowMask)
1149         {
1150           mf|=WS_CAPTION;
1151           if (smask & NSResizableWindowMask) mf|=WS_THICKFRAME;
1152         }
1153         if (mf != (val&(WS_CAPTION|WS_THICKFRAME)))
1154         {
1155           BOOL dovis = IsWindowVisible((HWND)oldw);
1156           NSWindow *oldpar = [oldw parentWindow];
1157           char oldtitle[2048];
1158           oldtitle[0]=0;
1159           GetWindowText(hwnd,oldtitle,sizeof(oldtitle));
1160           NSRect fr=[oldw frame];
1161           HWND oldOwner=NULL;
1162           if ([oldw respondsToSelector:@selector(swellGetOwner)]) oldOwner=(HWND)[(SWELL_ModelessWindow*)oldw swellGetOwner];
1163           NSInteger oldlevel = [oldw level];
1165           
1166           [tv retain];
1167           SWELL_hwndChild *tempview = [[SWELL_hwndChild alloc] initChild:nil Parent:(NSView *)oldw dlgProc:nil Param:0];          
1168           [tempview release];          
1169           
1170           unsigned int mask=0;
1171           
1172           if (val & WS_CAPTION)
1173           {
1174             mask|=NSTitledWindowMask;
1175             if (val & WS_THICKFRAME)
1176               mask|=NSMiniaturizableWindowMask|NSClosableWindowMask|NSResizableWindowMask;
1177           }
1178       
1179           HWND SWELL_CreateModelessFrameForWindow(HWND childW, HWND ownerW, unsigned int);
1180           HWND bla=SWELL_CreateModelessFrameForWindow((HWND)tv,(HWND)oldOwner,mask);
1181           
1182           if (bla)
1183           {
1184             [tv release];
1185             // move owned windows over
1186             if ([oldw respondsToSelector:@selector(swellGetOwnerWindowHead)])
1187             {
1188               void **p=(void **)[(SWELL_ModelessWindow*)oldw swellGetOwnerWindowHead];
1189               if (p && [(id)bla respondsToSelector:@selector(swellGetOwnerWindowHead)])
1190               {
1191                 void **p2=(void **)[(SWELL_ModelessWindow*)bla swellGetOwnerWindowHead];
1192                 if (p && p2) 
1193                 {
1194                   *p2=*p;
1195                   *p=0;
1196                   OwnedWindowListRec *rec = (OwnedWindowListRec *) *p2;
1197                   while (rec)
1198                   {
1199                     if (rec->hwnd && [rec->hwnd respondsToSelector:@selector(swellSetOwner:)])
1200                       [(SWELL_ModelessWindow *)rec->hwnd swellSetOwner:(id)bla];
1201                     rec=rec->_next;
1202                   }
1203                 }
1204               }
1205             }
1206             // move all child and owned windows over to new window
1207             NSArray *ar=[oldw childWindows];
1208             if (ar)
1209             {
1210               int x;
1211               for (x = 0; x < [ar count]; x ++)
1212               {
1213                 NSWindow *cw=[ar objectAtIndex:x];
1214                 if (cw)
1215                 {
1216                   [cw retain];
1217                   [oldw removeChildWindow:cw];
1218                   [(NSWindow *)bla addChildWindow:cw ordered:NSWindowAbove];
1219                   [cw release];
1220                   
1221                   
1222                 }
1223               }
1224             }
1225           
1226             if (oldpar) [oldpar addChildWindow:(NSWindow *)bla ordered:NSWindowAbove];
1227             if (oldtitle[0]) SetWindowText(hwnd,oldtitle);
1228             
1229             [(NSWindow *)bla setFrame:fr display:dovis];
1230             [(NSWindow *)bla setLevel:oldlevel];
1231             if (dovis) ShowWindow(bla,SW_SHOW);
1232       
1233             DestroyWindow((HWND)oldw);
1234           }
1235           else
1236           {
1237             [oldw setContentView:tv];
1238             [tv release];
1239           }  
1240       
1241         }
1242       }
1243     }
1244     return 0;
1245   }
1247   
1248   if ([pid respondsToSelector:@selector(setSwellExtraData:value:)])
1249   {
1250     LONG_PTR ov=0;
1251     if ([pid respondsToSelector:@selector(getSwellExtraData:)]) ov=(LONG_PTR)[pid getSwellExtraData:idx];
1253     [pid setSwellExtraData:idx value:val];
1254     
1255     return ov;
1256   }
1257    
1258   SWELL_END_TRY(;)
1259   return 0;
1262 LONG_PTR GetWindowLong(HWND hwnd, int idx)
1264   if (!hwnd) return 0;
1265   id pid=(id)hwnd;
1267   SWELL_BEGIN_TRY
1268   
1269   if (idx==GWL_EXSTYLE && [pid respondsToSelector:@selector(swellGetExtendedStyle)])
1270   {
1271     return (LONG_PTR)[pid swellGetExtendedStyle];
1272   }
1273   
1274   if (idx==GWL_USERDATA && [pid respondsToSelector:@selector(getSwellUserData)])
1275   {
1276     return (LONG_PTR)[pid getSwellUserData];
1277   }
1278   if (idx==GWL_USERDATA && [pid isKindOfClass:[NSText class]])
1279   {
1280     return 0xdeadf00b;
1281   }
1282   
1283   if (idx==GWL_ID && [pid respondsToSelector:@selector(tag)])
1284     return [pid tag];
1285   
1286   
1287   if (idx==GWL_WNDPROC && [pid respondsToSelector:@selector(getSwellWindowProc)])
1288   {
1289     return (LONG_PTR)[pid getSwellWindowProc];
1290   }
1291   if (idx==DWL_DLGPROC && [pid respondsToSelector:@selector(getSwellDialogProc)])
1292   {
1293     return (LONG_PTR)[pid getSwellDialogProc];
1294   }  
1295   if (idx==GWL_STYLE)
1296   {
1297     int ret=0;
1298     if ([pid respondsToSelector:@selector(getSwellStyle)])
1299     {
1300       return (LONG_PTR)[pid getSwellStyle];
1301     }    
1302     
1303     if ([pid isKindOfClass:[NSButton class]]) 
1304     {
1305       int tmp;
1306       if ([pid allowsMixedState]) ret |= BS_AUTO3STATE;
1307       else if ([pid isKindOfClass:[SWELL_Button class]] && (tmp = (int)[pid swellGetRadioFlags]))
1308       {
1309         ret |= BS_AUTORADIOBUTTON;
1310         if (tmp&2) ret|=WS_GROUP;
1311       }
1312       else ret |= BS_AUTOCHECKBOX; 
1313     }
1314     
1315     if ([pid isKindOfClass:[NSView class]])
1316     {
1317       if ([[pid window] contentView] != pid) ret |= WS_CHILDWINDOW;
1318       else
1319       {
1320         NSUInteger smask  =[[pid window] styleMask];
1321         if (smask & NSTitledWindowMask)
1322         {
1323           ret|=WS_CAPTION;
1324           if (smask & NSResizableWindowMask) ret|=WS_THICKFRAME;
1325         }
1326       }
1327     }
1328     
1329     return ret;
1330   }
1331   if ([pid respondsToSelector:@selector(getSwellExtraData:)])
1332   {
1333     return (LONG_PTR)[pid getSwellExtraData:idx];
1334   }
1335   
1336   SWELL_END_TRY(;)
1337   return 0;
1340 static bool IsWindowImpl(NSView *ch, NSView *par)
1342   if (!par || ![par isKindOfClass:[NSView class]]) return false;
1344   NSArray *ar = [par subviews];
1345   if (!ar) return false;
1346   [ar retain];
1347   NSInteger x,n=[ar count];
1348   for (x=0;x<n;x++)
1349     if ([ar objectAtIndex:x] == ch) 
1350     {
1351       [ar release];
1352       return true;
1353     }
1355   for (x=0;x<n;x++)
1356     if (IsWindowImpl(ch,[ar objectAtIndex:x])) 
1357     {
1358       [ar release];
1359       return true;
1360     }
1362   [ar release];
1363   return false;
1365 bool IsWindow(HWND hwnd)
1367   if (!hwnd) return false;
1368   // this is very costly, but required
1369   SWELL_BEGIN_TRY
1371   NSArray *ch=[NSApp windows];
1372   [ch retain];
1373   NSInteger x,n=[ch count];
1374   for(x=0;x<n; x ++)
1375   {
1376     @try { 
1377       NSWindow *w = [ch objectAtIndex:x]; 
1378       if (w == (NSWindow *)hwnd || [w contentView] == (NSView *)hwnd) 
1379       {
1380         [ch release];
1381         return true;
1382       }
1383     }
1384     @catch (NSException *ex) { 
1385     }
1386     @catch (id ex) {
1387     }
1388   }
1389   for(x=0;x<n; x ++)
1390   {
1391     @try { 
1392       NSWindow *w = [ch objectAtIndex:x];
1393       if (w && 
1394           // only validate children of our windows (maybe an option for this?)
1395           ([w isKindOfClass:[SWELL_ModelessWindow class]] || [w isKindOfClass:[SWELL_ModalDialog class]]) &&
1396           IsWindowImpl((NSView*)hwnd,[w contentView])) 
1397       {
1398         [ch release];
1399         return true;
1400       }
1401     } 
1402     @catch (NSException *ex) { 
1403     }
1404     @catch (id ex) {
1405     }
1406   }
1407   [ch release];
1409   SWELL_END_TRY(;)
1410   return false;
1413 bool IsWindowVisible(HWND hwnd)
1415   if (!hwnd) return false;
1417   SWELL_BEGIN_TRY
1418   id turd=(id)hwnd;
1419   if ([turd isKindOfClass:[NSView class]])
1420   {
1421     NSWindow *w = [turd window];
1422     if (w && ![w isVisible]) return false;
1423     
1424     return ![turd isHiddenOrHasHiddenAncestor];
1425   }
1426   if ([turd isKindOfClass:[NSWindow class]])
1427   {
1428     return !![turd isVisible];
1429   }
1430   SWELL_END_TRY(;)
1431   return true;
1434 static void *__GetNSImageFromHICON(HICON ico) // local copy to not be link dependent on swell-gdi.mm
1436   HGDIOBJ__ *i = (HGDIOBJ__ *)ico;
1437   if (!i || i->type != TYPE_BITMAP) return 0;
1438   return i->bitmapptr;
1442 @implementation SWELL_Button : NSButton
1444 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
1446 -(id) init {
1447   self = [super init];
1448   if (self != nil) {
1449     m_userdata=0;
1450     m_swellGDIimage=0;
1451     m_radioflags=0;
1452   }
1453   return self;
1455 -(int)swellGetRadioFlags { return m_radioflags; }
1456 -(void)swellSetRadioFlags:(int)f { m_radioflags=f; }
1457 -(LONG_PTR)getSwellUserData { return m_userdata; }
1458 -(void)setSwellUserData:(LONG_PTR)val {   m_userdata=val; }
1460 -(void)setSwellGDIImage:(void *)par
1462   m_swellGDIimage=par;
1464 -(void *)getSwellGDIImage
1466   return m_swellGDIimage;
1469 @end
1471 LRESULT SendMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1473   if (!hwnd) return 0;
1475   SWELL_BEGIN_TRY
1476   id obj=(id)hwnd;
1477   if ([obj respondsToSelector:@selector(onSwellMessage:p1:p2:)])
1478   {
1479     return (LRESULT) [obj onSwellMessage:msg p1:wParam p2:lParam];
1480   }
1481   else 
1482   {
1483     if (msg == BM_GETCHECK && [obj isKindOfClass:[NSButton class]])
1484     {
1485       NSInteger a=[(NSButton*)obj state];
1486       if (a==NSMixedState) return BST_INDETERMINATE;
1487       return a!=NSOffState;
1488     }
1489     if (msg == BM_SETCHECK && [obj isKindOfClass:[NSButton class]])
1490     {
1491       [(NSButton*)obj setState:(wParam&BST_INDETERMINATE)?NSMixedState:((wParam&BST_CHECKED)?NSOnState:NSOffState)];
1492       return 0;
1493     }
1494     if ((msg==BM_GETIMAGE || msg == BM_SETIMAGE) && [obj isKindOfClass:[SWELL_Button class]])
1495     {
1496       if (wParam != IMAGE_BITMAP && wParam != IMAGE_ICON) return 0; // ignore unknown types
1497       LONG_PTR ret=(LONG_PTR) (void *)[obj getSwellGDIImage];
1498       if (msg==BM_SETIMAGE)
1499       {
1500         NSImage *img=NULL;
1501         if (lParam) img=(NSImage *)__GetNSImageFromHICON((HICON)lParam);
1502         [obj setImage:img];
1503         [obj setSwellGDIImage:(void *)(img?lParam:0)];
1504       }
1505       return ret;
1506     }
1507     else if (msg >= CB_ADDSTRING && msg <= CB_INITSTORAGE && ([obj isKindOfClass:[NSPopUpButton class]] || [obj isKindOfClass:[NSComboBox class]]))
1508     {
1509         switch (msg)
1510         {
1511           case CB_ADDSTRING: return SWELL_CB_AddString(hwnd,0,(char*)lParam); 
1512           case CB_DELETESTRING: SWELL_CB_DeleteString(hwnd,0,(int)wParam); return 1;
1513           case CB_GETCOUNT: return SWELL_CB_GetNumItems(hwnd,0);
1514           case CB_GETCURSEL: return SWELL_CB_GetCurSel(hwnd,0);
1515           case CB_GETLBTEXT: return SWELL_CB_GetItemText(hwnd,0,(int)wParam,(char *)lParam, 1<<20);
1516           case CB_GETLBTEXTLEN: return SWELL_CB_GetItemText(hwnd,0,(int)wParam,NULL,0);
1517           case CB_INSERTSTRING: return SWELL_CB_InsertString(hwnd,0,(int)wParam,(char *)lParam);
1518           case CB_RESETCONTENT: SWELL_CB_Empty(hwnd,0); return 0;
1519           case CB_SETCURSEL: SWELL_CB_SetCurSel(hwnd,0,(int)wParam); return 0;
1520           case CB_GETITEMDATA: return SWELL_CB_GetItemData(hwnd,0,(int)wParam);
1521           case CB_SETITEMDATA: SWELL_CB_SetItemData(hwnd,0,(int)wParam,lParam); return 0;
1522           case CB_FINDSTRING:
1523           case CB_FINDSTRINGEXACT:
1524             if (lParam) return SWELL_CB_FindString(hwnd,0,(int)wParam,(const char *)lParam,msg==CB_FINDSTRINGEXACT);
1525             return CB_ERR;
1526           case CB_INITSTORAGE: return 0;                                                      
1527         }
1528         return 0;
1529     }
1530     else if (msg >= TBM_GETPOS && msg <= TBM_SETRANGE && ([obj isKindOfClass:[NSSlider class]]))
1531     {
1532         switch (msg)
1533         {
1534           case TBM_GETPOS: return SWELL_TB_GetPos(hwnd,0);
1535           case TBM_SETTIC: SWELL_TB_SetTic(hwnd,0,(int)lParam); return 1;
1536           case TBM_SETPOS: SWELL_TB_SetPos(hwnd,0,(int)lParam); return 1;
1537           case TBM_SETRANGE: SWELL_TB_SetRange(hwnd,0,LOWORD(lParam),HIWORD(lParam)); return 1;
1538         }
1539         return 0;
1540     }
1541     else if ((msg == EM_SETSEL || msg == EM_GETSEL || msg == EM_SETPASSWORDCHAR) && ([obj isKindOfClass:[NSTextField class]]))
1542     { 
1543       if (msg == EM_GETSEL)
1544       {
1545         NSRange range={0,};
1546         NSResponder *rs = [[obj window] firstResponder];
1547         if ([rs isKindOfClass:[NSView class]] && [(NSView *)rs isDescendantOf:obj])
1548         {
1549           NSText* text=[[obj window] fieldEditor:YES forObject:(NSTextField*)obj];  
1550           if (text) range=[text selectedRange];
1551         }
1552         if (wParam) *(int*)wParam=(int)range.location;
1553         if (lParam) *(int*)lParam=(int)(range.location+range.length);
1554       }      
1555       else if (msg == EM_SETSEL)
1556       {        
1557         //        [(NSTextField*)obj selectText:obj]; // Force the window's text field editor onto this control
1558         // don't force it, just ignore EM_GETSEL/EM_SETSEL if not in focus
1559         NSResponder *rs = [[obj window] firstResponder];
1560         if ([rs isKindOfClass:[NSView class]] && [(NSView *)rs isDescendantOf:obj])
1561         {
1562           NSText* text = [[obj window] fieldEditor:YES forObject:(NSTextField*)obj]; // then get it from the window 
1563           NSUInteger sl = [[text string] length];
1564           if (wParam == -1) lParam = wParam = 0;
1565           else if (lParam == -1) lParam = sl;        
1566           if (wParam>sl) wParam=sl;
1567           if (lParam>sl) lParam=sl;      
1568           if (text) [text setSelectedRange:NSMakeRange(wParam, wdl_max(lParam-wParam,0))]; // and set the range
1569         }
1570       }
1571       else if (msg == EM_SETPASSWORDCHAR)
1572       {
1573         // not implemented, because it requires replacing obj within its parent window
1574         // instead caller explicitly destroy the edit control and create a new one with ES_PASSWORD
1575       }
1576       return 0;
1577     }
1578     else
1579     {
1580       NSWindow *w;
1581       NSView *v;
1582       // if content view gets unhandled message send to window
1583       if ([obj isKindOfClass:[NSView class]] && (w=[obj window]) && [w contentView] == obj && [w respondsToSelector:@selector(onSwellMessage:p1:p2:)])
1584       {
1585         return (LRESULT) [(SWELL_hwndChild *)w onSwellMessage:msg p1:wParam p2:lParam];
1586       }
1587       // if window gets unhandled message send to content view
1588       else if ([obj isKindOfClass:[NSWindow class]] && (v=[obj contentView]) && [v respondsToSelector:@selector(onSwellMessage:p1:p2:)])
1589       {
1590         return (LRESULT) [(SWELL_hwndChild *)v onSwellMessage:msg p1:wParam p2:lParam];
1591       }
1592     }
1593   }
1594   SWELL_END_TRY(;)
1595   return 0;
1598 void DestroyWindow(HWND hwnd)
1600   if (!hwnd) return;
1601   SWELL_BEGIN_TRY
1602   id pid=(id)hwnd;
1603   if ([pid isKindOfClass:[NSView class]])
1604   {
1605     KillTimer(hwnd,~(UINT_PTR)0);
1606     sendSwellMessage((id)pid,WM_DESTROY,0,0);
1607       
1608     NSWindow *pw = [(NSView *)pid window];
1609     if (pw && [pw contentView] == pid) // destroying contentview should destroy top level window
1610     {
1611       DestroyWindow((HWND)pw);
1612     }
1613     else 
1614     {
1615       if (pw && [NSApp keyWindow] == pw)
1616       {
1617         id foc=[pw firstResponder];
1618         if (foc && (foc == pid || IsChild((HWND)pid,(HWND)foc)))
1619         {
1620           HWND h=GetParent((HWND)pid);
1621           if (h) SetFocus(h);
1622         }
1623       }
1624       [(NSView *)pid removeFromSuperview];
1625     }
1626   }
1627   else if ([pid isKindOfClass:[NSWindow class]])
1628   {
1629     KillTimer(hwnd,~(UINT_PTR)0);
1630     sendSwellMessage([(id)pid contentView],WM_DESTROY,0,0);
1631     sendSwellMessage((id)pid,WM_DESTROY,0,0);
1632       
1633     if ([(id)pid respondsToSelector:@selector(swellDoDestroyStuff)])
1634       [(id)pid swellDoDestroyStuff];
1635       
1636     NSWindow *par=[(NSWindow*)pid parentWindow];
1637     if (par)
1638     {
1639       [par removeChildWindow:(NSWindow*)pid];
1640     }
1641     [(NSWindow *)pid close]; // this is probably bad, but close takes too long to close!
1642   }
1643   SWELL_END_TRY(;)
1646 void EnableWindow(HWND hwnd, int enable)
1648   if (!hwnd) return;
1649   SWELL_BEGIN_TRY
1650   id bla=(id)hwnd;
1651   if ([bla isKindOfClass:[NSWindow class]]) bla = [bla contentView];
1652     
1653   if (bla && [bla respondsToSelector:@selector(setEnabled:)])
1654   {
1655     if (enable == -1000 && [bla respondsToSelector:@selector(setEnabledSwellNoFocus)])
1656       [bla setEnabledSwellNoFocus];
1657     else
1658       [bla setEnabled:(enable?YES:NO)];
1659     if ([bla isKindOfClass:[SWELL_TextField class]])
1660     {
1661       NSTextField* txt = (NSTextField*)bla;
1662       if (![txt isEditable] && ![txt isBordered] && ![txt drawsBackground]) // looks like a static text control
1663       {
1664         NSColor* col = [txt textColor];
1665         float alpha = (enable ? 1.0f : 0.5f);
1666         [txt setTextColor:[col colorWithAlphaComponent:alpha]];
1667       }
1668     }    
1669   }
1670   SWELL_END_TRY(;)
1673 void SetForegroundWindow(HWND hwnd)
1675   SetFocus(hwnd);
1678 void SetFocus(HWND hwnd) // these take NSWindow/NSView, and return NSView *
1680   id r=(id) hwnd;
1681   if (!r) return;
1682   
1683   SWELL_BEGIN_TRY
1684   if ([r isKindOfClass:[NSWindow class]])
1685   {
1686     [(NSWindow *)r makeFirstResponder:[(NSWindow *)r contentView]]; 
1687     if ([(NSWindow *)r isVisible]) [(NSWindow *)r makeKeyAndOrderFront:nil];
1688   }
1689   else if ([r isKindOfClass:[NSView class]])
1690   {
1691     NSWindow *wnd=[(NSView *)r window];
1692     if (wnd)
1693     {
1694       [wnd makeFirstResponder:r];
1695       if ([wnd isVisible])
1696       {
1697         [wnd makeKeyAndOrderFront:nil];
1698       }
1699     }
1700   }
1701   SWELL_END_TRY(;)
1704 void SWELL_GetViewPort(RECT *r, const RECT *sourcerect, bool wantWork)
1706   SWELL_BEGIN_TRY
1708   NSArray *ar=[NSScreen screens];
1709   
1710   const NSInteger cnt=[ar count];
1711   int cx=0;
1712   int cy=0;
1713   if (sourcerect)
1714   {
1715     cx=(sourcerect->left+sourcerect->right)/2;
1716     cy=(sourcerect->top+sourcerect->bottom)/2;
1717   }
1718   for (NSInteger x = 0; x < cnt; x ++)
1719   {
1720     NSScreen *sc=[ar objectAtIndex:x];
1721     if (sc)
1722     {
1723       NSRect tr=wantWork ? [sc visibleFrame] : [sc frame];
1724       if (!x || (cx >= tr.origin.x && cx < tr.origin.x+tr.size.width  &&
1725                 cy >= tr.origin.y && cy < tr.origin.y+tr.size.height))
1726       {
1727         r->left=(int)tr.origin.x;
1728         r->right=(int)(tr.origin.x+tr.size.width+0.5);
1729         r->top=(int)tr.origin.y;
1730         r->bottom=(int)(tr.origin.y+tr.size.height+0.5);
1731       }
1732     }
1733   }
1734   if (!cnt)
1735   {
1736     r->left=r->top=0;
1737     r->right=1600;
1738     r->bottom=1200;
1739   }
1740   SWELL_END_TRY(;)
1743 void ScreenToClient(HWND hwnd, POINT *p)
1745   if (!hwnd) return;
1746   // no need to try/catch, this should never have an issue *wince*
1747   
1748   id ch=(id)hwnd;
1749   if ([ch isKindOfClass:[NSWindow class]]) ch=[((NSWindow *)ch) contentView];
1750   if (!ch || ![ch isKindOfClass:[NSView class]]) return;
1751   
1752   NSWindow *window=[ch window];
1753   
1754   NSPoint wndpt = [window convertScreenToBase:NSMakePoint(p->x,p->y)];
1755   
1756   // todo : WM_NCCALCSIZE 
1757   NSPoint po = [ch convertPoint:wndpt fromView:nil];
1758   
1759   p->x=(int)(po.x+0.5);
1760   p->y=(int)(po.y+0.5);
1763 void ClientToScreen(HWND hwnd, POINT *p)
1765   if (!hwnd) return;
1766   
1767   id ch=(id)hwnd;
1768   if ([ch isKindOfClass:[NSWindow class]]) ch=[((NSWindow *)ch) contentView];
1769   if (!ch || ![ch isKindOfClass:[NSView class]]) return;
1770   
1771   NSWindow *window=[ch window];
1772   
1773   NSPoint wndpt = [ch convertPoint:NSMakePoint(p->x,p->y) toView:nil];
1774   
1775   NSPoint po = [window convertBaseToScreen:wndpt];
1776   // todo : WM_NCCALCSIZE 
1777   
1778   p->x=(int)(po.x+0.5);
1779   p->y=(int)(po.y+0.5);
1782 static NSView *NavigateUpScrollClipViews(NSView *ch)
1784   NSView *par=[ch superview];
1785   if (par && [par isKindOfClass:[NSClipView class]]) 
1786   {
1787     par=[par superview];
1788     if (par && [par isKindOfClass:[NSScrollView class]])
1789     {
1790       ch=par;
1791     }
1792   }
1793   return ch;
1796 HWND SWELL_NavigateUpScrollClipViews(HWND h)
1798   NSView *v = 0;
1799   if (h && [(id)h isKindOfClass:[NSView class]]) v = (NSView *)h;
1800   else if (h && [(id)h isKindOfClass:[NSWindow class]]) v = [(NSWindow *)h contentView];
1801   if (v)
1802     return (HWND)NavigateUpScrollClipViews(v);
1803   return 0;
1806 bool GetWindowRect(HWND hwnd, RECT *r)
1808   r->left=r->top=r->right=r->bottom=0;
1809   if (!hwnd) return false;
1811   SWELL_BEGIN_TRY
1812   
1813   id ch=(id)hwnd;
1814   NSWindow *nswnd;
1815   if ([ch isKindOfClass:[NSView class]] && (nswnd=[(NSView *)ch window]) && [nswnd contentView]==ch)
1816     ch=nswnd;
1817     
1818   if ([ch isKindOfClass:[NSWindow class]]) 
1819   {
1820     NSRect b=[ch frame];
1821     r->left=(int)(b.origin.x);
1822     r->top=(int)(b.origin.y);
1823     r->right = (int)(b.origin.x+b.size.width+0.5);
1824     r->bottom= (int)(b.origin.y+b.size.height+0.5);
1825     return true;
1826   }
1827   if (![ch isKindOfClass:[NSView class]]) return false;
1828   ch=NavigateUpScrollClipViews(ch);
1829   NSRect b=[ch bounds];
1830   r->left=(int)(b.origin.x);
1831   r->top=(int)(b.origin.y);
1832   r->right = (int)(b.origin.x+b.size.width+0.5);
1833   r->bottom= (int)(b.origin.y+b.size.height+0.5);
1834   ClientToScreen((HWND)ch,(POINT *)r);
1835   ClientToScreen((HWND)ch,((POINT *)r)+1);
1836   SWELL_END_TRY(return false;)
1838   return true;
1841 void GetWindowContentViewRect(HWND hwnd, RECT *r)
1843   SWELL_BEGIN_TRY
1844   NSWindow *nswnd;
1845   if (hwnd && [(id)hwnd isKindOfClass:[NSView class]] && (nswnd=[(NSView *)hwnd window]) && [nswnd contentView]==(id)hwnd)
1846     hwnd=(HWND)nswnd;
1847     
1848   if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]])
1849   {
1850     NSView *ch=[(id)hwnd contentView];
1851     NSRect b=[ch bounds];
1852     r->left=(int)(b.origin.x);
1853     r->top=(int)(b.origin.y);
1854     r->right = (int)(b.origin.x+b.size.width+0.5);
1855     r->bottom= (int)(b.origin.y+b.size.height+0.5);
1856     ClientToScreen(hwnd,(POINT *)r);
1857     ClientToScreen(hwnd,((POINT *)r)+1);
1858   }
1859   else GetWindowRect(hwnd,r);
1860   SWELL_END_TRY(;)
1864 void GetClientRect(HWND hwnd, RECT *r)
1866   r->left=r->top=r->right=r->bottom=0;
1867   if (!hwnd) return;
1868   
1869   SWELL_BEGIN_TRY
1870   id ch=(id)hwnd;
1871   if ([ch isKindOfClass:[NSWindow class]]) ch=[((NSWindow *)ch) contentView];
1872   if (!ch || ![ch isKindOfClass:[NSView class]]) return;
1873   ch=NavigateUpScrollClipViews(ch);
1874   
1875   NSRect b=[ch bounds];
1876   r->left=(int)(b.origin.x);
1877   r->top=(int)(b.origin.y);
1878   r->right = (int)(b.origin.x+b.size.width+0.5);
1879   r->bottom= (int)(b.origin.y+b.size.height+0.5);
1881   // todo this may need more attention
1882   NCCALCSIZE_PARAMS tr={{*r,},};
1883   SendMessage(hwnd,WM_NCCALCSIZE,FALSE,(LPARAM)&tr);
1884   r->right = r->left + (tr.rgrc[0].right-tr.rgrc[0].left);
1885   r->bottom = r->top + (tr.rgrc[0].bottom-tr.rgrc[0].top);
1886   SWELL_END_TRY(;)
1891 void SetWindowPos(HWND hwnd, HWND hwndAfter, int x, int y, int cx, int cy, int flags)
1893   if (!hwnd) return;
1895   SWELL_BEGIN_TRY
1896   NSWindow *nswnd; // content views = move window
1897   if (hwnd && [(id)hwnd isKindOfClass:[NSView class]] && (nswnd=[(NSView *)hwnd window]) && [nswnd contentView]==(id)hwnd)
1898     hwnd=(HWND)nswnd;
1900  // todo: handle SWP_SHOWWINDOW
1901   id ch=(id)hwnd;
1902   bool isview=false;
1903   if ([ch isKindOfClass:[NSWindow class]] || (isview=[ch isKindOfClass:[NSView class]])) 
1904   {
1905     if (isview)
1906     {
1907       ch=NavigateUpScrollClipViews(ch);
1908       if (isview && !(flags&SWP_NOZORDER))
1909       {
1910         NSView *v = (NSView *)ch;
1911         NSView *par = [v superview];
1912         NSArray *subs = [par subviews];
1913         NSInteger idx = [subs indexOfObjectIdenticalTo:v], cnt=[subs count];
1914         
1915         NSView *viewafter = NULL;            
1916         NSWindowOrderingMode omode = NSWindowAbove;
1917         
1918         if (cnt>1 && hwndAfter != (HWND)ch)
1919         {
1920           if (hwndAfter==HWND_TOPMOST||hwndAfter==HWND_NOTOPMOST)
1921           {
1922           }
1923           else if (hwndAfter == HWND_TOP)
1924           {
1925             if (idx<cnt-1) viewafter = [subs objectAtIndex:cnt-1];
1926           }
1927           else if (hwndAfter == HWND_BOTTOM)
1928           {
1929             if (idx>0) viewafter = [subs objectAtIndex:0];
1930             omode = NSWindowBelow;
1931           }
1932           else 
1933           {
1934             NSInteger a=[subs indexOfObjectIdenticalTo:(NSView *)hwndAfter];
1935             if (a != NSNotFound && a != (idx-1)) viewafter = (NSView *)hwndAfter;
1936           }
1937         }
1938         
1939         if (viewafter)
1940         { 
1941           HWND h = GetCapture();
1942           if (!h || (h!=(HWND)v && !IsChild((HWND)v,h))) // if this window is captured don't reorder!
1943           {
1944             NSView *oldfoc = (NSView*)[[v window] firstResponder];
1945             if (!oldfoc || ![oldfoc isKindOfClass:[NSView class]] || 
1946                 (oldfoc != v && ![oldfoc isDescendantOf:v])) oldfoc=NULL;
1947           
1948             // better way to do this? maybe :/
1949             [v retain];
1950             [v removeFromSuperviewWithoutNeedingDisplay];
1951             [par addSubview:v positioned:omode relativeTo:viewafter];
1952             [v release];
1953           
1954             if (oldfoc) [[v window] makeFirstResponder:oldfoc];
1955           }
1956         }
1957       }
1958     }    
1959     NSRect f=[ch frame];
1960     bool repos=false;
1961     if (!(flags&SWP_NOMOVE))
1962     {
1963       f.origin.x=(float)x;
1964       f.origin.y=(float)y;
1965       repos=true;
1966     }
1967     if (!(flags&SWP_NOSIZE))
1968     {
1969       f.size.width=(float)cx;
1970       f.size.height=(float)cy;
1971       if (f.size.height<0)f.size.height=-f.size.height;
1972       repos=true;
1973     }
1974     if (repos)
1975     {
1976       if (!isview)
1977       {
1978         NSSize mins=[ch minSize];
1979         NSSize maxs=[ch maxSize];
1980         if (f.size.width  < mins.width) f.size.width=mins.width;
1981         else if (f.size.width > maxs.width) f.size.width=maxs.width;
1982         if (f.size.height < mins.height) f.size.height=mins.height;
1983         else if (f.size.height> maxs.height) f.size.height=maxs.height;
1984         [ch setFrame:f display:NO];
1985         [ch display];
1986       }
1987       else
1988       {
1989         // this doesnt seem to actually be a good idea anymore
1990   //      if ([[ch window] contentView] != ch && ![[ch superview] isFlipped])
1991 //          f.origin.y -= f.size.height;
1992         [ch setFrame:f];
1993         if ([ch isKindOfClass:[NSScrollView class]])
1994         {
1995           NSView *cv=[ch documentView];
1996           if (cv && [cv isKindOfClass:[NSTextView class]])
1997           {
1998             NSRect fr=[cv frame];
1999             NSSize sz=[ch contentSize];
2000             int a=0;
2001             if (![ch hasHorizontalScroller]) {a ++; fr.size.width=sz.width; }
2002             if (![ch hasVerticalScroller]) { a++; fr.size.height=sz.height; }
2003             if (a) [cv setFrame:fr];
2004           }
2005         }
2006       }
2007     }    
2008     return;
2009   }  
2010   SWELL_END_TRY(;)  
2013 BOOL EnumWindows(BOOL (*proc)(HWND, LPARAM), LPARAM lp)
2015   NSArray *ch=[NSApp windows];
2016   [ch retain];
2017   const NSInteger n=[ch count];
2018   for(NSInteger x=0;x<n; x ++)
2019   {
2020     NSWindow *w = [ch objectAtIndex:x];
2021     if (!proc((HWND)[w contentView],lp)) 
2022     {
2023       [ch release];
2024       return FALSE;
2025     }
2026   }
2027   [ch release];
2028   return TRUE;
2032 HWND GetWindow(HWND hwnd, int what)
2034   if (!hwnd) return 0;
2035   SWELL_BEGIN_TRY
2037   if ([(id)hwnd isKindOfClass:[NSWindow class]]) hwnd=(HWND)[(id)hwnd contentView];
2038   if (!hwnd || ![(id)hwnd isKindOfClass:[NSView class]]) return 0;
2039   
2040   NSView *v=(NSView *)hwnd;
2041   if (what == GW_CHILD)
2042   {
2043     NSArray *ar=[v subviews];
2044     if (ar && [ar count]>0)
2045     {
2046       return (HWND)[ar objectAtIndex:0];
2047     }
2048     return 0;
2049   }
2050   if (what == GW_OWNER)
2051   {
2052     v=NavigateUpScrollClipViews(v);
2053     if ([[v window] contentView] == v)
2054     {
2055       if ([[v window] respondsToSelector:@selector(swellGetOwner)])
2056       {
2057         return (HWND)[(SWELL_ModelessWindow*)[v window] swellGetOwner];
2058       }
2059       return 0;
2060     }
2061     return (HWND)[v superview];
2062   }
2063   
2064   if (what >= GW_HWNDFIRST && what <= GW_HWNDPREV)
2065   {
2066     v=NavigateUpScrollClipViews(v);
2067     if ([[v window] contentView] == v)
2068     {
2069       if (what <= GW_HWNDLAST) return (HWND)hwnd; // content view is only window
2070       
2071       return 0; // we're the content view so cant do next/prev
2072     }
2073     NSView *par=[v superview];
2074     if (par)
2075     {
2076       NSArray *ar=[par subviews];
2077       NSInteger cnt;
2078       if (ar && (cnt=[ar count]) > 0)
2079       {
2080         if (what == GW_HWNDFIRST)
2081           return (HWND)[ar objectAtIndex:0];
2082         if (what == GW_HWNDLAST)
2083           return (HWND)[ar objectAtIndex:(cnt-1)];
2084         
2085         NSInteger idx=[ar indexOfObjectIdenticalTo:v];
2086         if (idx == NSNotFound) return 0;
2088         if (what==GW_HWNDNEXT) idx++;
2089         else if (what==GW_HWNDPREV) idx--;
2090         
2091         if (idx<0 || idx>=cnt) return 0;
2092         
2093         return (HWND)[ar objectAtIndex:idx];
2094       }
2095     }
2096     return 0;
2097   }
2098   SWELL_END_TRY(;)
2099   return 0;
2103 HWND GetParent(HWND hwnd)
2104 {  
2105   SWELL_BEGIN_TRY
2106   if (hwnd && [(id)hwnd isKindOfClass:[NSView class]])
2107   {
2108     hwnd=(HWND)NavigateUpScrollClipViews((NSView *)hwnd);
2110     NSView *cv=[[(NSView *)hwnd window] contentView];
2111     if (cv == (NSView *)hwnd) hwnd=(HWND)[(NSView *)hwnd window]; // passthrough to get window parent
2112     else
2113     {
2114       HWND h=(HWND)[(NSView *)hwnd superview];
2115       return h;
2116     }
2117   }
2118   
2119   if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]]) 
2120   {
2121     HWND h= (HWND)[(NSWindow *)hwnd parentWindow];
2122     if (h) h=(HWND)[(NSWindow *)h contentView];
2123     if (h) return h;
2124   }
2125   
2126   if (hwnd && [(id)hwnd respondsToSelector:@selector(swellGetOwner)])
2127   {
2128     HWND h= (HWND)[(SWELL_ModelessWindow *)hwnd swellGetOwner];
2129     if (h && [(id)h isKindOfClass:[NSWindow class]]) h=(HWND)[(NSWindow *)h contentView];
2130     return h;  
2131   }
2132   
2133   SWELL_END_TRY(;)
2134   return 0;
2137 HWND SetParent(HWND hwnd, HWND newPar)
2139   SWELL_BEGIN_TRY
2140   NSView *v=(NSView *)hwnd;
2141   if (!v || ![(id)v isKindOfClass:[NSView class]]) return 0;
2142   v=NavigateUpScrollClipViews(v);
2143   
2144   if ([(id)hwnd isKindOfClass:[NSView class]])
2145   {
2146     NSView *tv=(NSView *)hwnd;
2147     if ([[tv window] contentView] == tv) // if we're reparenting a contentview (aka top level window)
2148     {
2149       if (!newPar) return NULL;
2150     
2151       NSView *npv = (NSView *)newPar;
2152       if ([npv isKindOfClass:[NSWindow class]]) npv=[(NSWindow *)npv contentView];
2153       if (!npv || ![npv isKindOfClass:[NSView class]])
2154         return NULL;
2155     
2156       char oldtitle[2048];
2157       oldtitle[0]=0;
2158       GetWindowText(hwnd,oldtitle,sizeof(oldtitle));
2159     
2160       NSWindow *oldwnd = [tv window];
2161       id oldown = NULL;
2162       if ([oldwnd respondsToSelector:@selector(swellGetOwner)]) oldown=[(SWELL_ModelessWindow*)oldwnd swellGetOwner];
2164       if ([tv isKindOfClass:[SWELL_hwndChild class]]) ((SWELL_hwndChild*)tv)->m_lastTopLevelOwner = oldown;
2165     
2166       [tv retain];
2167       SWELL_hwndChild *tmpview = [[SWELL_hwndChild alloc] initChild:nil Parent:(NSView *)oldwnd dlgProc:nil Param:0];          
2168       [tmpview release];
2169     
2170       [npv addSubview:tv];  
2171       [tv release];
2172     
2173       DestroyWindow((HWND)oldwnd); // close old window since its no longer used
2174       if (oldtitle[0]) SetWindowText(hwnd,oldtitle);
2175       return (HWND)npv;
2176     }
2177     else if (!newPar) // not content view, not parent (so making it a top level modeless dialog)
2178     {
2179       char oldtitle[2048];
2180       oldtitle[0]=0;
2181       GetWindowText(hwnd,oldtitle,sizeof(oldtitle));
2182       
2183       [tv retain];
2184       [tv removeFromSuperview];
2186     
2187       unsigned int wf=(NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask|NSResizableWindowMask);
2188       if ([tv respondsToSelector:@selector(swellCreateWindowFlags)])
2189         wf=(unsigned int)[(SWELL_hwndChild *)tv swellCreateWindowFlags];
2191       HWND newOwner=NULL;
2192       if ([tv isKindOfClass:[SWELL_hwndChild class]])
2193       {
2194          id oldown = ((SWELL_hwndChild*)tv)->m_lastTopLevelOwner;
2195          if (oldown)
2196          {
2197            NSArray *ch=[NSApp windows];
2198            const NSInteger n = [ch count];
2199            for(NSInteger x=0;x<n && !newOwner; x ++)
2200            {
2201              NSWindow *w = [ch objectAtIndex:x];
2202              if (w == (NSWindow *)oldown || [w contentView] == (NSView *)oldown) newOwner = (HWND)w;
2203            }
2204          }
2205       }
2207       HWND SWELL_CreateModelessFrameForWindow(HWND childW, HWND ownerW, unsigned int);
2208       HWND bla=SWELL_CreateModelessFrameForWindow((HWND)tv,(HWND)newOwner,wf);
2209       // create a new modeless frame 
2211      
2212       
2213       [(NSWindow *)bla display];
2214       
2215       [tv release];
2216       
2217       if (oldtitle[0]) SetWindowText(hwnd,oldtitle);
2218       
2219       return NULL;
2220       
2221     }
2222   }
2223   HWND ret=(HWND) [v superview];
2224   if (ret) 
2225   {
2226     [v retain];
2227     [v removeFromSuperview];
2228   }
2229   NSView *np=(NSView *)newPar;
2230   if (np && [np isKindOfClass:[NSWindow class]]) np=[(NSWindow *)np contentView];
2231   
2232   if (np && [np isKindOfClass:[NSView class]])
2233   {
2234     [np addSubview:v];
2235     [v release];
2236   }
2237   return ret;
2238   SWELL_END_TRY(;)
2239   return NULL;
2243 int IsChild(HWND hwndParent, HWND hwndChild)
2245   if (!hwndParent || !hwndChild || hwndParent == hwndChild) return 0;
2246   SWELL_BEGIN_TRY
2247   id par=(id)hwndParent;
2248   id ch=(id)hwndChild;
2249   if (![ch isKindOfClass:[NSView class]]) return 0;
2250   if ([par isKindOfClass:[NSWindow class]])
2251   {
2252     return [ch window] == par;
2253   }
2254   else if ([par isKindOfClass:[NSView class]])
2255   {
2256     return !![ch isDescendantOf:par];
2257   }
2258   SWELL_END_TRY(;)
2259   return 0;
2262 HWND GetForegroundWindow()
2264   SWELL_BEGIN_TRY
2265   NSWindow *window=[NSApp keyWindow];
2266   if (!window) return 0;
2267   id ret=[window firstResponder];
2268   if (ret && [ret isKindOfClass:[NSView class]]) 
2269   {
2270 //    if (ret == [window contentView]) return (HWND) window;
2271     return (HWND) ret;
2272   }
2273   return (HWND)window;
2274   SWELL_END_TRY(;)
2275   return NULL;
2278 HWND GetFocus()
2280   SWELL_BEGIN_TRY
2281   NSWindow *window=[NSApp keyWindow];
2282   if (!window) return 0;
2283   id ret=[window firstResponder];
2284   if (ret && [ret isKindOfClass:[NSView class]]) 
2285   {
2286 //    if (ret == [window contentView]) return (HWND) window;
2288     if ([ret isKindOfClass:[NSTextView class]] && [ret superview] && [[ret superview] superview])
2289     {
2290       NSView* v = [[ret superview] superview];
2291       if ([v isKindOfClass:[NSTextField class]]) return (HWND) v;
2292     }
2294     return (HWND) ret;
2295   }
2296   SWELL_END_TRY(;)
2297   return 0;
2300 bool IsEquivalentTextView(HWND h1, HWND h2)
2302   if (!h1 || !h2) return false;
2303   if (h1 == h2) return true;
2304   SWELL_BEGIN_TRY
2305   NSView* v1 = (NSView*)h1;
2306   NSView* v2 = (NSView*)h2;
2307   if ([v1 isKindOfClass:[NSTextField class]] && [v2 isKindOfClass:[NSTextView class]])
2308   {
2309     NSView* t = v1;
2310     v1 = v2;
2311     v2 = t;
2312   }
2313   if ([v1 isKindOfClass: [NSTextView class]] && [v2 isKindOfClass:[NSTextField class]])
2314   {
2315     if ([v1 superview] && [[v1 superview] superview] && [[[v1 superview] superview] superview] == v2) return true;
2316   }
2317   SWELL_END_TRY(;)
2318   return false;
2320   
2323 BOOL SetDlgItemText(HWND hwnd, int idx, const char *text)
2325   NSView *obj=(NSView *)(idx ? GetDlgItem(hwnd,idx) : hwnd);
2326   if (!obj) return false;
2327   
2328   SWELL_BEGIN_TRY
2329   NSWindow *nswnd;
2330   if ([(id)obj isKindOfClass:[NSView class]] && (nswnd=[(NSView *)obj window]) && [nswnd contentView]==(id)obj)
2331   {
2332     SetDlgItemText((HWND)nswnd,0,text); // also set window if setting content view
2333   }
2334   
2335   if ([obj respondsToSelector:@selector(onSwellSetText:)])
2336   {
2337     [(SWELL_hwndChild*)obj onSwellSetText:text];
2338     return TRUE;
2339   }
2340   
2341   BOOL rv=TRUE;  
2342   NSString *lbl=(NSString *)SWELL_CStringToCFString(text);
2343   if ([obj isKindOfClass:[NSWindow class]] || [obj isKindOfClass:[NSButton class]]) [(NSButton*)obj setTitle:lbl];
2344   else if ([obj isKindOfClass:[NSControl class]]) 
2345   {
2346     [(NSControl*)obj setStringValue:lbl];
2347     if ([obj isKindOfClass:[NSTextField class]] && [(NSTextField *)obj isEditable])
2348     {
2349       SendMessage(GetParent((HWND)obj),WM_COMMAND,[(NSControl *)obj tag]|(EN_CHANGE<<16),(LPARAM)obj);
2350     }
2351   }
2352   else if ([obj isKindOfClass:[NSText class]])  
2353   {
2354     // todo if there is a way to find out that the window's NSTextField is already assigned 
2355     // to another field, restore the assignment afterwards
2356     [(NSText*)obj setString:lbl];
2357     [obj setNeedsDisplay:YES]; // required on Sierra, it seems -- if the parent is hidden (e.g. DialogBox() + WM_INITDIALOG), the view is not drawn
2358   }
2359   else if ([obj isKindOfClass:[NSBox class]])
2360   {
2361     [(NSBox *)obj setTitle:lbl];
2362   }
2363   else
2364   {
2365     rv=FALSE;
2366   }
2367   
2368   [lbl release];
2369   return rv;
2370   SWELL_END_TRY(;)
2371   return FALSE;
2374 BOOL GetDlgItemText(HWND hwnd, int idx, char *text, int textlen)
2376   *text=0;
2377   NSView *pvw=(NSView *)(idx?GetDlgItem(hwnd,idx) : hwnd);
2378   if (!pvw) return false;
2380   SWELL_BEGIN_TRY
2381   
2382   if ([(id)pvw isKindOfClass:[NSView class]] && [[(id)pvw window] contentView] == pvw)
2383   {
2384     pvw=(NSView *)[(id)pvw window];
2385   }
2386   
2387   if ([(id)pvw respondsToSelector:@selector(onSwellGetText)])
2388   {  
2389     const char *p=(const char *)[(SWELL_hwndChild*)pvw onSwellGetText];
2390     lstrcpyn_safe(text,p?p:"",textlen);
2391     return TRUE;
2392   }
2393   
2394   NSString *s;
2395   
2396   if ([pvw isKindOfClass:[NSButton class]]||[pvw isKindOfClass:[NSWindow class]]) s=[((NSButton *)pvw) title];
2397   else if ([pvw isKindOfClass:[NSControl class]]) s=[((NSControl *)pvw) stringValue];
2398   else if ([pvw isKindOfClass:[NSText class]])  s=[(NSText*)pvw string];
2399   else if ([pvw isKindOfClass:[NSBox class]]) s=[(NSBox *)pvw title];
2400   else return FALSE;
2401   
2402   if (s) SWELL_CFStringToCString(s,text,textlen);
2403 //    [s getCString:text maxLength:textlen];
2404     
2405   return !!s;
2406   SWELL_END_TRY(;)
2407   return FALSE;
2410 void CheckDlgButton(HWND hwnd, int idx, int check)
2412   NSView *pvw=(NSView *)GetDlgItem(hwnd,idx);
2413   if (!pvw) return;
2414   if ([pvw isKindOfClass:[NSButton class]]) 
2415     [(NSButton*)pvw setState:(check&BST_INDETERMINATE)?NSMixedState:((check&BST_CHECKED)?NSOnState:NSOffState)];
2419 int IsDlgButtonChecked(HWND hwnd, int idx)
2421   NSView *pvw=(NSView *)GetDlgItem(hwnd,idx);
2422   if (pvw && [pvw isKindOfClass:[NSButton class]])
2423   {
2424     NSInteger a=[(NSButton*)pvw state];
2425     if (a==NSMixedState) return BST_INDETERMINATE;
2426     return a!=NSOffState;
2427   }
2428   return 0;
2431 void SWELL_TB_SetPos(HWND hwnd, int idx, int pos)
2433   NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2434   if (p  && [p isKindOfClass:[NSSlider class]]) 
2435   {
2436     [p setDoubleValue:(double)pos];
2437   }
2438   else 
2439   {
2440     sendSwellMessage(p,TBM_SETPOS,1,pos); 
2441   }
2444 void SWELL_TB_SetRange(HWND hwnd, int idx, int low, int hi)
2446   NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2447   if (p && [p isKindOfClass:[NSSlider class]])
2448   {
2449     [p setMinValue:low];
2450     [p setMaxValue:hi];
2451   }
2452   else 
2453   {
2454     sendSwellMessage(p,TBM_SETRANGE,1,((low&0xffff)|(hi<<16)));
2455   }
2456   
2459 int SWELL_TB_GetPos(HWND hwnd, int idx)
2461   NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2462   if (p && [p isKindOfClass:[NSSlider class]]) 
2463   {
2464     return (int) ([p doubleValue]+0.5);
2465   }
2466   else 
2467   {
2468     return (int) sendSwellMessage(p,TBM_GETPOS,0,0);
2469   }
2470   return 0;
2473 void SWELL_TB_SetTic(HWND hwnd, int idx, int pos)
2475   NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2476   sendSwellMessage(p,TBM_SETTIC,0,pos);
2479 void SWELL_CB_DeleteString(HWND hwnd, int idx, int wh)
2481   NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2482   if (!p) return;
2483   if ([p isKindOfClass:[SWELL_ComboBox class]])
2484   {
2485     if (wh>=0 && wh<[p numberOfItems])
2486     {
2487       [p removeItemAtIndex:wh];
2488       if (((SWELL_ComboBox*)p)->m_ids) ((SWELL_ComboBox*)p)->m_ids->Delete(wh);
2489     }
2490   }
2491   else if ( [p isKindOfClass:[NSPopUpButton class]])
2492   {
2493     NSMenu *menu = [p menu];
2494     if (menu)
2495     {
2496       if (wh >= 0 && wh < [menu numberOfItems])
2497         [menu removeItemAtIndex:wh];
2498     }
2499   }
2503 int SWELL_CB_FindString(HWND hwnd, int idx, int startAfter, const char *str, bool exact)
2505   NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);  
2506   if (!p) return 0;
2507   
2508   int pos = startAfter;
2509   if (pos<0)pos=0;
2510   else pos++;
2511   
2512   const size_t l1len = strlen(str);
2513   const int ni=(int)[p numberOfItems];
2514   
2515   if ([p isKindOfClass:[NSComboBox class]])
2516   {
2517     for(;pos<ni;pos++)
2518     {
2519       NSString *s=[p itemObjectValueAtIndex:pos];
2520       if (s)
2521       {
2522         char buf[4096];
2523         SWELL_CFStringToCString(s,buf,sizeof(buf));
2524         if (exact ? !stricmp(str,buf) : !strnicmp(str,buf,l1len))
2525           return pos;
2526       }
2527     }
2528   }
2529   else 
2530   {
2531     for(;pos<ni;pos++)
2532     {
2533       NSMenuItem *i=[(NSPopUpButton *)p itemAtIndex:pos];
2534       if (i)
2535       {
2536         NSString *s=[i title];
2537         if (s)          
2538         {
2539           char buf[4096];
2540           SWELL_CFStringToCString(s,buf,sizeof(buf));
2541           if (exact ? !stricmp(str,buf) : !strnicmp(str,buf,l1len))
2542             return pos;
2543         }
2544       }
2545     }
2546   }
2547   return -1;
2550 int SWELL_CB_GetItemText(HWND hwnd, int idx, int item, char *buf, int bufsz)
2552   NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2554   if (buf) *buf=0;
2555   if (!p) return CB_ERR;
2556   const int ni = (int)[p numberOfItems];
2557   if (item < 0 || item >= ni) return CB_ERR;
2558   
2559   if ([p isKindOfClass:[NSComboBox class]])
2560   {
2561     NSString *s=[p itemObjectValueAtIndex:item];
2562     if (s)
2563     {
2564       if (!buf) return (int) ([s lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 64);
2566       SWELL_CFStringToCString(s,buf,bufsz);
2567       return 1;
2568     }
2569   }
2570   else 
2571   {
2572     NSMenuItem *i=[(NSPopUpButton *)p itemAtIndex:item];
2573     if (i)
2574     {
2575       NSString *s=[i title];
2576       if (s)
2577       {
2578         if (!buf) return (int) ([s lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 64);
2580         SWELL_CFStringToCString(s,buf,bufsz);
2581         return 1;
2582       }
2583     }
2584   }
2585   return CB_ERR;
2589 int SWELL_CB_InsertString(HWND hwnd, int idx, int pos, const char *str)
2591   NSString *label=(NSString *)SWELL_CStringToCFString(str);
2592   NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2593   if (!p) return 0;
2594   
2595   bool isAppend=false;
2596   const int ni = (int)[p numberOfItems];
2597   if (pos == -1000) 
2598   {
2599     isAppend=true;
2600     pos=ni;
2601   }
2602   else if (pos < 0) pos=0;
2603   else if (pos > ni) pos=ni;
2604   
2605    
2606   if ([p isKindOfClass:[SWELL_ComboBox class]])
2607   {
2608     if (isAppend && (((int)[(SWELL_ComboBox*)p getSwellStyle]) & CBS_SORT))
2609     {
2610       pos=(int)arr_bsearch_mod(label,[p objectValues],_nsStringSearchProc);
2611     }
2612     
2613     if (pos==ni)
2614       [p addItemWithObjectValue:label];
2615     else
2616       [p insertItemWithObjectValue:label atIndex:pos];
2617   
2618     if (((SWELL_ComboBox*)p)->m_ids) ((SWELL_ComboBox*)p)->m_ids->Insert(pos,(char*)0);
2619     [p setNumberOfVisibleItems:(ni+1)];
2620   }
2621   else
2622   {
2623     NSMenu *menu = [(NSPopUpButton *)p menu];
2624     if (menu)
2625     {
2626       const bool needclearsel = [p indexOfSelectedItem] < 0;
2627       if (isAppend && [p respondsToSelector:@selector(getSwellStyle)] && (((int)[(SWELL_PopUpButton*)p getSwellStyle]) & CBS_SORT))
2628       {
2629         pos=(int)arr_bsearch_mod(label,[menu itemArray],_nsMenuSearchProc);
2630       }
2631       NSMenuItem *item=[menu insertItemWithTitle:label action:NULL keyEquivalent:@"" atIndex:pos];
2632       [item setEnabled:YES];      
2633       if (needclearsel) [(NSPopUpButton *)p selectItemAtIndex:-1];
2634     }
2635   }
2636   [label release];
2637   return pos;
2638   
2641 int SWELL_CB_AddString(HWND hwnd, int idx, const char *str)
2643   return SWELL_CB_InsertString(hwnd,idx,-1000,str);
2646 int SWELL_CB_GetCurSel(HWND hwnd, int idx)
2648   NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2649   if (!p) return -1;
2650   return (int)[p indexOfSelectedItem];
2653 void SWELL_CB_SetCurSel(HWND hwnd, int idx, int item)
2655   NSComboBox *cb = (NSComboBox *)GetDlgItem(hwnd,idx);
2656   if (!cb) return;
2658   if (item < 0 || item >= [cb numberOfItems])
2659   {
2660     // combo boxes can be NSComboBox or NSPopupButton, NSComboBox needs
2661     // a different deselect method (selectItemAtIndex:-1 throws an exception)
2662     if ([cb isKindOfClass:[NSComboBox class]])
2663     {
2664       const NSInteger sel = [cb indexOfSelectedItem];
2665       if (sel>=0) [cb deselectItemAtIndex:sel];
2666     }
2667     else if ([cb isKindOfClass:[NSPopUpButton class]])
2668       [(NSPopUpButton*)cb selectItemAtIndex:-1];
2669   }
2670   else
2671     [cb selectItemAtIndex:item];
2674 int SWELL_CB_GetNumItems(HWND hwnd, int idx)
2676   NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2677   if (!p) return 0;
2678   return (int)[p numberOfItems];
2683 void SWELL_CB_SetItemData(HWND hwnd, int idx, int item, LONG_PTR data)
2685   id cb=(id)GetDlgItem(hwnd,idx);
2686   if (!cb) return;
2688   if ([cb isKindOfClass:[NSPopUpButton class]])
2689   {
2690     if (item < 0 || item >= [cb numberOfItems]) return;
2691     NSMenuItem *it=[(NSPopUpButton*)cb itemAtIndex:item];
2692     if (!it) return;
2693   
2694     SWELL_DataHold *p=[[SWELL_DataHold alloc] initWithVal:(void *)data];  
2695     [it setRepresentedObject:p];
2696     [p release];
2697   }
2698   else if ([cb isKindOfClass:[SWELL_ComboBox class]])
2699   {
2700     if (item < 0 || item >= [cb numberOfItems]) return;
2701     if (((SWELL_ComboBox*)cb)->m_ids) ((SWELL_ComboBox*)cb)->m_ids->Set(item,(char*)data);
2702   }
2705 LONG_PTR SWELL_CB_GetItemData(HWND hwnd, int idx, int item)
2707   id cb=(id)GetDlgItem(hwnd,idx);
2708   if (!cb) return 0;
2709   if ([cb isKindOfClass:[NSPopUpButton class]])
2710   {
2711     if (item < 0 || item >= [cb numberOfItems]) return 0;
2712     NSMenuItem *it=[(NSPopUpButton*)cb itemAtIndex:item];
2713     if (!it) return 0;
2714     id p= [it representedObject];
2715     if (!p || ![p isKindOfClass:[SWELL_DataHold class]]) return 0;
2716     return (LONG_PTR) (void *)[p getValue];
2717   }
2718   else if ([cb isKindOfClass:[SWELL_ComboBox class]])
2719   {
2720     if (item < 0 || item >= [cb numberOfItems]) return 0;
2721     if (((SWELL_ComboBox*)cb)->m_ids) return (LONG_PTR) ((SWELL_ComboBox*)cb)->m_ids->Get(item);    
2722   }
2723   return 0;
2726 void SWELL_CB_Empty(HWND hwnd, int idx)
2728   id cb=(id)GetDlgItem(hwnd,idx);
2729   if (!cb) return;  
2730   if ([cb isKindOfClass:[NSPopUpButton class]] ||
2731       [cb isKindOfClass:[NSComboBox class]]) [cb removeAllItems];
2732   
2733   if ([cb isKindOfClass:[SWELL_ComboBox class]])
2734   {
2735     if (((SWELL_ComboBox*)cb)->m_ids) ((SWELL_ComboBox*)cb)->m_ids->Empty(); 
2736   }
2740 BOOL SetDlgItemInt(HWND hwnd, int idx, int val, int issigned)
2742   char buf[128];
2743   sprintf(buf,issigned?"%d":"%u",val);
2744   return SetDlgItemText(hwnd,idx,buf);
2747 int GetDlgItemInt(HWND hwnd, int idx, BOOL *translated, int issigned)
2749   char buf[128];
2750   if (!GetDlgItemText(hwnd,idx,buf,sizeof(buf)))
2751   {
2752     if (translated) *translated=0;
2753     return 0;
2754   }
2755   char *p=buf;
2756   while (*p == ' ' || *p == '\t') p++;
2757   int a=atoi(p);
2758   if ((a<0 && !issigned) || (!a && p[0] != '0')) { if (translated) *translated=0; return 0; }
2759   if (translated) *translated=1;
2760   return a;
2763 void SWELL_HideApp()
2765   [NSApp hide:NSApp];
2769 BOOL SWELL_GetGestureInfo(LPARAM lParam, GESTUREINFO* gi)
2771   if (!lParam || !gi) return FALSE;
2772   memcpy(gi, (GESTUREINFO*)lParam, sizeof(GESTUREINFO));
2773   return TRUE;
2775   
2777 void ShowWindow(HWND hwnd, int cmd)
2779   id pid=(id)hwnd;
2780   
2781   if (pid && [pid isKindOfClass:[NSWindow class]])
2782   {
2783     if (cmd == SW_SHOWNA && [pid isKindOfClass:[SWELL_ModelessWindow class]])
2784     {
2785       if (((SWELL_ModelessWindow *)pid)->m_wantInitialKeyWindowOnShow)
2786       {
2787         ((SWELL_ModelessWindow *)pid)->m_wantInitialKeyWindowOnShow=false;
2788         cmd = SW_SHOW;
2789       }
2790     }
2791     if (cmd==SW_SHOW)
2792     {
2793       [pid makeKeyAndOrderFront:pid];
2794     }
2795     else if (cmd==SW_SHOWNA)
2796     {
2797       [pid orderFront:pid];
2798     }
2799     else if (cmd==SW_HIDE)
2800     {
2801       [pid orderOut:pid];
2802     }
2803     else if (cmd == SW_SHOWMINIMIZED)
2804     {   
2805       // this ought to work
2806       //if ([NSApp mainWindow] == pid)
2807       //{
2808       //  [NSApp hide:pid];
2809       //}
2810       //else
2811       //{
2812         [pid miniaturize:pid];
2813       //}
2814     }
2815     return;
2816   }
2817   if (!pid || ![pid isKindOfClass:[NSView class]]) return;
2818   
2819   pid=NavigateUpScrollClipViews(pid);
2820   
2821   switch (cmd)
2822   {
2823     case SW_SHOW:
2824     case SW_SHOWNA:
2825       [((NSView *)pid) setHidden:NO];
2826     break;
2827     case SW_HIDE:
2828       {
2829         NSWindow *pw=[pid window];
2830         if (pw && [NSApp keyWindow] == pw)
2831         {
2832           id foc=[pw firstResponder];
2833           if (foc && (foc == pid || IsChild((HWND)pid,(HWND)foc)))
2834           {
2835             HWND h=GetParent((HWND)pid);
2836             if (h) SetFocus(h);
2837           }
2838         }
2839         if (![((NSView *)pid) isHidden])
2840         {
2841           if ((NSView *)pid != [pw contentView])
2842           {
2843             HWND par = (HWND) [(NSView *)pid superview];
2844             if (par)
2845             {
2846               RECT r;
2847               GetWindowRect((HWND)pid,&r);
2848               ScreenToClient(par,(LPPOINT)&r);
2849               ScreenToClient(par,((LPPOINT)&r)+1);
2850               InvalidateRect(par,&r,FALSE);
2851             }
2852           }
2853           [((NSView *)pid) setHidden:YES];
2854         }
2855     }
2856     break;
2857   }
2858   
2859   NSWindow *nswnd;
2860   if ((nswnd=[(NSView *)pid window]) && [nswnd contentView]==(id)pid)
2861   {
2862     ShowWindow((HWND)nswnd,cmd);
2863   }
2866 void *SWELL_ModalWindowStart(HWND hwnd)
2868   if (hwnd && [(id)hwnd isKindOfClass:[NSView class]]) hwnd=(HWND)[(NSView *)hwnd window];
2869   if (!hwnd) return 0;
2870   return (void *)[NSApp beginModalSessionForWindow:(NSWindow *)hwnd];
2873 bool SWELL_ModalWindowRun(void *ctx, int *ret) // returns false and puts retval in *ret when done
2875   if (!ctx) return false;
2876   NSInteger r=[NSApp runModalSession:(NSModalSession)ctx];
2877   if (r==NSRunContinuesResponse) return true;
2878   if (ret) *ret=(int)r;
2879   return false;
2882 void SWELL_ModalWindowEnd(void *ctx)
2884   if (ctx) 
2885   {
2886     if ([NSApp runModalSession:(NSModalSession)ctx] == NSRunContinuesResponse)
2887     {    
2888       [NSApp stopModal];
2889       while ([NSApp runModalSession:(NSModalSession)ctx]==NSRunContinuesResponse) Sleep(10);
2890     }
2891     [NSApp endModalSession:(NSModalSession)ctx];
2892   }
2895 void SWELL_CloseWindow(HWND hwnd)
2897   if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]])
2898   {
2899     [((NSWindow*)hwnd) close];
2900   }
2901   else if (hwnd && [(id)hwnd isKindOfClass:[NSView class]])
2902   {
2903     [[(NSView*)hwnd window] close];
2904   }
2908 #include "swell-dlggen.h"
2910 static id m_make_owner;
2911 static NSRect m_transform;
2912 static float m_parent_h;
2913 static bool m_doautoright;
2914 static NSRect m_lastdoauto;
2915 static bool m_sizetofits;
2916 static int m_make_radiogroupcnt;
2918 #define ACTIONTARGET (m_make_owner)
2920 void SWELL_MakeSetCurParms(float xscale, float yscale, float xtrans, float ytrans, HWND parent, bool doauto, bool dosizetofit)
2922   m_make_radiogroupcnt=0;
2923   m_sizetofits=dosizetofit;
2924   m_lastdoauto.origin.x = 0;
2925   m_lastdoauto.origin.y = -100;
2926   m_lastdoauto.size.width = 0;
2927   m_doautoright=doauto;
2928   m_transform.origin.x=xtrans;
2929   m_transform.origin.y=ytrans;
2930   m_transform.size.width=xscale;
2931   m_transform.size.height=yscale;
2932   m_make_owner=(id)parent;
2933   if ([m_make_owner isKindOfClass:[NSWindow class]]) m_make_owner=[(NSWindow *)m_make_owner contentView];
2934   m_parent_h=100.0;
2935   if ([(id)m_make_owner isKindOfClass:[NSView class]])
2936   {
2937     m_parent_h=[(NSView *)m_make_owner bounds].size.height;
2938     if (m_transform.size.height > 0 && [(id)parent isFlipped])
2939       m_transform.size.height*=-1;
2940   }
2943 static void UpdateAutoCoords(NSRect r)
2945   m_lastdoauto.size.width=r.origin.x + r.size.width - m_lastdoauto.origin.x;
2948 static NSRect MakeCoords(int x, int y, int w, int h, bool wantauto, bool ignorevscaleheight=false)
2950   if (w<0&&h<0)
2951   {
2952     return NSMakeRect(-x,-y,-w,-h);
2953   }
2954   float ysc=m_transform.size.height;
2955   float ysc2 = ignorevscaleheight ? 1.0 : ysc;
2956   int newx=(int)((x+m_transform.origin.x)*m_transform.size.width + 0.5);
2957   int newy=(int)((ysc >= 0.0 ? m_parent_h - ((y+m_transform.origin.y) )*ysc + h*ysc2 : 
2958                          ((y+m_transform.origin.y) )*-ysc) + 0.5);
2959                          
2960   NSRect ret= NSMakeRect(newx,  
2961                          newy,                  
2962                         (int) (w*m_transform.size.width+0.5),
2963                         (int) (h*fabs(ysc2)+0.5));
2964                         
2965   NSRect oret=ret;
2966   if (wantauto && m_doautoright)
2967   {
2968     float dx = ret.origin.x - m_lastdoauto.origin.x;
2969     if (fabs(dx)<32 && m_lastdoauto.origin.y >= ret.origin.y && m_lastdoauto.origin.y < ret.origin.y + ret.size.height)
2970     {
2971       ret.origin.x += (int) m_lastdoauto.size.width;
2972     }
2973     
2974     m_lastdoauto.origin.x = oret.origin.x + oret.size.width;
2975     m_lastdoauto.origin.y = ret.origin.y + ret.size.height*0.5;
2976     m_lastdoauto.size.width=0;
2977   }
2978   return ret;
2981 static const double minwidfontadjust=1.81;
2982 #define TRANSFORMFONTSIZE (m_transform.size.width<1?8:m_transform.size.width<2?10:12)
2983 /// these are for swell-dlggen.h
2984 HWND SWELL_MakeButton(int def, const char *label, int idx, int x, int y, int w, int h, int flags)
2985 {  
2986   UINT_PTR a=(UINT_PTR)label;
2987   if (a < 65536) label = "ICONTEMP";
2988   SWELL_Button *button=[[SWELL_Button alloc] init];
2989   if (flags & BS_BITMAP)
2990   {
2991     SWELL_ImageButtonCell * cell = [[SWELL_ImageButtonCell alloc] init];
2992     [button setCell:cell];
2993     [cell release];
2994   }
2995   
2996   if (m_transform.size.width < minwidfontadjust)
2997   {
2998     [button setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
2999   }
3000   
3001   [button setTag:idx];
3002   if (g_swell_want_nice_style==1)
3003     [button setBezelStyle:NSShadowlessSquareBezelStyle ];
3004   else
3005     [button setBezelStyle:NSRoundedBezelStyle ];
3006   NSRect tr=MakeCoords(x,y,w,h,true);
3007   
3008   
3009   if (g_swell_want_nice_style!=1 && tr.size.height >= 18 && tr.size.height<24)
3010   {
3011     tr.size.height=24;
3012   }
3013   
3014   [button setFrame:tr];
3015   NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(label);
3016   [button setTitle:labelstr];
3017   [button setTarget:ACTIONTARGET];
3018   [button setAction:@selector(onSwellCommand:)];
3019   if (flags&SWELL_NOT_WS_VISIBLE) [button setHidden:YES];
3020   [m_make_owner addSubview:button];
3021   if (m_doautoright) UpdateAutoCoords([button frame]);
3022   if (def) [[m_make_owner window] setDefaultButtonCell:(NSButtonCell*)button];
3023   [labelstr release];
3024   [button release];
3025   return (HWND) button;
3029 @implementation SWELL_TextView
3031 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
3033 -(NSInteger) tag
3035   return m_tag;
3038 -(void) setTag:(NSInteger)tag
3040   m_tag=tag;
3043 -(LRESULT)onSwellMessage:(UINT)msg p1:(WPARAM)wParam p2:(LPARAM)lParam
3045   switch (msg)
3046   {
3047     case EM_SCROLL:
3048       if (wParam == SB_TOP)
3049       {
3050         [self scrollRangeToVisible:NSMakeRange(0, 0)];
3051       }
3052       else if (wParam == SB_BOTTOM)
3053       {
3054         NSUInteger len = [[self string] length];
3055         [self scrollRangeToVisible:NSMakeRange(len, 0)];
3056       }
3057     return 0;
3058     
3059     case EM_SETSEL:    
3060     {
3061       NSUInteger sl =  [[self string] length];
3062       if (wParam == -1) lParam = wParam = 0;
3063       else if (lParam == -1) lParam = sl;
3064       
3065       if (wParam>sl)wParam=sl;
3066       if (lParam>sl)lParam=sl;
3067       [self setSelectedRange:NSMakeRange(wParam, lParam>wParam ? lParam-wParam : 0)];
3068     }
3069     return 0;
3070     
3071     case EM_GETSEL:
3072     {
3073       NSRange r = [self selectedRange];
3074       if (wParam) *(int*)wParam = (int)r.location;
3075       if (lParam) *(int*)lParam = (int)(r.location+r.length);
3076     }
3077     return 0;
3078       
3079     case WM_SETFONT:
3080     {
3081       HGDIOBJ__* obj = (HGDIOBJ__*)wParam;
3082       if (obj && obj->type == TYPE_FONT)
3083       {
3084         if (obj->ct_FontRef)
3085         {
3086           [self setFont:(NSFont *)obj->ct_FontRef];
3087         }
3088 #ifdef SWELL_ATSUI_TEXT_SUPPORT
3089         else if (obj->atsui_font_style)
3090         {
3091           ATSUFontID fontid = kATSUInvalidFontID;      
3092           Fixed fsize = 0;          
3093           Boolean isbold = NO;
3094           Boolean isital = NO;
3095           Boolean isunder = NO;          
3096           if (ATSUGetAttribute(obj->atsui_font_style, kATSUFontTag, sizeof(ATSUFontID), &fontid, 0) == noErr &&
3097               ATSUGetAttribute(obj->atsui_font_style, kATSUSizeTag, sizeof(Fixed), &fsize, 0) == noErr && fsize &&
3098               ATSUGetAttribute(obj->atsui_font_style, kATSUQDBoldfaceTag, sizeof(Boolean), &isbold, 0) == noErr && 
3099               ATSUGetAttribute(obj->atsui_font_style, kATSUQDItalicTag, sizeof(Boolean), &isital, 0) == noErr &&
3100               ATSUGetAttribute(obj->atsui_font_style, kATSUQDUnderlineTag, sizeof(Boolean), &isunder, 0) == noErr)
3101           {
3102             char name[255];
3103             name[0]=0;
3104             ByteCount namelen=0;
3105             if (ATSUFindFontName(fontid, kFontFullName, (FontPlatformCode)kFontNoPlatform, kFontNoScriptCode, kFontNoLanguageCode, sizeof(name), name, &namelen, 0) == noErr && name[0] && namelen)
3106             {
3107               namelen /= 2;
3108               int i;
3109               for (i = 0; i < namelen; ++i) name[i] = name[2*i];
3110               name[namelen]=0;
3112               // todo bold/ital/underline
3113               NSString* str = (NSString*)SWELL_CStringToCFString(name);
3114               CGFloat sz = Fix2Long(fsize);
3115               NSFont* font = [NSFont fontWithName:str size:sz];
3116               [str release];
3117               if (font) 
3118               {
3119                 [self setFont:font];
3120               }
3121             }
3122           }            
3123         }
3124 #endif
3125       }
3126     }
3127     return 0;
3128   }
3129   return 0;
3132 - (BOOL)becomeFirstResponder;
3134   BOOL didBecomeFirstResponder = [super becomeFirstResponder];
3135   if (didBecomeFirstResponder) SendMessage(GetParent((HWND)self),WM_COMMAND,[self tag]|(EN_SETFOCUS<<16),(LPARAM)self);
3136   return didBecomeFirstResponder;
3138 @end
3141 @implementation SWELL_TextField
3142 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
3144 - (BOOL)becomeFirstResponder;
3146   BOOL didBecomeFirstResponder = [super becomeFirstResponder];
3147   if (didBecomeFirstResponder) SendMessage(GetParent((HWND)self),WM_COMMAND,[self tag]|(EN_SETFOCUS<<16),(LPARAM)self);
3148   return didBecomeFirstResponder;
3150 @end
3154 HWND SWELL_MakeEditField(int idx, int x, int y, int w, int h, int flags)
3155 {  
3156   if ((flags&WS_VSCROLL) || (flags&WS_HSCROLL)) // || (flags & ES_READONLY))
3157   {
3158     SWELL_TextView *obj=[[SWELL_TextView alloc] init];
3159     [obj setEditable:(flags & ES_READONLY)?NO:YES];
3160     if (m_transform.size.width < minwidfontadjust)
3161       [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3162     [obj setTag:idx];
3163     [obj setDelegate:ACTIONTARGET];
3164   
3165     [obj setHorizontallyResizable:NO];
3166     
3167     if (flags & WS_VSCROLL)
3168     {
3169       NSRect fr=MakeCoords(x,y,w,h,true);
3170       
3171       [obj setVerticallyResizable:YES];
3172       NSScrollView *obj2=[[NSScrollView alloc] init];
3173       [obj2 setFrame:fr];
3174       if (flags&WS_VSCROLL) [obj2 setHasVerticalScroller:YES];
3175       if (flags&WS_HSCROLL) [obj2 setHasHorizontalScroller:YES];
3176       [obj2 setAutohidesScrollers:YES];
3177       [obj2 setDrawsBackground:NO];
3178       [obj2 setDocumentView:obj];
3179       [m_make_owner addSubview:obj2];
3180       if (m_doautoright) UpdateAutoCoords([obj2 frame]);
3181       if (flags&SWELL_NOT_WS_VISIBLE) [obj2 setHidden:YES];
3182       [obj2 release];
3183       
3184       NSRect tr;
3185       memset(&tr,0,sizeof(tr));
3186       tr.size = [obj2 contentSize];
3187       [obj setFrame:tr];
3188       [obj release];
3189       
3190       return (HWND)obj2;
3191     }
3192     else
3193     {
3194       [obj setFrame:MakeCoords(x,y,w,h,true)];
3195       [obj setVerticallyResizable:NO];
3196       if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3197       [m_make_owner addSubview:obj];
3198       if (m_doautoright) UpdateAutoCoords([obj frame]);
3199       [obj release];
3200       return (HWND)obj;
3201     }  
3202   }  
3203   
3204   NSTextField *obj;
3205   
3206   if (flags & ES_PASSWORD) obj=[[NSSecureTextField alloc] init];
3207   else obj=[[SWELL_TextField alloc] init];
3208   [obj setEditable:(flags & ES_READONLY)?NO:YES];
3209   if (flags & ES_READONLY) [obj setSelectable:YES];
3210   if (m_transform.size.width < minwidfontadjust)
3211     [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3212   
3213   NSCell* cell = [obj cell];  
3214   if (flags&ES_CENTER) [cell setAlignment:NSCenterTextAlignment];
3215   else if (flags&ES_RIGHT) [cell setAlignment:NSRightTextAlignment];
3216   if (abs(h) < 20)
3217   {
3218     [cell setWraps:NO];
3219     [cell setScrollable:YES];
3220   }
3221   [obj setTag:idx];
3222   [obj setTarget:ACTIONTARGET];
3223   [obj setAction:@selector(onSwellCommand:)];
3224   [obj setDelegate:ACTIONTARGET];
3225   
3226   [obj setFrame:MakeCoords(x,y,w,h,true)];
3227   if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3228   [m_make_owner addSubview:obj];
3229   if (m_doautoright) UpdateAutoCoords([obj frame]);
3230   [obj release];
3232   return (HWND)obj;
3235 HWND SWELL_MakeLabel( int align, const char *label, int idx, int x, int y, int w, int h, int flags)
3237   NSTextField *obj=[[SWELL_TextField alloc] init];
3238   [obj setEditable:NO];
3239   [obj setSelectable:NO];
3240   [obj setBordered:NO];
3241   [obj setBezeled:NO];
3242   [obj setDrawsBackground:NO];
3243   if (m_transform.size.width < minwidfontadjust)
3244     [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3246   if (flags & SS_NOTIFY)
3247   {
3248     [obj setTarget:ACTIONTARGET];
3249     [obj setAction:@selector(onSwellCommand:)];
3250   }
3251   
3252   NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(label);
3253   [obj setStringValue:labelstr];
3254   [obj setAlignment:(align<0?NSLeftTextAlignment:align>0?NSRightTextAlignment:NSCenterTextAlignment)];
3255   
3256   [[obj cell] setWraps:(h>12 ? YES : NO)];
3257   
3258   [obj setTag:idx];
3259   [obj setFrame:MakeCoords(x,y,w,h,true)];
3260   if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3261   [m_make_owner addSubview:obj];
3262   if (m_sizetofits && strlen(label)>1)[obj sizeToFit];
3263   if (m_doautoright) UpdateAutoCoords([obj frame]);
3264   [obj release];
3265   [labelstr release];
3266   return (HWND)obj;
3270 HWND SWELL_MakeCheckBox(const char *name, int idx, int x, int y, int w, int h, int flags=0)
3272   return SWELL_MakeControl(name,idx,"Button",BS_AUTOCHECKBOX|flags,x,y,w,h,0);
3275 HWND SWELL_MakeListBox(int idx, int x, int y, int w, int h, int styles)
3277   HWND hw=SWELL_MakeControl("",idx,"SysListView32_LB",styles,x,y,w,h,0);
3278 /*  if (hw)
3279   {
3280     LVCOLUMN lvc={0,};
3281     RECT r;
3282     GetClientRect(hw,&r);
3283     lvc.cx=300;//yer.right-r.left;
3284     lvc.pszText="";
3285     ListView_InsertColumn(hw,0,&lvc);
3286   }
3287   */
3288   return hw;
3292 typedef struct ccprocrec
3294   SWELL_ControlCreatorProc proc;
3295   int cnt;
3296   struct ccprocrec *next;
3297 } ccprocrec;
3299 static ccprocrec *m_ccprocs;
3301 void SWELL_RegisterCustomControlCreator(SWELL_ControlCreatorProc proc)
3303   if (!proc) return;
3304   
3305   ccprocrec *p=m_ccprocs;
3306   while (p && p->next)
3307   {
3308     if (p->proc == proc)
3309     {
3310       p->cnt++;
3311       return;
3312     }
3313     p=p->next;
3314   }
3315   ccprocrec *ent = (ccprocrec*)malloc(sizeof(ccprocrec));
3316   ent->proc=proc;
3317   ent->cnt=1;
3318   ent->next=0;
3319   
3320   if (p) p->next=ent;
3321   else m_ccprocs=ent;
3324 void SWELL_UnregisterCustomControlCreator(SWELL_ControlCreatorProc proc)
3326   if (!proc) return;
3327   
3328   ccprocrec *lp=NULL;
3329   ccprocrec *p=m_ccprocs;
3330   while (p)
3331   {
3332     if (p->proc == proc)
3333     {
3334       if (--p->cnt <= 0)
3335       {
3336         if (lp) lp->next=p->next;
3337         else m_ccprocs=p->next;
3338         free(p);
3339       }
3340       return;
3341     }
3342     lp=p;
3343     p=p->next;
3344   }
3348 HWND SWELL_MakeControl(const char *cname, int idx, const char *classname, int style, int x, int y, int w, int h, int exstyle)
3350   if (m_ccprocs)
3351   {
3352     NSRect wcr=MakeCoords(x,y,w,h,false);
3353     ccprocrec *p=m_ccprocs;
3354     while (p)
3355     {
3356       HWND hwnd=p->proc((HWND)m_make_owner,cname,idx,classname,style,
3357           (int)(wcr.origin.x+0.5),(int)(wcr.origin.y+0.5),(int)(wcr.size.width+0.5),(int)(wcr.size.height+0.5));
3358       if (hwnd) 
3359       {
3360         if (exstyle) SetWindowLong(hwnd,GWL_EXSTYLE,exstyle);
3361         return hwnd;
3362       }
3363       p=p->next;
3364     }
3365   }
3366   if (!stricmp(classname,"SysTabControl32"))
3367   {
3368     SWELL_TabView *obj=[[SWELL_TabView alloc] init];
3369     if (1) // todo: only if on 10.4 maybe?
3370     {
3371       y-=1;
3372       h+=6;
3373     }
3374     [obj setTag:idx];
3375     [obj setDelegate:(id)obj];
3376     [obj setAllowsTruncatedLabels:YES];
3377     [obj setNotificationWindow:ACTIONTARGET];
3378     [obj setHidden:NO];
3379     [obj setFrame:MakeCoords(x,y,w,h,false)];
3380     if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3381     [m_make_owner addSubview:obj];
3382     SetAllowNoMiddleManRendering((HWND)m_make_owner,FALSE);
3383     [obj release];
3384     return (HWND)obj;
3385   }
3386   else if (!stricmp(classname, "SysListView32")||!stricmp(classname, "SysListView32_LB"))
3387   {
3388     SWELL_ListView *obj = [[SWELL_ListView alloc] init];
3389     [obj setColumnAutoresizingStyle:NSTableViewNoColumnAutoresizing];
3390     [obj setFocusRingType:NSFocusRingTypeNone];
3391     [obj setDataSource:(id)obj];
3392     obj->style=style;
3394     BOOL isLB=!stricmp(classname, "SysListView32_LB");
3395     [obj setSwellNotificationMode:isLB];
3396     
3397     if (isLB)
3398     {
3399       [obj setHeaderView:nil];
3400       [obj setAllowsMultipleSelection:!!(style & LBS_EXTENDEDSEL)];
3401     }
3402     else
3403     {
3404       if ((style & LVS_NOCOLUMNHEADER) || !(style & LVS_REPORT))  [obj setHeaderView:nil];
3405       [obj setAllowsMultipleSelection:!(style & LVS_SINGLESEL)];
3406     }
3407     [obj setAllowsColumnReordering:NO];
3408     [obj setAllowsEmptySelection:YES];
3409     [obj setTag:idx];
3410     [obj setHidden:NO];
3411     id target=ACTIONTARGET;
3412     [obj setDelegate:target];
3413     [obj setTarget:target];
3414     [obj setAction:@selector(onSwellCommand:)];
3415     if ([target respondsToSelector:@selector(swellOnControlDoubleClick:)])
3416     {
3417       [obj setDoubleAction:@selector(swellOnControlDoubleClick:)];
3418     }
3419     else
3420     {
3421       [obj setDoubleAction:@selector(onSwellCommand:)];
3422     }
3423     NSScrollView *obj2=[[NSScrollView alloc] init];
3424     NSRect tr=MakeCoords(x,y,w,h,false);
3425     [obj2 setFrame:tr];
3426     [obj2 setDocumentView:obj];
3427     [obj2 setHasVerticalScroller:YES];
3428     if (!isLB) [obj2 setHasHorizontalScroller:YES];
3429     [obj2 setAutohidesScrollers:YES];
3430     [obj2 setDrawsBackground:NO];
3431     [obj release];
3432     if (style&SWELL_NOT_WS_VISIBLE) [obj2 setHidden:YES];
3433     [m_make_owner addSubview:obj2];
3434     [obj2 release];
3435     
3436     if (isLB || !(style & LVS_REPORT))
3437     {
3438       LVCOLUMN lvc={0,};
3439       lvc.mask=LVCF_TEXT|LVCF_WIDTH;
3440       lvc.cx=(int)ceil(wdl_max(tr.size.width,300.0));
3441       lvc.pszText=(char*)"";
3442       ListView_InsertColumn((HWND)obj,0,&lvc);
3443       if (isLB && (style & LBS_OWNERDRAWFIXED))
3444       {
3445         NSArray *ar=[obj tableColumns];
3446         NSTableColumn *c;
3447         if (ar && [ar count] && (c=[ar objectAtIndex:0]))
3448         {
3449           SWELL_ODListViewCell *t=[[SWELL_ODListViewCell alloc] init];
3450           [c setDataCell:t];
3451           [t setOwnerControl:obj];
3452           [t release];
3453         }
3454       }
3455     }
3456     
3457     return (HWND)obj;
3458   }
3459   else if (!stricmp(classname, "SysTreeView32"))
3460   {
3461     SWELL_TreeView *obj = [[SWELL_TreeView alloc] init];
3462     [obj setFocusRingType:NSFocusRingTypeNone];
3463     [obj setDataSource:(id)obj];
3464     obj->style=style;
3465     id target=ACTIONTARGET;
3466     [obj setHeaderView:nil];    
3467     [obj setDelegate:target];
3468     [obj setAllowsColumnReordering:NO];
3469     [obj setAllowsMultipleSelection:NO];
3470     [obj setAllowsEmptySelection:YES];
3471     [obj setTag:idx];
3472     [obj setHidden:NO];
3473     [obj setTarget:target];
3474     [obj setAction:@selector(onSwellCommand:)];
3475     if ([target respondsToSelector:@selector(swellOnControlDoubleClick:)])
3476       [obj setDoubleAction:@selector(swellOnControlDoubleClick:)];
3477     else
3478       [obj setDoubleAction:@selector(onSwellCommand:)];
3479     NSScrollView *obj2=[[NSScrollView alloc] init];
3480     NSRect tr=MakeCoords(x,y,w,h,false);
3481     [obj2 setFrame:tr];
3482     [obj2 setDocumentView:obj];
3483     [obj2 setHasVerticalScroller:YES];
3484     [obj2 setAutohidesScrollers:YES];
3485     [obj2 setDrawsBackground:NO];
3486     [obj release];
3487     if (style&SWELL_NOT_WS_VISIBLE) [obj2 setHidden:YES];
3488     [m_make_owner addSubview:obj2];
3489     [obj2 release];
3491     {
3492       NSTableColumn *col=[[NSTableColumn alloc] init];
3493       SWELL_ListViewCell *cell = [[SWELL_ListViewCell alloc] initTextCell:@""];
3494       [col setDataCell:cell];
3495       [cell release];
3497       [col setWidth:(int)ceil(wdl_max(tr.size.width,300.0))];
3498       [col setEditable:NO];
3499       [[col dataCell] setWraps:NO];     
3500       [obj addTableColumn:col];
3501       [obj setOutlineTableColumn:col];
3503       [col release];
3504     }
3505 ///    [obj setIndentationPerLevel:10.0];
3506     
3507     return (HWND)obj;
3508   }
3509   else if (!stricmp(classname, "msctls_progress32"))
3510   {
3511     SWELL_ProgressView *obj=[[SWELL_ProgressView alloc] init];
3512     [obj setStyle:NSProgressIndicatorBarStyle];
3513     [obj setIndeterminate:NO];
3514     [obj setTag:idx];
3515     [obj setFrame:MakeCoords(x,y,w,h,false)];
3516     if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3517     [m_make_owner addSubview:obj];
3518     [obj release];
3519     return (HWND)obj;
3520   }
3521   else if (!stricmp(classname,"Edit"))
3522   {
3523     return SWELL_MakeEditField(idx,x,y,w,h,style);
3524   }
3525   else if (!stricmp(classname, "static"))
3526   {
3527     NSTextField *obj=[[SWELL_TextField alloc] init];
3528     [obj setEditable:NO];
3529     [obj setSelectable:NO];
3530     [obj setBordered:NO];
3531     [obj setBezeled:NO];
3532     [obj setDrawsBackground:NO];
3533     if (m_transform.size.width < minwidfontadjust)
3534       [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3536     if (cname && *cname)
3537     {
3538       NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(cname);
3539       [obj setStringValue:labelstr];
3540       [labelstr release];
3541     }
3542     
3543     if ((style&SS_TYPEMASK) == SS_LEFTNOWORDWRAP) [[obj cell] setWraps:NO];
3544     else if ((style&SS_TYPEMASK) == SS_CENTER) [[obj cell] setAlignment:NSCenterTextAlignment];
3545     else if ((style&SS_TYPEMASK) == SS_RIGHT) [[obj cell] setAlignment:NSRightTextAlignment];
3547     [obj setTag:idx];
3548     [obj setFrame:MakeCoords(x,y,w,h,true)];
3549     if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3550     [m_make_owner addSubview:obj];
3551     if ((style & SS_TYPEMASK) == SS_BLACKRECT)
3552     {
3553       [obj setHidden:YES];
3554     }
3555     [obj release];
3556     return (HWND)obj;
3557   }
3558   else if (!stricmp(classname,"Button"))
3559   {
3560     if (style & BS_GROUPBOX)
3561     {
3562       return SWELL_MakeGroupBox(cname, idx, x, y, w, h, style &~BS_GROUPBOX);
3563     }
3564     if (style & BS_DEFPUSHBUTTON)
3565     {
3566        return SWELL_MakeButton(1, cname, idx, x,y,w,h,style &~BS_DEFPUSHBUTTON);
3567     }
3568     if (style & BS_PUSHBUTTON)
3569     {
3570        return SWELL_MakeButton(0, cname, idx, x,y,w,h,style &~BS_PUSHBUTTON);
3571     }
3572     SWELL_Button *button=[[SWELL_Button alloc] init];
3573     [button setTag:idx];
3574     NSRect fr=MakeCoords(x,y,w,h,true);
3575     SEL actionSel = @selector(onSwellCommand:);
3576     if ((style & 0xf) == BS_AUTO3STATE)
3577     {
3578       [button setButtonType:NSSwitchButton];
3579       [button setAllowsMixedState:YES];
3580     }    
3581     else if ((style & 0xf) == BS_AUTOCHECKBOX)
3582     {
3583       [button setButtonType:NSSwitchButton];
3584       [button setAllowsMixedState:NO];
3585     }
3586     else if ((style & 0xf) == BS_AUTORADIOBUTTON)
3587     {
3588 #ifdef MAC_OS_X_VERSION_10_8
3589       // Compiling with the OSX 10.8+ SDK and running on 10.8+ causes radio buttons with a common action selector to
3590       // be treated as a group. This works around that. if you need more than 8 groups (seriously?!), add the extra 
3591       // functions in swell-dlg.mm and in the switch below
3592       {
3593         NSView *v;
3594         NSArray *sv;
3595         if ((style & WS_GROUP) ||
3596               !(sv = [m_make_owner subviews]) || 
3597               ![sv count] ||
3598               !(v = [sv lastObject]) ||
3599               ![v isKindOfClass:[SWELL_Button class]] ||
3600               ([(SWELL_Button *)v swellGetRadioFlags]&2)) m_make_radiogroupcnt++;
3601       }
3602       switch (m_make_radiogroupcnt & 7)
3603       {
3604         case 0: actionSel = @selector(onSwellCommand0:); break;
3605         case 1: break; // default
3606         case 2: actionSel = @selector(onSwellCommand2:); break;
3607         case 3: actionSel = @selector(onSwellCommand3:); break;
3608         case 4: actionSel = @selector(onSwellCommand4:); break;
3609         case 5: actionSel = @selector(onSwellCommand5:); break;
3610         case 6: actionSel = @selector(onSwellCommand6:); break;
3611         case 7: actionSel = @selector(onSwellCommand7:); break;
3612       }
3613 #endif
3614      
3615       [button setButtonType:NSRadioButton];
3616       [button swellSetRadioFlags:(style & WS_GROUP)?3:1];
3617     }
3618     else if ((style & 0xf) == BS_OWNERDRAW)
3619     {
3620       SWELL_ODButtonCell *cell = [[SWELL_ODButtonCell alloc] init];
3621       [button setCell:cell];
3622       [cell release];
3623       //NSButtonCell
3624     }
3625     else // normal button
3626     {
3627       if (style & BS_BITMAP)
3628       {
3629         SWELL_ImageButtonCell * cell = [[SWELL_ImageButtonCell alloc] init];
3630         [button setCell:cell];
3631         [cell release];
3632       }
3633 //      fr.size.width+=8;
3634     }
3635     
3636     if (m_transform.size.width < minwidfontadjust)
3637       [button setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3638     [button setFrame:fr];
3639     NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(cname);
3640     [button setTitle:labelstr];
3641     [button setTarget:ACTIONTARGET];
3642     [button setAction:actionSel];
3643     if (style&BS_LEFTTEXT) [button setImagePosition:NSImageRight];
3644     if (style&SWELL_NOT_WS_VISIBLE) [button setHidden:YES];
3645     [m_make_owner addSubview:button];
3646     if (m_sizetofits && (style & 0xf) != BS_OWNERDRAW) [button sizeToFit];
3647     if (m_doautoright) UpdateAutoCoords([button frame]);
3648     [labelstr release];
3649     [button release];
3650     return (HWND)button;
3651   }
3652   else if (!stricmp(classname,"REAPERhfader")||!stricmp(classname,"msctls_trackbar32"))
3653   {
3654     NSSlider *obj=[[NSSlider alloc] init];
3655     [obj setTag:idx];
3656     [obj setMinValue:0.0];
3657     [obj setMaxValue:1000.0];
3658     [obj setFrame:MakeCoords(x,y,w,h,false)];
3659     if (!stricmp(classname, "msctls_trackbar32"))
3660     {
3661       [[obj cell] setControlSize:NSMiniControlSize];
3662     }
3663     [obj setTarget:ACTIONTARGET];
3664     [obj setAction:@selector(onSwellCommand:)];
3665     if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3666     [m_make_owner addSubview:obj];
3667     [obj release];
3668     return (HWND)obj;
3669   }
3670   return 0;
3673 HWND SWELL_MakeCombo(int idx, int x, int y, int w, int h, int flags)
3675   if ((flags & 0x3) == CBS_DROPDOWNLIST)
3676   {
3677     SWELL_PopUpButton *obj=[[SWELL_PopUpButton alloc] init];
3678     [obj setTag:idx];
3679     [obj setFont:[NSFont systemFontOfSize:10.0f]];
3680     NSRect rc=MakeCoords(x,y,w,18,true,true);
3681         
3682     [obj setSwellStyle:flags];
3683     [obj setFrame:rc];
3684     [obj setAutoenablesItems:NO];
3685     [obj setTarget:ACTIONTARGET];
3686     [obj setAction:@selector(onSwellCommand:)];
3688     if (g_swell_want_nice_style==1)
3689     {
3690       [obj setBezelStyle:NSShadowlessSquareBezelStyle ];
3691       [[obj cell] setArrowPosition:NSPopUpArrowAtBottom];
3692     }
3693     if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3694     [m_make_owner addSubview:obj];
3695     if (m_doautoright) UpdateAutoCoords([obj frame]);
3696     [obj release];
3697     return (HWND)obj;
3698   }
3699   else
3700   {
3701     SWELL_ComboBox *obj=[[SWELL_ComboBox alloc] init];
3702     [obj setFocusRingType:NSFocusRingTypeNone];
3703     [obj setFont:[NSFont systemFontOfSize:10.0f]];
3704     [obj setEditable:(flags & 0x3) == CBS_DROPDOWNLIST?NO:YES];
3705     [obj setSwellStyle:flags];
3706     [obj setTag:idx];
3707     [obj setFrame:MakeCoords(x,y-1,w,22,true,true)];
3708     [obj setTarget:ACTIONTARGET];
3709     [obj setAction:@selector(onSwellCommand:)];
3710     [obj setDelegate:ACTIONTARGET];
3711     if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3712     [m_make_owner addSubview:obj];
3713     if (m_doautoright) UpdateAutoCoords([obj frame]);
3714     [obj release];
3715     return (HWND)obj;
3716   }
3719 @implementation SWELL_BoxView
3721 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
3723 -(NSInteger) tag
3725   return m_tag;
3727 -(void) setTag:(NSInteger)tag
3729   m_tag=tag;
3731 @end
3733 HWND SWELL_MakeGroupBox(const char *name, int idx, int x, int y, int w, int h, int style)
3735   SWELL_BoxView *obj=[[SWELL_BoxView alloc] init];
3736   
3737   // this just doesn't work, you can't color the border unless it's NSBoxCustom, 
3738   // and I can't get it to show the title text if it's NSBoxCustom
3739   //[obj setBoxType:(NSBoxType)4];   // NSBoxCustom, so we can color the border 
3740   //[obj setTitlePosition:(NSTitlePosition)2];  // NSAtTop, default but NSBoxCustom unsets it
3741   
3742 //  [obj setTag:idx];
3743   if (1) // todo: only if on 10.4 maybe?
3744   {
3745     y-=1;
3746     h+=3;
3747   }
3748   NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(name);
3749   [obj setTitle:labelstr];
3750   [obj setTag:idx];
3751   [labelstr release];
3752   if (style & BS_CENTER)
3753   {
3754     [[obj titleCell] setAlignment:NSCenterTextAlignment];
3755   }
3756   [obj setFrame:MakeCoords(x,y,w,h,false)];
3757   [m_make_owner addSubview:obj positioned:NSWindowBelow relativeTo:nil];
3758   [obj release];
3759   return (HWND)obj;
3763 int TabCtrl_GetItemCount(HWND hwnd)
3765   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return 0;
3766   SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3767   return (int)[tv numberOfTabViewItems];
3770 BOOL TabCtrl_AdjustRect(HWND hwnd, BOOL fLarger, RECT *r)
3772   if (!r || !hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return FALSE;
3773   
3774   int sign=fLarger?-1:1;
3775   r->left+=sign*7; // todo: correct this?
3776   r->right-=sign*7;
3777   r->top+=sign*26;
3778   r->bottom-=sign*3;
3779   return TRUE;
3783 BOOL TabCtrl_DeleteItem(HWND hwnd, int idx)
3785   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return 0;
3786   SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3787   if (idx<0 || idx>= [tv numberOfTabViewItems]) return 0;
3788   [tv removeTabViewItem:[tv tabViewItemAtIndex:idx]];
3789   return TRUE;
3792 int TabCtrl_InsertItem(HWND hwnd, int idx, TCITEM *item)
3794   if (!item || !hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return -1;
3795   if (!(item->mask & TCIF_TEXT) || !item->pszText) return -1;
3796   SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3798   const int ni = (int)[tv numberOfTabViewItems];
3799   if (idx<0) idx=0;
3800   else if (idx>ni) idx=ni;
3801   
3802   NSTabViewItem *tabitem=[[NSTabViewItem alloc] init];
3803   NSString *str=(NSString *)SWELL_CStringToCFString(item->pszText);  
3804   [tabitem setLabel:str];
3805   [str release];
3806   id turd=[tv getNotificationWindow];
3807   [tv setNotificationWindow:nil];
3808   [tv insertTabViewItem:tabitem atIndex:idx];
3809   [tv setNotificationWindow:turd];
3810   [tabitem release];
3811   return idx;
3814 int TabCtrl_SetCurSel(HWND hwnd, int idx)
3816   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return -1;
3817   SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3818   int ret=TabCtrl_GetCurSel(hwnd);
3819   if (idx>=0 && idx < [tv numberOfTabViewItems])
3820   {
3821     [tv selectTabViewItemAtIndex:idx];
3822   }
3823   return ret;
3826 int TabCtrl_GetCurSel(HWND hwnd)
3828   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return 0;
3829   SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3830   NSTabViewItem *item=[tv selectedTabViewItem];
3831   if (!item) return 0;
3832   return (int)[tv indexOfTabViewItem:item];
3835 void ListView_SetExtendedListViewStyleEx(HWND h, int mask, int style)
3837   if (!h) return;
3838   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
3839   SWELL_ListView *tv=(SWELL_ListView*)h;
3840   
3841   if (mask&LVS_EX_GRIDLINES)
3842   {
3843     int s=0;
3844     if (style&LVS_EX_GRIDLINES) 
3845     {
3846       s=NSTableViewSolidVerticalGridLineMask|NSTableViewSolidHorizontalGridLineMask;
3847     }
3848     [tv setGridStyleMask:s];
3849   }
3850   
3851   if (mask&LVS_EX_HEADERDRAGDROP)
3852   {
3853     [tv setAllowsColumnReordering:!!(style&LVS_EX_HEADERDRAGDROP)];
3854   }
3855   
3856   
3857   // todo LVS_EX_FULLROWSELECT (enabled by default on OSX)
3860 void SWELL_SetListViewFastClickMask(HWND hList, int mask)
3862   if (!hList || ![(id)hList isKindOfClass:[SWELL_ListView class]]) return;
3863   SWELL_ListView *lv = (SWELL_ListView *)hList;
3864   lv->m_fastClickMask=mask;
3869 void ListView_SetImageList(HWND h, HIMAGELIST imagelist, int which)
3871   if (!h) return;
3872   
3873   SWELL_ListView *v=(SWELL_ListView *)h;
3874   
3875   v->m_status_imagelist_type=which;
3876   v->m_status_imagelist=(WDL_PtrList<HGDIOBJ__> *)imagelist;
3877   if (v->m_cols && v->m_cols->GetSize()>0)
3878   {
3879     NSTableColumn *col=(NSTableColumn*)v->m_cols->Get(0);
3880     if (![col isKindOfClass:[SWELL_StatusCell class]])
3881     {
3882       SWELL_StatusCell *cell=[[SWELL_StatusCell alloc] initNewCell];
3883       [cell setWraps:NO];
3884       [col setDataCell:cell];
3885       [cell release];
3886     }
3887   }  
3890 int ListView_GetColumnWidth(HWND h, int pos)
3892   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
3893   SWELL_ListView *v=(SWELL_ListView *)h;
3894   if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return 0;
3895   
3896   NSTableColumn *col=v->m_cols->Get(pos);
3897   if (!col) return 0;
3898   
3899   if ([col respondsToSelector:@selector(isHidden)] && [(SWELL_TableColumnExtensions*)col isHidden]) return 0;
3900   return (int) floor(0.5+[col width]);
3903 void ListView_InsertColumn(HWND h, int pos, const LVCOLUMN *lvc)
3905   if (!h || !lvc) return;
3906   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
3908   SWELL_BEGIN_TRY
3910   SWELL_ListView *v=(SWELL_ListView *)h;
3911   NSTableColumn *col=[[NSTableColumn alloc] init];
3912   // note, not looking at lvc->mask at all
3914   [col setEditable:NO];
3915   // [col setResizingMask:2];  // user resizable, this seems to be the default
3916   
3917   if (lvc->fmt == LVCFMT_CENTER) [[col headerCell] setAlignment:NSCenterTextAlignment];
3918   else if (lvc->fmt == LVCFMT_RIGHT) [[col headerCell] setAlignment:NSRightTextAlignment];
3919   
3920   if (!v->m_lbMode && !(v->style & LVS_NOCOLUMNHEADER))
3921   {
3922     NSString *lbl=(NSString *)SWELL_CStringToCFString(lvc->pszText);  
3923     [[col headerCell] setStringValue:lbl];
3924     [lbl release];
3925   }
3926   
3927   if (!pos && v->m_status_imagelist) 
3928   {
3929     SWELL_StatusCell *cell=[[SWELL_StatusCell alloc] initNewCell];
3930     [cell setWraps:NO];
3931     [col setDataCell:cell];
3932     [cell release];
3933   }
3934   else
3935   {  
3936     SWELL_ListViewCell *cell = [[SWELL_ListViewCell alloc] initTextCell:@""];
3937     [col setDataCell:cell];
3938     [cell setWraps:NO];
3939    
3940     if (lvc->fmt == LVCFMT_CENTER) [cell setAlignment:NSCenterTextAlignment];
3941     else if (lvc->fmt == LVCFMT_RIGHT) [cell setAlignment:NSRightTextAlignment];
3942     [cell release];
3943   }
3945   [v addTableColumn:col];
3946   v->m_cols->Add(col);
3947   [col release];
3949   if (lvc->mask&LVCF_WIDTH)
3950   {
3951     ListView_SetColumnWidth(h,pos,lvc->cx);
3952   }
3953   SWELL_END_TRY(;)
3956 void ListView_SetColumn(HWND h, int pos, const LVCOLUMN *lvc)
3958   if (!h || !lvc || ![(id)h isKindOfClass:[SWELL_ListView class]]) return;
3959   SWELL_ListView *v=(SWELL_ListView *)h;
3960   if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return;
3961   
3962   NSTableColumn *col=v->m_cols->Get(pos);
3963   if (!col) return;
3964   
3965   if (lvc->mask&LVCF_FMT)
3966   {
3967     if (lvc->fmt == LVCFMT_LEFT) [[col headerCell] setAlignment:NSLeftTextAlignment];
3968     else if (lvc->fmt == LVCFMT_CENTER) [[col headerCell] setAlignment:NSCenterTextAlignment];
3969     else if (lvc->fmt == LVCFMT_RIGHT) [[col headerCell] setAlignment:NSRightTextAlignment];
3970   }
3971   if (lvc->mask&LVCF_WIDTH)
3972   {
3973     if (!lvc->cx)
3974     {
3975       if ([col respondsToSelector:@selector(setHidden:)])  [(SWELL_TableColumnExtensions*)col setHidden:YES];
3976     }
3977     else 
3978     {
3979       if ([col respondsToSelector:@selector(setHidden:)])  [(SWELL_TableColumnExtensions*)col setHidden:NO];
3980       [col setWidth:lvc->cx];
3981     }
3982   }
3983   if (lvc->mask&LVCF_TEXT)
3984   {
3985     if (!v->m_lbMode && !(v->style&LVS_NOCOLUMNHEADER))
3986     {
3987       NSString *lbl=(NSString *)SWELL_CStringToCFString(lvc->pszText);  
3988       [[col headerCell] setStringValue:lbl];
3989       [lbl release]; 
3990     }
3991   }
3994 bool ListView_DeleteColumn(HWND h, int pos)
3996         if (!h) return false;
3997         if (![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
3998         SWELL_ListView *v=(SWELL_ListView *)h;
3999         if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return false;
4000         [v removeTableColumn:v->m_cols->Get(pos)];
4001         v->m_cols->Delete(pos);
4002         return true;
4005 void ListView_GetItemText(HWND hwnd, int item, int subitem, char *text, int textmax)
4007   LVITEM it={LVIF_TEXT,item,subitem,0,0,text,textmax,};
4008   ListView_GetItem(hwnd,&it);
4011 int ListView_InsertItem(HWND h, const LVITEM *item)
4013   if (!h || !item || item->iSubItem) return 0;
4014   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4015   
4016   SWELL_ListView *tv=(SWELL_ListView*)h;
4017   if (!tv->m_lbMode && (tv->style & LVS_OWNERDATA)) return -1;
4018   if (!tv->m_items) return -1;
4019     
4020   int a=item->iItem;
4021   if (a<0)a=0;
4022   else if (a > tv->m_items->GetSize()) a=tv->m_items->GetSize();
4023   
4024   if (!tv->m_lbMode && (item->mask & LVIF_TEXT))
4025   {
4026     if (tv->style & LVS_SORTASCENDING)
4027     {
4028        a=ptrlist_bsearch_mod((char *)item->pszText,tv->m_items,_listviewrowSearchFunc,NULL);
4029     }
4030     else if (tv->style & LVS_SORTDESCENDING)
4031     {
4032        a=ptrlist_bsearch_mod((char *)item->pszText,tv->m_items,_listviewrowSearchFunc2,NULL);
4033     }
4034   }
4035   
4036   SWELL_ListView_Row *nr=new SWELL_ListView_Row;
4037   nr->m_vals.Add(strdup((item->mask & LVIF_TEXT) ? item->pszText : ""));
4038   if (item->mask & LVIF_PARAM) nr->m_param = item->lParam;
4039   tv->m_items->Insert(a,nr);
4040   
4042   
4043   if ((item->mask&LVIF_STATE) && (item->stateMask & (0xff<<16)))
4044   {
4045     nr->m_imageidx=(item->state>>16)&0xff;
4046   }
4047   
4048   [tv reloadData];
4049   
4050   if (a < tv->m_items->GetSize()-1)
4051   {
4052     NSIndexSet *sel=[tv selectedRowIndexes];
4053     if (sel && [sel count])
4054     {
4055       NSMutableIndexSet *ms = [[NSMutableIndexSet alloc] initWithIndexSet:sel];
4056       [ms shiftIndexesStartingAtIndex:a by:1];
4057       [tv selectRowIndexes:ms byExtendingSelection:NO];
4058       [ms release];
4059     }
4060   }
4061   
4062   if (item->mask & LVIF_STATE)
4063   {
4064     if (item->stateMask & LVIS_SELECTED)
4065     {
4066       if (item->state&LVIS_SELECTED)
4067       {
4068         bool isSingle = tv->m_lbMode ? !(tv->style & LBS_EXTENDEDSEL) : !!(tv->style&LVS_SINGLESEL);
4069         [tv selectRowIndexes:[NSIndexSet indexSetWithIndex:a] byExtendingSelection:isSingle?NO:YES];        
4070       }
4071     }
4072   }
4073   
4074   return a;
4077 void ListView_SetItemText(HWND h, int ipos, int cpos, const char *txt)
4079   if (!h || cpos < 0 || cpos >= 32) return;
4080   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4081   
4082   SWELL_ListView *tv=(SWELL_ListView*)h;
4083   if (!tv->m_lbMode && (tv->style & LVS_OWNERDATA)) return;
4084   if (!tv->m_items) return;
4085   
4086   SWELL_ListView_Row *p=tv->m_items->Get(ipos);
4087   if (!p) return;
4088   int x;
4089   for (x = p->m_vals.GetSize(); x < cpos; x ++)
4090   {
4091     p->m_vals.Add(strdup(""));
4092   }
4093   if (cpos < p->m_vals.GetSize())
4094   {
4095     free(p->m_vals.Get(cpos));
4096     p->m_vals.Set(cpos,strdup(txt));
4097   }
4098   else p->m_vals.Add(strdup(txt));
4099     
4100   [tv reloadData];
4103 int ListView_GetNextItem(HWND h, int istart, int flags)
4105   if (flags==LVNI_FOCUSED||flags==LVNI_SELECTED)
4106   {
4107     if (!h) return -1;
4108     if (![(id)h isKindOfClass:[SWELL_ListView class]]) return -1;
4109     
4110     SWELL_ListView *tv=(SWELL_ListView*)h;
4111     
4112     if (flags==LVNI_SELECTED)
4113     {
4114       //int orig_start=istart;
4115       if (istart++<0)istart=0;
4116       const int n = (int)[tv numberOfRows];
4117       while (istart < n)
4118       {
4119         if ([tv isRowSelected:istart]) return istart;
4120         istart++;
4121       }
4122       return -1;
4123     }
4124     
4125     return (int)[tv selectedRow];
4126   }
4127   return -1;
4130 bool ListView_SetItem(HWND h, LVITEM *item)
4132   if (!item) return false;
4133   if (!h) return false;
4134   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
4135     
4136   SWELL_ListView *tv=(SWELL_ListView*)h;
4137   if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4138   {
4139     if (!tv->m_items) return false;
4140     SWELL_ListView_Row *row=tv->m_items->Get(item->iItem);
4141     if (!row) return false;  
4142   
4143     if (item->mask & LVIF_PARAM) 
4144     {
4145       row->m_param=item->lParam;
4146     }
4147     if ((item->mask & LVIF_TEXT) && item->pszText) 
4148     {
4149       ListView_SetItemText(h,item->iItem,item->iSubItem,item->pszText);
4150     }
4151     if ((item->mask&LVIF_IMAGE) && item->iImage >= 0)
4152     {
4153       row->m_imageidx=item->iImage+1;
4154       ListView_RedrawItems(h, item->iItem, item->iItem);
4155     }
4156   }
4157   if ((item->mask & LVIF_STATE) && item->stateMask)
4158   {
4159     ListView_SetItemState(h,item->iItem,item->state,item->stateMask); 
4160   }
4162   return true;
4165 bool ListView_GetItem(HWND h, LVITEM *item)
4167   if (!item) return false;
4168   if ((item->mask&LVIF_TEXT)&&item->pszText && item->cchTextMax > 0) item->pszText[0]=0;
4169   item->state=0;
4170   if (!h) return false;
4171   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
4172   
4173   
4174   SWELL_ListView *tv=(SWELL_ListView*)h;
4175   if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4176   {
4177     if (!tv->m_items) return false;
4178     
4179     SWELL_ListView_Row *row=tv->m_items->Get(item->iItem);
4180     if (!row) return false;  
4181   
4182     if (item->mask & LVIF_PARAM) item->lParam=row->m_param;
4183     if (item->mask & LVIF_TEXT) if (item->pszText && item->cchTextMax>0)
4184     {
4185       char *p=row->m_vals.Get(item->iSubItem);
4186       lstrcpyn_safe(item->pszText,p?p:"",item->cchTextMax);
4187     }
4188       if (item->mask & LVIF_STATE)
4189       {
4190         if (item->stateMask & (0xff<<16))
4191         {
4192           item->state|=row->m_imageidx<<16;
4193         }
4194       }
4195   }
4196   else
4197   {
4198     if (item->iItem <0 || item->iItem >= tv->ownermode_cnt) return false;
4199   }
4200   if (item->mask & LVIF_STATE)
4201   {
4202      if ((item->stateMask&LVIS_SELECTED) && [tv isRowSelected:item->iItem]) item->state|=LVIS_SELECTED;
4203      if ((item->stateMask&LVIS_FOCUSED) && [tv selectedRow] == item->iItem) item->state|=LVIS_FOCUSED;
4204   }
4206   return true;
4208 int ListView_GetItemState(HWND h, int ipos, UINT mask)
4210   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4211   SWELL_ListView *tv=(SWELL_ListView*)h;
4212   UINT flag=0;
4213   if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4214   {
4215     if (!tv->m_items) return 0;
4216     SWELL_ListView_Row *row=tv->m_items->Get(ipos);
4217     if (!row) return 0;  
4218     if (mask & (0xff<<16))
4219     {
4220       flag|=row->m_imageidx<<16;
4221     }
4222   }
4223   else
4224   {
4225     if (ipos<0 || ipos >= tv->ownermode_cnt) return 0;
4226   }
4227   
4228   if ((mask&LVIS_SELECTED) && [tv isRowSelected:ipos]) flag|=LVIS_SELECTED;
4229   if ((mask&LVIS_FOCUSED) && [tv selectedRow]==ipos) flag|=LVIS_FOCUSED;
4230   return flag;  
4233 bool ListView_SetItemState(HWND h, int ipos, UINT state, UINT statemask)
4235   int doref=0;
4236   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
4237   SWELL_ListView *tv=(SWELL_ListView*)h;
4238   static int _is_doing_all;
4239   
4240   if (ipos == -1)
4241   {
4242     int x;
4243     int n=ListView_GetItemCount(h);
4244     _is_doing_all++;
4245     for (x = 0; x < n; x ++)
4246       ListView_SetItemState(h,x,state,statemask);
4247     _is_doing_all--;
4248     ListView_RedrawItems(h,0,n-1);
4249     return true;
4250   }
4252   if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4253   {
4254     if (!tv->m_items) return false;
4255     SWELL_ListView_Row *row=tv->m_items->Get(ipos);
4256     if (!row) return false;  
4257     if (statemask & (0xff<<16))
4258     {
4259       if (row->m_imageidx!=((state>>16)&0xff))
4260       {
4261         row->m_imageidx=(state>>16)&0xff;
4262         doref=1;
4263       }
4264     }
4265   }
4266   else
4267   {
4268     if (ipos<0 || ipos >= tv->ownermode_cnt) return 0;
4269   }
4270   bool didsel=false;
4271   if (statemask & LVIS_SELECTED)
4272   {
4273     if (state & LVIS_SELECTED)
4274     {      
4275       bool isSingle = tv->m_lbMode ? !(tv->style & LBS_EXTENDEDSEL) : !!(tv->style&LVS_SINGLESEL);
4276       if (![tv isRowSelected:ipos]) { didsel=true;  [tv selectRowIndexes:[NSIndexSet indexSetWithIndex:ipos] byExtendingSelection:isSingle?NO:YES]; }
4277     }
4278     else
4279     {
4280       if ([tv isRowSelected:ipos]) { didsel=true; [tv deselectRow:ipos];  }
4281     }
4282   }
4283   if (statemask & LVIS_FOCUSED)
4284   {
4285     if (state&LVIS_FOCUSED)
4286     {
4287     }
4288     else
4289     {
4290       
4291     }
4292   }
4293   
4294   if (!_is_doing_all)
4295   {
4296     if (didsel)
4297     {
4298       static int __rent;
4299       if (!__rent)
4300       {
4301         __rent=1;
4302         NMLISTVIEW nm={{(HWND)h,(UINT_PTR)[tv tag],LVN_ITEMCHANGED},ipos,0,state,};
4303         SendMessage(GetParent(h),WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
4304         __rent=0;
4305       }
4306     }
4307     if (doref)
4308       ListView_RedrawItems(h,ipos,ipos);
4309   }
4310   return true;
4313 void ListView_RedrawItems(HWND h, int startitem, int enditem)
4315   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4316   SWELL_ListView *tv=(SWELL_ListView*)h;
4317   if (!tv->m_items) return;
4318   [tv reloadData];
4321 void ListView_DeleteItem(HWND h, int ipos)
4323   if (!h) return;
4324   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4325   
4326   SWELL_ListView *tv=(SWELL_ListView*)h;
4327   if (!tv->m_items) return;
4328   
4329   if (ipos >=0 && ipos < tv->m_items->GetSize())
4330   {
4331     if (ipos != tv->m_items->GetSize()-1)
4332     {
4333       NSIndexSet *sel=[tv selectedRowIndexes];
4334       if (sel && [sel count])
4335       {
4336         NSMutableIndexSet *ms = [[NSMutableIndexSet alloc] initWithIndexSet:sel];
4337         [ms shiftIndexesStartingAtIndex:ipos+1 by:-1];
4338         [tv selectRowIndexes:ms byExtendingSelection:NO];
4339         [ms release];
4340       }
4341     }
4342     tv->m_items->Delete(ipos,true);
4343     
4344     [tv reloadData];
4345     
4346   }
4349 void ListView_DeleteAllItems(HWND h)
4351   if (!h) return;
4352   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4353   
4354   SWELL_ListView *tv=(SWELL_ListView*)h;
4355   tv->ownermode_cnt=0;
4356   if (tv->m_items) tv->m_items->Empty(true);
4357   
4358   [tv reloadData];
4361 int ListView_GetSelectedCount(HWND h)
4363   if (!h) return 0;
4364   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4365   
4366   SWELL_ListView *tv=(SWELL_ListView*)h;
4367   return (int)[tv numberOfSelectedRows];
4370 int ListView_GetItemCount(HWND h)
4372   if (!h) return 0;
4373   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4374   
4375   SWELL_ListView *tv=(SWELL_ListView*)h;
4376   if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4377   {
4378     if (!tv->m_items) return 0;
4379   
4380     return tv->m_items->GetSize();
4381   }
4382   return tv->ownermode_cnt;
4385 int ListView_GetSelectionMark(HWND h)
4387   if (!h) return 0;
4388   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4389   
4390   SWELL_ListView *tv=(SWELL_ListView*)h;
4391   return (int)[tv selectedRow];
4394 int SWELL_GetListViewHeaderHeight(HWND h)
4396   if (!h) return 0;
4397   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4398   
4399   SWELL_ListView* tv=(SWELL_ListView*)h;
4400   NSTableHeaderView* hv=[tv headerView];
4401   NSRect r=[hv bounds];
4402   return (int)(r.size.height+0.5);
4405 void ListView_SetColumnWidth(HWND h, int pos, int wid)
4407   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4408   SWELL_ListView *v=(SWELL_ListView *)h;
4409   if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return;
4410   
4411   NSTableColumn *col=v->m_cols->Get(pos);
4412   if (!col) return;
4413   
4414   if (!wid)
4415   {
4416     if ([col respondsToSelector:@selector(setHidden:)])  [(SWELL_TableColumnExtensions*)col setHidden:YES];
4417   }
4418   else 
4419   {
4420     if ([col respondsToSelector:@selector(setHidden:)])  [(SWELL_TableColumnExtensions*)col setHidden:NO];
4421     [col setWidth:wid];
4422   }
4425 BOOL ListView_GetColumnOrderArray(HWND h, int cnt, int* arr)
4427   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return FALSE;
4428   SWELL_ListView* lv=(SWELL_ListView*)h;
4429   if (!lv->m_cols || lv->m_cols->GetSize() != cnt) return FALSE;
4430   
4431   int i;
4432   for (i=0; i < cnt; ++i)
4433   {
4434     arr[i]=[lv getColumnPos:i];
4435   }
4437   return TRUE;
4440 BOOL ListView_SetColumnOrderArray(HWND h, int cnt, int* arr)
4442   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return FALSE;
4443   SWELL_ListView* lv=(SWELL_ListView*)h;
4444   if (!lv->m_cols || lv->m_cols->GetSize() != cnt) return FALSE;
4445   
4446   int i;
4447   for (i=0; i < cnt; ++i)
4448   {
4449     int pos=[lv getColumnPos:i];
4450     int dest=arr[i];
4451     if (dest>=0 && dest<cnt) [lv moveColumn:pos toColumn:dest];
4452   }
4454   return TRUE;
4457 HWND ListView_GetHeader(HWND h)
4459   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4460   return h;
4463 int Header_GetItemCount(HWND h)
4465   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4466   SWELL_ListView* lv=(SWELL_ListView*)h;
4467   if (lv->m_cols) return lv->m_cols->GetSize();
4468   return 0;
4471 BOOL Header_GetItem(HWND h, int col, HDITEM* hi)
4473   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]] || !hi) return FALSE;
4474   SWELL_ListView* lv=(SWELL_ListView*)h;
4475   if (!lv->m_cols || col < 0 || col >= lv->m_cols->GetSize()) return FALSE;
4476   NSTableColumn* hcol=lv->m_cols->Get(col);
4477   if (!hcol) return FALSE;
4478   
4479   if (hi->mask&HDI_FORMAT)
4480   {
4481     hi->fmt=0;
4482     NSImage* img=[lv indicatorImageInTableColumn:hcol];
4483     if (img)
4484     {
4485       NSString* imgname=[img name];
4486       if (imgname)
4487       {
4488         if ([imgname isEqualToString:@"NSAscendingSortIndicator"]) hi->fmt |= HDF_SORTUP;
4489         else if ([imgname isEqualToString:@"NSDescendingSortIndicator"]) hi->fmt |= HDF_SORTDOWN;
4490       }
4491     }
4492   }
4493   // etc todo
4494   
4495   return TRUE;
4498 BOOL Header_SetItem(HWND h, int col, HDITEM* hi)
4500   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]] || !hi) return FALSE;
4501   SWELL_ListView* lv=(SWELL_ListView*)h;
4502   if (!lv->m_cols || col < 0 || col >= lv->m_cols->GetSize()) return FALSE;
4503   NSTableColumn* hcol=lv->m_cols->Get(col);
4504   if (!hcol) return FALSE;
4505   
4506   if (hi->mask&HDI_FORMAT)
4507   {
4508     NSImage* img=0;
4509     if (hi->fmt&HDF_SORTUP) img=[NSImage imageNamed:@"NSAscendingSortIndicator"];
4510     else if (hi->fmt&HDF_SORTDOWN) img=[NSImage imageNamed:@"NSDescendingSortIndicator"];
4511     [lv setIndicatorImage:img inTableColumn:hcol];
4512   }
4513   // etc todo
4514   
4515   return TRUE;
4518 int ListView_HitTest(HWND h, LVHITTESTINFO *pinf)
4520   if (!h || !pinf) return -1;
4521   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return -1;
4522   
4523   SWELL_ListView *tv=(SWELL_ListView*)h;
4524   // return index
4525   pinf->flags=0;
4526   pinf->iItem=-1;
4527   
4528   // rowAtPoint will return a row even if it is scrolled out of the clip view
4529   NSScrollView* sv=(NSScrollView *)NavigateUpScrollClipViews(tv);
4530   if (![sv isKindOfClass:[NSScrollView class]] && ![sv isKindOfClass:[NSClipView class]]) sv=NULL;
4531   
4532   NSRect r=[sv documentVisibleRect];
4533   int x=pinf->pt.x-r.origin.x;
4534   int y=pinf->pt.y-r.origin.y;
4536   if (x < 0) pinf->flags |= LVHT_TOLEFT;
4537   if (x >= r.size.width) pinf->flags |= LVHT_TORIGHT;
4538   if (y < 0) pinf->flags |= LVHT_ABOVE;
4539   if (y >= r.size.height) pinf->flags |= LVHT_BELOW;
4540   
4541   if (!pinf->flags)
4542   {
4543     NSPoint pt = NSMakePoint( pinf->pt.x, pinf->pt.y );
4544     pinf->iItem=(int)[(NSTableView *)h rowAtPoint:pt];
4545     if (pinf->iItem >= 0)
4546     {
4547       if (tv->m_status_imagelist && pt.x <= [tv rowHeight])
4548       {
4549         pinf->flags=LVHT_ONITEMSTATEICON;
4550       }
4551       else 
4552       {
4553         pinf->flags=LVHT_ONITEMLABEL;
4554       }
4555     }
4556     else 
4557     {
4558       pinf->flags=LVHT_NOWHERE;
4559     }
4560   }
4561   
4562   return pinf->iItem;
4565 int ListView_SubItemHitTest(HWND h, LVHITTESTINFO *pinf)
4567   int row = ListView_HitTest(h, pinf);
4569   NSPoint pt=NSMakePoint(pinf->pt.x,pinf->pt.y);
4570   if (row < 0 && pt.y < 0)
4571   { // Fake the point in the client area of the listview to get the column # (like win32)
4572     pt.y = 0;
4573   }
4574   pinf->iSubItem=(int)[(NSTableView *)h columnAtPoint:pt];
4575   return row;
4578 void ListView_SetItemCount(HWND h, int cnt)
4580   if (!h) return;
4581   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4582   
4583   SWELL_ListView *tv=(SWELL_ListView*)h;
4584   if (!tv->m_lbMode && (tv->style & LVS_OWNERDATA))
4585   {
4586     tv->ownermode_cnt=cnt;
4587   }
4590 void ListView_EnsureVisible(HWND h, int i, BOOL pok)
4592   if (!h) return;
4593   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4594   
4595   SWELL_ListView *tv=(SWELL_ListView*)h;
4596   
4597   if (i<0)i=0;
4598   if (!tv->m_lbMode && (tv->style & LVS_OWNERDATA))
4599   {
4600     if (i >=tv->ownermode_cnt-1) i=tv->ownermode_cnt-1;
4601   }
4602   else
4603   {
4604     if (tv->m_items && i >= tv->m_items->GetSize()) i=tv->m_items->GetSize()-1;
4605   }
4606   if (i>=0)
4607   {
4608     [tv scrollRowToVisible:i];
4609   }  
4612 static bool ListViewGetRectImpl(HWND h, int item, int subitem, RECT* r) // subitem<0 for full item rect
4614   if (!h) return false;
4615   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
4616   if (item < 0 || item > ListView_GetItemCount(h)) return false;
4617   SWELL_ListView *tv=(SWELL_ListView*)h;
4618   
4619   if (subitem >= 0 && (!tv->m_cols || subitem >= tv->m_cols->GetSize())) return false;
4620   subitem=[tv getColumnPos:subitem];
4621   
4622   NSRect ar;
4623   if (subitem < 0) ar = [tv rectOfRow:item];
4624   else ar=[tv frameOfCellAtColumn:subitem row:item];
4625   NSSize sp=[tv intercellSpacing];
4626   
4627   r->left=(int)ar.origin.x;
4628   r->top=(int)ar.origin.y;
4629   r->right=(int)(ar.origin.x+ar.size.width+sp.width);
4630   r->bottom=(int)(ar.origin.y+ar.size.height+sp.height);
4631   
4632   return true;
4635 bool ListView_GetSubItemRect(HWND h, int item, int subitem, int code, RECT *r)
4637   return ListViewGetRectImpl(h, item, subitem, r);
4640 bool ListView_GetItemRect(HWND h, int item, RECT *r, int code)
4642   return ListViewGetRectImpl(h, item, -1, r);
4645 int ListView_GetTopIndex(HWND h)
4647   NSTableView* tv = (NSTableView*)h;
4648   if (!tv) return -1;
4649   NSScrollView* sv = [tv enclosingScrollView];
4650   if (!sv) return -1;  
4651   
4652   NSPoint pt = { 0, 0 };
4653   NSView *hdr = [tv headerView];
4654   if (hdr && ![hdr isHidden])
4655   {
4656     NSRect fr=[hdr frame];
4657     if (fr.size.height > 0.0) pt.y = fr.origin.y + fr.size.height;
4658   }
4659   pt.y += [sv documentVisibleRect].origin.y;
4660   return (int)[tv rowAtPoint:pt];      
4663 int ListView_GetCountPerPage(HWND h)
4665   NSTableView* tv = (NSTableView*)h;
4666   if (!tv) return 0;
4667   NSScrollView* sv = [tv enclosingScrollView];
4668   if (!sv) return 0;  
4669   
4670   NSRect tvr = [sv documentVisibleRect];
4671   int rowh = [tv rowHeight];
4672   return tvr.size.height/rowh;
4675 bool ListView_Scroll(HWND h, int xscroll, int yscroll)
4677   NSTableView* tv = (NSTableView*)h;
4678   NSScrollView* sv = [tv enclosingScrollView];
4679   if (!sv) return false;
4680   
4681   NSRect tvr = [sv documentVisibleRect];
4682   NSPoint pt = { tvr.origin.x, tvr.origin.y };
4683   if (xscroll > 0) pt.x += tvr.size.width-1;
4684   if (yscroll > 0) pt.y += tvr.size.height-1;
4685   
4686   const NSInteger nr = [tv numberOfRows];
4687   NSInteger rowidx = [tv rowAtPoint:pt];
4688   if (rowidx < 0) rowidx=0;
4689   else if (rowidx >= nr) rowidx=nr-1;
4690   
4691   const NSInteger nc = [tv numberOfColumns];
4692   NSInteger colidx = [tv columnAtPoint:pt];
4693   if (colidx < 0) colidx=0;
4694   else if (colidx >= nc) colidx = nc-1;
4696   // colidx is our column index, not the display order, convert
4697   if ([tv isKindOfClass:[SWELL_ListView class]]) colidx = [(SWELL_ListView*)tv getColumnPos:(int)colidx];
4699   NSRect ir = [tv frameOfCellAtColumn:colidx row:rowidx];
4701   if (yscroll)
4702   {
4703     if (ir.size.height) rowidx += yscroll / ir.size.height;
4705     if (rowidx < 0) rowidx=0;
4706     else if (rowidx >= nr) rowidx = nr-1;
4707     [tv scrollRowToVisible:rowidx];
4708   }
4709   
4710   if (xscroll)
4711   {
4712     if (ir.size.width) colidx += xscroll / ir.size.width;
4713    
4714     if (colidx < 0) colidx=0;
4715     else if (colidx >= nc) colidx = nc-1;
4717     // scrollColumnToVisible takes display order, which we have here
4718     [tv scrollColumnToVisible:colidx];
4719   }
4720   
4721   
4722   return true;
4725 bool ListView_GetScroll(HWND h, POINT* p)
4727   NSTableView* tv = (NSTableView*)h;
4728   NSScrollView* sv = [tv enclosingScrollView];
4729   if (sv)
4730   {
4731     NSRect cr = [sv documentVisibleRect];
4732     p->x = cr.origin.x;
4733     p->y = cr.origin.y;
4734     return true;
4735   }
4736   p->x=p->y=0;
4737   return false;
4740 void ListView_SortItems(HWND hwnd, PFNLVCOMPARE compf, LPARAM parm)
4742   if (!hwnd) return;
4743   if (![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
4744   SWELL_ListView *tv=(SWELL_ListView*)hwnd;
4745   if (tv->m_lbMode || (tv->style & LVS_OWNERDATA) || !tv->m_items) return;
4746     
4747   WDL_HeapBuf tmp;
4748   tmp.Resize(tv->m_items->GetSize()*sizeof(void *));
4749   int x;
4750   int sc=0;
4751   for(x=0;x<tv->m_items->GetSize();x++)
4752   {
4753     SWELL_ListView_Row *r = tv->m_items->Get(x);
4754     if (r) 
4755     {
4756       r->m_tmp = !![tv isRowSelected:x];
4757       sc++;
4758     }
4759   }
4760   __listview_mergesort_internal(tv->m_items->GetList(),tv->m_items->GetSize(),sizeof(void *),compf,parm,(char*)tmp.Get());
4761   if (sc)
4762   {
4763     NSMutableIndexSet *indexSet = [[NSMutableIndexSet  alloc] init];
4764     
4765     for(x=0;x<tv->m_items->GetSize();x++)
4766     {
4767       SWELL_ListView_Row *r = tv->m_items->Get(x);
4768       if (r && (r->m_tmp&1)) [indexSet addIndex:x];
4769     }
4770     [tv selectRowIndexes:indexSet byExtendingSelection:NO];
4771     [indexSet release];
4772   }
4773   
4774   [tv reloadData];
4778 HWND WindowFromPoint(POINT p)
4780   NSArray *windows=[NSApp orderedWindows];
4781   const NSInteger cnt=windows ? [windows count] : 0;
4783   NSWindow *kw = [NSApp keyWindow];
4784   if (kw && windows && [windows containsObject:kw]) kw=NULL;
4786   NSWindow *bestwnd=0;
4787   for (NSInteger x = kw ? -1 : 0; x < cnt; x ++)
4788   {
4789     NSWindow *wnd = kw;
4790     if (x>=0) wnd=[windows objectAtIndex:x];
4791     if (wnd && [wnd isVisible])
4792     {
4793       NSRect fr=[wnd frame];
4794       if (p.x >= fr.origin.x && p.x < fr.origin.x + fr.size.width &&
4795           p.y >= fr.origin.y && p.y < fr.origin.y + fr.size.height)
4796       {
4797         bestwnd=wnd;
4798         break;
4799       }    
4800     }
4801   }
4802   
4803   if (!bestwnd) return 0;
4804   NSPoint pt=NSMakePoint(p.x,p.y);
4805   NSPoint lpt=[bestwnd convertScreenToBase:pt];
4806   NSView *v=[[bestwnd contentView] hitTest:lpt];
4807   if (v) return (HWND)v;
4808   return (HWND)[bestwnd contentView]; 
4811 void UpdateWindow(HWND hwnd)
4813   if (hwnd && [(id)hwnd isKindOfClass:[NSView class]] && [(NSView *)hwnd needsDisplay])
4814   {
4815     NSWindow *wnd = [(NSView *)hwnd window];
4816     [wnd displayIfNeeded];
4817   }
4820 void SWELL_FlushWindow(HWND h)
4822   if (h)
4823   {
4824     NSWindow *w=NULL;
4825     if ([(id)h isKindOfClass:[NSView class]]) 
4826     {
4827       if ([(NSView *)h needsDisplay]) return;
4828       
4829       w = [(NSView *)h window];
4830     }
4831     else if ([(id)h isKindOfClass:[NSWindow class]]) w = (NSWindow *)h;
4832     
4833     if (w && ![w viewsNeedDisplay])
4834     {
4835       [w flushWindow];
4836     }
4837   }
4840 static void InvalidateSuperViews(NSView *view)
4842   if (!view) return;
4843   view = [view superview];
4844   while (view)
4845   {
4846     if ([view isKindOfClass:[SWELL_hwndChild class]]) 
4847     {
4848       if (((SWELL_hwndChild *)view)->m_isdirty&2) break;
4849       ((SWELL_hwndChild *)view)->m_isdirty|=2;
4850     }
4851     view = [view superview];
4852   }
4854            
4855 BOOL InvalidateRect(HWND hwnd, const RECT *r, int eraseBk)
4857   if (!hwnd) return FALSE;
4858   id view=(id)hwnd;
4859   if ([view isKindOfClass:[NSWindow class]]) view=[view contentView];
4860   if ([view isKindOfClass:[NSView class]]) 
4861   {
4863     NSView *sv = view;
4864     
4865     bool skip_parent_invalidate=false;
4866     if ([view isKindOfClass:[SWELL_hwndChild class]])
4867     {
4868       if (!(((SWELL_hwndChild *)view)->m_isdirty&1))
4869       {
4870         ((SWELL_hwndChild *)view)->m_isdirty|=1;
4871       }
4872       else skip_parent_invalidate=true; // if already dirty, then assume parents are already dirty too
4873     }
4874     if (!skip_parent_invalidate)
4875     {
4876       InvalidateSuperViews(view);
4877     }
4878     if (r)
4879     {
4880       RECT tr=*r;
4881       if (tr.top>tr.bottom)
4882       {
4883         int a = tr.top; tr.top=tr.bottom; tr.bottom=a;
4884       }
4885       [sv setNeedsDisplayInRect:NSMakeRect(tr.left,tr.top,tr.right-tr.left,tr.bottom-tr.top)]; 
4886     }
4887     else [sv setNeedsDisplay:YES];
4888     
4889   }
4890   return TRUE;
4893 static HWND m_fakeCapture;
4894 static BOOL m_capChangeNotify;
4895 HWND GetCapture()
4898   return m_fakeCapture;
4901 HWND SetCapture(HWND hwnd)
4903   HWND oc=m_fakeCapture;
4904   int ocn=m_capChangeNotify;
4905   m_fakeCapture=hwnd;
4906   m_capChangeNotify = hwnd && [(id)hwnd respondsToSelector:@selector(swellCapChangeNotify)] && [(SWELL_hwndChild*)hwnd swellCapChangeNotify];
4908   if (ocn && oc && oc != hwnd) SendMessage(oc,WM_CAPTURECHANGED,0,(LPARAM)hwnd);
4909   return oc;
4913 void ReleaseCapture()
4915   HWND h=m_fakeCapture;
4916   m_fakeCapture=NULL;
4917   if (m_capChangeNotify && h)
4918   {
4919     SendMessage(h,WM_CAPTURECHANGED,0,0);
4920   }
4924 HDC BeginPaint(HWND hwnd, PAINTSTRUCT *ps)
4926   if (!ps) return 0;
4927   memset(ps,0,sizeof(PAINTSTRUCT));
4928   if (!hwnd) return 0;
4929   id turd = (id)hwnd;
4930   if (![turd respondsToSelector:@selector(getSwellPaintInfo:)]) return 0;
4932   [(SWELL_hwndChild*)turd getSwellPaintInfo:(PAINTSTRUCT *)ps];
4933   return ps->hdc;
4936 BOOL EndPaint(HWND hwnd, PAINTSTRUCT *ps)
4938   return TRUE;
4941 LRESULT DefWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4943   if (msg==WM_RBUTTONUP||msg==WM_NCRBUTTONUP)
4944   {  
4945     POINT p={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
4946     HWND hwndDest=hwnd;
4947     if (msg==WM_RBUTTONUP)
4948     {
4949       ClientToScreen(hwnd,&p);
4950       HWND h=WindowFromPoint(p);
4951       if (h && IsChild(hwnd,h)) hwndDest=h;
4952     }
4953     SendMessage(hwnd,WM_CONTEXTMENU,(WPARAM)hwndDest,(p.x&0xffff)|(p.y<<16));
4954     return 1;
4955   }
4956   else if (msg==WM_CONTEXTMENU || msg == WM_MOUSEWHEEL || msg == WM_MOUSEHWHEEL || msg == WM_GESTURE)
4957   {
4958     if ([(id)hwnd isKindOfClass:[NSView class]])
4959     {
4960       NSView *h=(NSView *)hwnd;
4961       while (h && [[h window] contentView] != h)
4962       {
4963         h=[h superview];
4964         if (h && [h respondsToSelector:@selector(onSwellMessage:p1:p2:)]) 
4965         {
4966            return SendMessage((HWND)h,msg,wParam,lParam);    
4967         }
4968       }
4969     }
4970   }
4971   else if (msg==WM_NCHITTEST) 
4972   {
4973     int rv=HTCLIENT;
4974     SWELL_BEGIN_TRY
4975     RECT r;
4976     GetWindowRect(hwnd,&r);
4977     POINT pt={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
4979     if (r.top > r.bottom) 
4980     { 
4981       pt.y = r.bottom + (r.top - pt.y); // translate coordinate into flipped-window
4983       int a=r.top; r.top=r.bottom; r.bottom=a; 
4984     }
4985     NCCALCSIZE_PARAMS p={{r,}};
4986     SendMessage(hwnd,WM_NCCALCSIZE,FALSE,(LPARAM)&p);
4987     if (!PtInRect(&p.rgrc[0],pt)) rv=HTNOWHERE;
4988     SWELL_END_TRY(;)
4989     return rv;
4990   }
4991   else if (msg==WM_KEYDOWN || msg==WM_KEYUP) return 69;
4992   else if (msg == WM_DISPLAYCHANGE)
4993   {
4994     if ([(id)hwnd isKindOfClass:[NSView class]])
4995     {
4996       NSArray *ch = [(NSView *)hwnd subviews];
4997       if (ch)
4998       {
4999         int x;
5000         for(x=0;x<[ch count]; x ++)
5001         {
5002           NSView *v = [ch objectAtIndex:x];
5003           sendSwellMessage(v,WM_DISPLAYCHANGE,wParam,lParam);
5004         }
5005         if (x)
5006         {
5007           void SWELL_DoDialogColorUpdates(HWND hwnd, DLGPROC d, bool isUpdate);
5008           DLGPROC d = (DLGPROC)GetWindowLong(hwnd,DWL_DLGPROC);
5009           if (d) SWELL_DoDialogColorUpdates(hwnd,d,true);
5010         }
5011       }
5012     }
5013   }
5014   return 0;
5017 void SWELL_BroadcastMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
5019   int x;
5020   NSArray *ch=[NSApp orderedWindows];
5021   for(x=0;x<[ch count]; x ++)
5022   {
5023     NSView *v = [[ch objectAtIndex:x] contentView];
5024     if (v && [v respondsToSelector:@selector(onSwellMessage:p1:p2:)])
5025     {
5026       [(SWELL_hwndChild *)v onSwellMessage:uMsg p1:wParam p2:lParam];
5027       
5028       if (uMsg == WM_DISPLAYCHANGE)
5029         InvalidateRect((HWND)v,NULL,FALSE);
5030     }
5031   }  
5047 ///////////////// clipboard compatability (NOT THREAD SAFE CURRENTLY)
5050 BOOL DragQueryPoint(HDROP hDrop,LPPOINT pt)
5052   if (!hDrop) return 0;
5053   DROPFILES *df=(DROPFILES*)GlobalLock(hDrop);
5054   BOOL rv=!df->fNC;
5055   *pt=df->pt;
5056   GlobalUnlock(hDrop);
5057   return rv;
5060 void DragFinish(HDROP hDrop)
5062 //do nothing for now (caller will free hdrops)
5065 UINT DragQueryFile(HDROP hDrop, UINT wf, char *buf, UINT bufsz)
5067   if (!hDrop) return 0;
5068   DROPFILES *df=(DROPFILES*)GlobalLock(hDrop);
5070   size_t rv=0;
5071   char *p=(char*)df + df->pFiles;
5072   if (wf == 0xFFFFFFFF)
5073   {
5074     while (*p)
5075     {
5076       rv++;
5077       p+=strlen(p)+1;
5078     }
5079   }
5080   else
5081   {
5082     while (*p)
5083     {
5084       if (!wf--)
5085       {
5086         if (buf)
5087         {
5088           lstrcpyn_safe(buf,p,bufsz);
5089           rv=strlen(buf);
5090         }
5091         else rv=strlen(p);
5092           
5093         break;
5094       }
5095       p+=strlen(p)+1;
5096     }
5097   }
5098   GlobalUnlock(hDrop);
5099   return (UINT)rv;
5112 static WDL_PtrList<void> m_clip_recs;
5113 static WDL_PtrList<NSString> m_clip_fmts;
5114 static WDL_PtrList<char> m_clip_curfmts;
5115 struct swell_pendingClipboardStates
5117   UINT type;
5118   HANDLE h;
5119   swell_pendingClipboardStates(UINT _type, HANDLE _h)
5120   {
5121     type = _type;
5122     h = _h;
5123   }
5124   ~swell_pendingClipboardStates()
5125   {
5126     GlobalFree(h);
5127   }
5130 static WDL_PtrList<swell_pendingClipboardStates> m_clipsPending;
5132 bool OpenClipboard(HWND hwndDlg)
5134   m_clipsPending.Empty(true);
5136   CF_TEXT; // ensure this type is registered
5137   
5138   NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:@"SWELL_APP"];
5139   m_clip_curfmts.Empty();
5140   NSArray *ar=[pasteboard types];
5142   
5143   if (ar && [ar count])
5144   {
5145     int x;
5146     
5147     for (x = 0; x < [ar count]; x ++)
5148     {
5149       NSString *s=[ar objectAtIndex:x];
5150       if (!s) continue;
5151       int y;
5152       for (y = 0; y < m_clip_fmts.GetSize(); y ++)
5153       {
5154         if ([s compare:(NSString *)m_clip_fmts.Get(y)]==NSOrderedSame)
5155         {
5156           if (m_clip_curfmts.Find((char*)(INT_PTR)(y+1))<0)
5157             m_clip_curfmts.Add((char*)(INT_PTR)(y+1));
5158           break;
5159         }
5160       }
5161       
5162     }
5163   }
5164   return true;
5167 void CloseClipboard() // frees any remaining items in clipboard
5169   m_clip_recs.Empty(GlobalFree);
5170   
5171   if (m_clipsPending.GetSize())
5172   {
5173     int x;
5174     for (x=0;x<m_clipsPending.GetSize() && m_clipsPending.Get(x)->type != CF_TEXT;x++);
5175     NSPasteboard *pasteboard = x<m_clipsPending.GetSize() ? [NSPasteboard generalPasteboard] : [NSPasteboard pasteboardWithName:@"SWELL_APP"];
5176     
5177     NSMutableArray *ar = [[NSMutableArray alloc] initWithCapacity:m_clipsPending.GetSize()];
5178     
5179     for (x=0;x<m_clipsPending.GetSize();x++)
5180     {
5181       swell_pendingClipboardStates *cs=m_clipsPending.Get(x);
5182       NSString *fmt=m_clip_fmts.Get(cs->type-1);
5183       if (fmt) [ar addObject:fmt];
5184     }
5185     if ([ar count])
5186     {
5187       [pasteboard declareTypes:ar owner:nil];
5188       for (x=0;x<m_clipsPending.GetSize();x++)
5189       {
5190         swell_pendingClipboardStates *cs=m_clipsPending.Get(x);
5191         NSString *fmt=m_clip_fmts.Get(cs->type-1);
5192         if (!fmt) continue;
5193         
5194         void *buf=GlobalLock(cs->h);
5195         if (buf)
5196         {
5197           int bufsz=GlobalSize(cs->h);
5198           if (cs->type == CF_TEXT)
5199           {
5200             char *t = (char *)malloc(bufsz+1);
5201             if (t)
5202             {
5203               memcpy(t,buf,bufsz);
5204               t[bufsz]=0;
5205               NSString *s = (NSString*)SWELL_CStringToCFString(t);
5206               [pasteboard setString:s forType:fmt];
5207               [s release];
5208               free(t);
5209             }
5210           }
5211           else
5212           {
5213             NSData *data=[NSData dataWithBytes:buf length:bufsz];
5214             [pasteboard setData:data forType:fmt];
5215           }
5216           GlobalUnlock(cs->h);
5217         }
5218       }
5219     }
5220     [ar release];
5221     m_clipsPending.Empty(true);
5222   }  
5225 UINT EnumClipboardFormats(UINT lastfmt) // won't enumerate CF_TEXT (since thats a separate pasteboard)
5227   if (!m_clip_curfmts.GetSize()) return 0;
5228   if (lastfmt == 0) return (UINT)(INT_PTR)m_clip_curfmts.Get(0);
5229   int x;
5230   for (x = m_clip_curfmts.GetSize()-2; x >= 0; x--) // scan backwards to avoid dupes causing infinite loops
5231   {
5232     if ((UINT)(INT_PTR)m_clip_curfmts.Get(x) == lastfmt)
5233       return (UINT)(INT_PTR)m_clip_curfmts.Get(x+1);
5234   }
5235   return 0;
5238 HANDLE GetClipboardData(UINT type)
5240   NSString *fmt=m_clip_fmts.Get(type-1);
5241   if (!fmt) return 0;
5242   NSPasteboard *pasteboard = type == CF_TEXT ? [NSPasteboard generalPasteboard] : [NSPasteboard pasteboardWithName:@"SWELL_APP"];
5243   
5244   HANDLE h=0;
5245   if (type == CF_TEXT)
5246   {
5247     [pasteboard types];
5248     NSString *str = [pasteboard stringForType:fmt];
5249     if (str)
5250     {
5251       int l = (int) ([str length]*4 + 32);
5252       char *buf = (char *)malloc(l);
5253       if (!buf) return 0;
5254       SWELL_CFStringToCString(str,buf,l);
5255       buf[l-1]=0;
5256       l = (int) (strlen(buf)+1);
5257       h=GlobalAlloc(0,l);  
5258       memcpy(GlobalLock(h),buf,l);
5259       GlobalUnlock(h);
5260       free(buf);
5261     }
5262   }
5263   else
5264   {
5265     
5266     NSData *data=[pasteboard dataForType:fmt];
5267     if (!data) return 0; 
5268     int l = (int)[data length];
5269     h=GlobalAlloc(0,l);  
5270     if (h) memcpy(GlobalLock(h),[data bytes],l);
5271     GlobalUnlock(h);
5272   }
5273   
5274   if (h) m_clip_recs.Add(h);
5275         return h;
5278 void EmptyClipboard()
5280   m_clipsPending.Empty(true);
5284 void SetClipboardData(UINT type, HANDLE h)
5286   m_clipsPending.Add(new swell_pendingClipboardStates(type,h));    
5289 UINT RegisterClipboardFormat(const char *desc)
5291   NSString *s=NULL;
5292   if (!strcmp(desc,"SWELL__CF_TEXT")) 
5293   {
5294     s=NSStringPboardType;
5295     [s retain];
5296   }
5297   if (!s) s=(NSString*)SWELL_CStringToCFString(desc);
5298   int x;
5299   for (x = 0; x < m_clip_fmts.GetSize(); x ++)
5300   {
5301     NSString *ts=m_clip_fmts.Get(x);
5302     if ([ts compare:s]==NSOrderedSame)
5303     {
5304       [s release];
5305       return x+1;
5306     }
5307   }
5308   m_clip_fmts.Add(s);
5309   return m_clip_fmts.GetSize();
5312 int EnumPropsEx(HWND hwnd, PROPENUMPROCEX proc, LPARAM lParam)
5314   if (!hwnd || ![(id)hwnd respondsToSelector:@selector(swellEnumProps:lp:)]) return -1;
5315   return (int)[(SWELL_hwndChild *)hwnd swellEnumProps:proc lp:lParam];
5318 HANDLE GetProp(HWND hwnd, const char *name)
5320   if (!hwnd || ![(id)hwnd respondsToSelector:@selector(swellGetProp:wantRemove:)]) return NULL;
5321   return (HANDLE)[(SWELL_hwndChild *)hwnd swellGetProp:name wantRemove:NO];
5324 BOOL SetProp(HWND hwnd, const char *name, HANDLE val)
5326   if (!hwnd || ![(id)hwnd respondsToSelector:@selector(swellSetProp:value:)]) return FALSE;
5327   return (BOOL)!![(SWELL_hwndChild *)hwnd swellSetProp:name value:val];
5330 HANDLE RemoveProp(HWND hwnd, const char *name)
5332   if (!hwnd || ![(id)hwnd respondsToSelector:@selector(swellGetProp:wantRemove:)]) return NULL;
5333   return (HANDLE)[(SWELL_hwndChild *)hwnd swellGetProp:name wantRemove:YES];
5337 int GetSystemMetrics(int p)
5339 switch (p)
5341 case SM_CXSCREEN:
5342 case SM_CYSCREEN:
5344   NSScreen *s=[NSScreen mainScreen];
5345   if (!s) return 1024;
5346   return p==SM_CXSCREEN ? [s frame].size.width : [s frame].size.height;
5348 case SM_CXHSCROLL: return 16;
5349 case SM_CYHSCROLL: return 16;
5350 case SM_CXVSCROLL: return 16;
5351 case SM_CYVSCROLL: return 16;
5353 return 0;
5356 BOOL ScrollWindow(HWND hwnd, int xamt, int yamt, const RECT *lpRect, const RECT *lpClipRect)
5358   if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]]) hwnd=(HWND)[(id)hwnd contentView];
5359   if (!hwnd || ![(id)hwnd isKindOfClass:[NSView class]]) return FALSE;
5361   if (!xamt && !yamt) return FALSE;
5362   
5363   // move child windows only
5364   if (1)
5365   {
5366     if (xamt || yamt)
5367     {
5368       NSArray *ar=[(NSView*)hwnd subviews];
5369       NSInteger i,c=[ar count];
5370       for(i=0;i<c;i++)
5371       {
5372         NSView *v=(NSView *)[ar objectAtIndex:i];
5373         NSRect r=[v frame];
5374         r.origin.x+=xamt;
5375         r.origin.y+=yamt;
5376         [v setFrame:r];
5377       }
5378     }
5379     [(id)hwnd setNeedsDisplay:YES];
5380   }
5381   else
5382   {
5383     NSRect r=[(NSView*)hwnd bounds];
5384     r.origin.x -= xamt;
5385     r.origin.y -= yamt;
5386     [(id)hwnd setBoundsOrigin:r.origin];
5387     [(id)hwnd setNeedsDisplay:YES];
5388   }
5389   return TRUE;
5392 HWND FindWindowEx(HWND par, HWND lastw, const char *classname, const char *title)
5394   // note: this currently is far far far from fully functional, bleh
5395   if (!par)
5396   {
5397     if (!title) return NULL;
5399     // get a list of top level windows, find any that match
5400     // (this does not scan child windows, which is a todo really)
5401     HWND rv=NULL;
5402     NSArray *ch=[NSApp windows];
5403     NSInteger x=0,n=[ch count];
5404     if (lastw)
5405     {
5406       for(;x<n; x ++)
5407       {
5408         NSWindow *w = [ch objectAtIndex:x]; 
5409         if ((HWND)w == lastw || (HWND)[w contentView] == lastw) break;
5410       }
5411       x++;
5412     }
5414     NSString *srch=(NSString*)SWELL_CStringToCFString(title);
5415     for(;x<n && !rv; x ++)
5416     {
5417       NSWindow *w = [ch objectAtIndex:x]; 
5418       if ([[w title] isEqualToString:srch]) rv=(HWND)[w contentView];
5419     }
5420     [srch release]; 
5422     return rv;
5423   }
5424   HWND h=lastw?GetWindow(lastw,GW_HWNDNEXT):GetWindow(par,GW_CHILD);
5425   while (h)
5426   {
5427     bool isOk=true;
5428     if (title)
5429     {
5430       char buf[512];
5431       buf[0]=0;
5432       GetWindowText(h,buf,sizeof(buf));
5433       if (strcmp(title,buf)) isOk=false;
5434     }
5435     if (classname)
5436     {
5437       if (!stricmp(classname,"Static") && ![(id)h isKindOfClass:[NSTextField class]]) isOk=false;
5438       // todo: other classname translations
5439     }
5440     
5441     if (isOk) return h;
5442     h=GetWindow(h,GW_HWNDNEXT);
5443   }
5444   return h;
5447 BOOL TreeView_SetIndent(HWND hwnd, int indent)
5449   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return 0;
5450   SWELL_TreeView* tv = (SWELL_TreeView*)hwnd;  
5451   [tv setIndentationPerLevel:(float)indent];  
5452   return TRUE;
5455 HTREEITEM TreeView_InsertItem(HWND hwnd, TV_INSERTSTRUCT *ins)
5457   if (!hwnd || !ins) return 0;
5458   if (![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return 0;
5459   
5460   SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5462   HTREEITEM__ *par=NULL;
5463   int inspos=0;
5464   
5465   if (ins->hParent && ins->hParent != TVI_ROOT && ins->hParent != TVI_FIRST && ins->hParent != TVI_LAST && ins->hParent != TVI_SORT)
5466   {
5467     if ([tv findItem:ins->hParent parOut:&par idxOut:&inspos])
5468     {
5469       par = (HTREEITEM__ *)ins->hParent; 
5470     }
5471     else return 0;
5472   }
5473   
5474   if (ins->hInsertAfter == TVI_FIRST) inspos=0;
5475   else if (ins->hInsertAfter == TVI_LAST || ins->hInsertAfter == TVI_SORT || !ins->hInsertAfter) inspos=par ? par->m_children.GetSize() : tv->m_items ? tv->m_items->GetSize() : 0;
5476   else inspos = par ? par->m_children.Find((HTREEITEM__*)ins->hInsertAfter)+1 : tv->m_items ? tv->m_items->Find((HTREEITEM__*)ins->hInsertAfter)+1 : 0;      
5477   
5478   HTREEITEM__ *item=new HTREEITEM__;
5479   if (ins->item.mask & TVIF_CHILDREN)
5480     item->m_haschildren = !!ins->item.cChildren;
5481   if (ins->item.mask & TVIF_PARAM) item->m_param = ins->item.lParam;
5482   if (ins->item.mask & TVIF_TEXT) item->m_value = strdup(ins->item.pszText);
5483   if (!par)
5484   {
5485     if (!tv->m_items) tv->m_items = new WDL_PtrList<HTREEITEM__>;
5486     tv->m_items->Insert(inspos,item);
5487   }
5488   else par->m_children.Insert(inspos,item);
5489   
5490   [tv reloadData];
5491   return (HTREEITEM) item;
5494 BOOL TreeView_Expand(HWND hwnd, HTREEITEM item, UINT flag)
5496   if (!hwnd || !item) return false;
5497   
5498   if (![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return false;
5499   
5500   SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5501   
5502   id itemid=((HTREEITEM__*)item)->m_dh;
5503   bool isExp=!![tv isItemExpanded:itemid];
5504   
5505   if (flag == TVE_EXPAND && !isExp) [tv expandItem:itemid];
5506   else if (flag == TVE_COLLAPSE && isExp) [tv collapseItem:itemid];
5507   else if (flag==TVE_TOGGLE) 
5508   {
5509     if (isExp) [tv collapseItem:itemid];
5510     else [tv expandItem:itemid];
5511   }
5512   else return FALSE;
5514   return TRUE;
5515   
5518 HTREEITEM TreeView_GetSelection(HWND hwnd)
5520   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return NULL;
5521   
5522   SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5523   NSInteger idx=[tv selectedRow];
5524   if (idx<0) return NULL;
5525   
5526   SWELL_DataHold *t=[tv itemAtRow:idx];
5527   if (t) return (HTREEITEM)[t getValue];
5528   return NULL;
5529   
5532 void TreeView_DeleteItem(HWND hwnd, HTREEITEM item)
5534   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5535   SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5536   
5537   HTREEITEM__ *par=NULL;
5538   int idx=0;
5539   
5540   if ([tv findItem:item parOut:&par idxOut:&idx])
5541   {
5542     if (par)
5543     {
5544       par->m_children.Delete(idx,true);
5545     }
5546     else if (tv->m_items)
5547     {
5548       tv->m_items->Delete(idx,true);
5549     }
5550     [tv reloadData];
5551   }
5554 void TreeView_DeleteAllItems(HWND hwnd)
5556   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5557   SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5558   
5559   if (tv->m_items) tv->m_items->Empty(true);
5560   [tv reloadData];
5563 void TreeView_SelectItem(HWND hwnd, HTREEITEM item)
5565   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5566   
5567   NSInteger row=[(SWELL_TreeView*)hwnd rowForItem:((HTREEITEM__*)item)->m_dh];
5568   if (row>=0)
5569     [(SWELL_TreeView*)hwnd selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];            
5570   static int __rent;
5571   if (!__rent)
5572   {
5573     __rent=1;
5574     NMTREEVIEW nm={{(HWND)hwnd,(UINT_PTR)[(SWELL_TreeView*)hwnd tag],TVN_SELCHANGED},};
5575     SendMessage(GetParent(hwnd),WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
5576     __rent=0;
5577   }
5580 BOOL TreeView_GetItem(HWND hwnd, LPTVITEM pitem)
5582   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]] || !pitem || !(pitem->mask & TVIF_HANDLE) || !(pitem->hItem)) return FALSE;
5583   
5584   HTREEITEM__ *ti = (HTREEITEM__*)pitem->hItem;
5585   pitem->cChildren = ti->m_haschildren ? 1:0;
5586   pitem->lParam = ti->m_param;
5587   if ((pitem->mask&TVIF_TEXT)&&pitem->pszText&&pitem->cchTextMax>0)
5588   {
5589     lstrcpyn_safe(pitem->pszText,ti->m_value?ti->m_value:"",pitem->cchTextMax);
5590   }
5591   pitem->state=0;
5592   
5593   
5594   NSInteger itemRow = [(SWELL_TreeView*)hwnd rowForItem:ti->m_dh];
5595   if (itemRow >= 0 && [(SWELL_TreeView*)hwnd isRowSelected:itemRow])
5596     pitem->state |= TVIS_SELECTED;   
5597   if ([(SWELL_TreeView*)hwnd isItemExpanded:ti->m_dh])
5598     pitem->state |= TVIS_EXPANDED;   
5599   
5600   return TRUE;
5603 BOOL TreeView_SetItem(HWND hwnd, LPTVITEM pitem)
5605   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]] || !pitem || !(pitem->mask & TVIF_HANDLE) || !(pitem->hItem)) return FALSE;
5606   
5607   HTREEITEM__ *par=NULL;
5608   int idx=0;
5609   
5610   if (![(SWELL_TreeView*)hwnd findItem:pitem->hItem parOut:&par idxOut:&idx]) return FALSE;
5611   
5612   HTREEITEM__ *ti = (HTREEITEM__*)pitem->hItem;
5613   
5614   if (pitem->mask & TVIF_CHILDREN) ti->m_haschildren = pitem->cChildren?1:0;
5615   if (pitem->mask & TVIF_PARAM)  ti->m_param =  pitem->lParam;
5616   
5617   if ((pitem->mask&TVIF_TEXT)&&pitem->pszText)
5618   {
5619     free(ti->m_value);
5620     ti->m_value=strdup(pitem->pszText);
5621     InvalidateRect(hwnd, 0, FALSE);
5622   }
5624   if (pitem->stateMask & TVIS_SELECTED)
5625   {
5626     NSInteger itemRow = [(SWELL_TreeView*)hwnd rowForItem:ti->m_dh];
5627     if (itemRow >= 0)
5628     {
5629       if (pitem->state&TVIS_SELECTED)
5630       {
5631         [(SWELL_TreeView*)hwnd selectRowIndexes:[NSIndexSet indexSetWithIndex:itemRow] byExtendingSelection:NO];
5632         
5633         static int __rent;
5634         if (!__rent)
5635         {
5636           __rent=1;
5637           NMTREEVIEW nm={{(HWND)hwnd,(UINT_PTR)[(SWELL_TreeView*)hwnd tag],TVN_SELCHANGED},};
5638           SendMessage(GetParent(hwnd),WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
5639           __rent=0;
5640         }
5641         
5642       }
5643       else
5644       {
5645         // todo figure out unselect?!
5646 //         [(SWELL_TreeView*)hwnd selectRowIndexes:[NSIndexSet indexSetWithIndex:itemRow] byExtendingSelection:NO];
5647       }
5648     }
5649   }
5650   
5651   if (pitem->stateMask & TVIS_EXPANDED)
5652     TreeView_Expand(hwnd,pitem->hItem,(pitem->state&TVIS_EXPANDED)?TVE_EXPAND:TVE_COLLAPSE);
5653     
5654   
5655   return TRUE;
5658 HTREEITEM TreeView_HitTest(HWND hwnd, TVHITTESTINFO *hti)
5660   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]] || !hti) return NULL;
5661   SWELL_TreeView* tv = (SWELL_TreeView*)hwnd;
5662   int x = hti->pt.x;
5663   int y = hti->pt.y;
5664   
5665   int i; 
5666   for (i = 0; i < [tv numberOfRows]; ++i)
5667   {
5668     NSRect r = [tv rectOfRow:i];
5669     if (x >= r.origin.x && x < r.origin.x+r.size.width && y >= r.origin.y && y < r.origin.y+r.size.height)
5670     {
5671       SWELL_DataHold* t = [tv itemAtRow:i];
5672       if (t) return (HTREEITEM)[t getValue];
5673       return 0;
5674     }
5675   }
5676   
5677   return NULL; // not hit
5680 HTREEITEM TreeView_GetRoot(HWND hwnd)
5682   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return NULL;
5683   SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5684   
5685   if (!tv->m_items) return 0;
5686   return (HTREEITEM) tv->m_items->Get(0);
5689 HTREEITEM TreeView_GetChild(HWND hwnd, HTREEITEM item)
5691   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return NULL;
5693   HTREEITEM__ *titem=(HTREEITEM__ *)item;
5694   if (!titem) return TreeView_GetRoot(hwnd);
5695   
5696   return (HTREEITEM) titem->m_children.Get(0);
5698 HTREEITEM TreeView_GetNextSibling(HWND hwnd, HTREEITEM item)
5700   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return NULL;
5701   SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5703   if (!item) return TreeView_GetRoot(hwnd);
5704   
5705   HTREEITEM__ *par=NULL;
5706   int idx=0;  
5707   if ([tv findItem:item parOut:&par idxOut:&idx])
5708   {
5709     if (par)
5710     {
5711       return par->m_children.Get(idx+1);
5712     }    
5713     if (tv->m_items) return tv->m_items->Get(idx+1);
5714   }
5715   return 0;
5718 void TreeView_SetBkColor(HWND hwnd, int color)
5720   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5721   [(NSOutlineView*)hwnd setBackgroundColor:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f 
5722               green:GetGValue(color)/255.0f 
5723               blue:GetBValue(color)/255.0f alpha:1.0f]];
5725 void TreeView_SetTextColor(HWND hwnd, int color)
5727   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5729   SWELL_TreeView *f = (SWELL_TreeView *)hwnd;
5730   [f->m_fgColor release];
5731   f->m_fgColor = [NSColor colorWithCalibratedRed:GetRValue(color)/255.0f 
5732               green:GetGValue(color)/255.0f 
5733               blue:GetBValue(color)/255.0f alpha:1.0f];
5734   [f->m_fgColor retain];
5736 void ListView_SetBkColor(HWND hwnd, int color)
5738   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
5739   [(NSTableView*)hwnd setBackgroundColor:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f 
5740               green:GetGValue(color)/255.0f 
5741               blue:GetBValue(color)/255.0f alpha:1.0f]];
5744 void ListView_SetSelColors(HWND hwnd, int *colors, int ncolors) // this works for SWELL_ListView as well as SWELL_TreeView
5746   if (!hwnd) return;
5747   NSMutableArray *ar=[[NSMutableArray alloc] initWithCapacity:ncolors];
5748   
5749   while (ncolors-->0)
5750   {
5751     const int color = colors ? *colors++ : 0;
5752     [ar addObject:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f
5753                                               green:GetGValue(color)/255.0f 
5754                                                blue:GetBValue(color)/255.0f alpha:1.0f]]; 
5755   }
5757   if ([(id)hwnd isKindOfClass:[SWELL_ListView class]]) 
5758   {
5759     SWELL_ListView *lv = (SWELL_ListView*)hwnd;
5760     [lv->m_selColors release];
5761     lv->m_selColors=ar;
5762   }
5763   else if ([(id)hwnd isKindOfClass:[SWELL_TreeView class]]) 
5764   {
5765     SWELL_TreeView *lv = (SWELL_TreeView*)hwnd;
5766     [lv->m_selColors release];
5767     lv->m_selColors=ar;
5768   }
5769   else 
5770   {
5771     [ar release];
5772   }
5774 void ListView_SetGridColor(HWND hwnd, int color)
5776   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
5777   [(NSTableView*)hwnd setGridColor:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f 
5778               green:GetGValue(color)/255.0f 
5779               blue:GetBValue(color)/255.0f alpha:1.0f]];
5781 void ListView_SetTextBkColor(HWND hwnd, int color)
5783   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
5784   // not implemented atm
5786 void ListView_SetTextColor(HWND hwnd, int color)
5788   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
5790   SWELL_ListView *f = (SWELL_ListView *)hwnd;
5791   [f->m_fgColor release];
5792   f->m_fgColor = [NSColor colorWithCalibratedRed:GetRValue(color)/255.0f 
5793               green:GetGValue(color)/255.0f 
5794               blue:GetBValue(color)/255.0f alpha:1.0f];
5795   [f->m_fgColor retain];
5799 BOOL ShellExecute(HWND hwndDlg, const char *action,  const char *content1, const char *content2, const char *content3, int blah)
5801   if (content1 && !strnicmp(content1,"http://",7))
5802   {
5803      NSWorkspace *wk = [NSWorkspace sharedWorkspace];
5804      if (!wk) return FALSE;
5805      NSString *fnstr=(NSString *)SWELL_CStringToCFString(content1);
5806      BOOL ret=[wk openURL:[NSURL URLWithString:fnstr]];
5807      [fnstr release];
5808      return ret;
5809   }
5810   
5811   if (content1 && !stricmp(content1,"explorer.exe")) content1="";
5812   else if (content1 && (!stricmp(content1,"notepad.exe")||!stricmp(content1,"notepad"))) content1="TextEdit.app";
5813   
5814   if (content2 && !stricmp(content2,"explorer.exe")) content2="";
5816   if (content1 && content2 && *content1 && *content2)
5817   {
5818       NSWorkspace *wk = [NSWorkspace sharedWorkspace];
5819       if (!wk) return FALSE;
5820       NSString *appstr=(NSString *)SWELL_CStringToCFString(content1);
5821       NSString *fnstr=(NSString *)SWELL_CStringToCFString(content2);
5822       BOOL ret=[wk openFile:fnstr withApplication:appstr andDeactivate:YES];
5823       [fnstr release];
5824       [appstr release];
5825       return ret;
5826   }
5827   else if ((content1&&*content1) || (content2&&*content2))
5828   {
5829       const char *fn = (content1 && *content1) ? content1 : content2;
5830       NSWorkspace *wk = [NSWorkspace sharedWorkspace];
5831       if (!wk) return FALSE;
5832       NSString *fnstr = nil;
5833       BOOL ret = FALSE;
5834     
5835       if (fn && !strnicmp(fn, "/select,\"", 9))
5836       {
5837         char* tmp = strdup(fn+9);
5838         if (*tmp && tmp[strlen(tmp)-1]=='\"') tmp[strlen(tmp)-1]='\0';
5839         if (*tmp)
5840         {
5841           if ([wk respondsToSelector:@selector(activateFileViewerSelectingURLs:)]) // 10.6+
5842           {
5843             fnstr=(NSString *)SWELL_CStringToCFString(tmp);
5844             NSURL *url = [NSURL fileURLWithPath:fnstr isDirectory:false];
5845             if (url)
5846             {
5847               [wk activateFileViewerSelectingURLs:[NSArray arrayWithObjects:url, nil]]; // NSArray (and NSURL) autoreleased
5848               ret=TRUE;
5849             }
5850           }
5851           else
5852           {
5853             if (WDL_remove_filepart(tmp))
5854             {
5855               fnstr=(NSString *)SWELL_CStringToCFString(tmp);
5856               ret=[wk openFile:fnstr];
5857             }
5858           }
5859         }
5860         free(tmp);
5861       }
5862       else if (strlen(fn)>4 && !stricmp(fn+strlen(fn)-4,".app"))
5863       {
5864         fnstr=(NSString *)SWELL_CStringToCFString(fn);
5865         ret=[wk launchApplication:fnstr];
5866       }
5867       else
5868       {
5869         fnstr=(NSString *)SWELL_CStringToCFString(fn);
5870         ret=[wk openFile:fnstr];
5871       }
5872       [fnstr release];
5873       return ret;
5874   }
5875   return FALSE;
5881 @implementation SWELL_FocusRectWnd
5883 -(BOOL)isOpaque { return YES; }
5884 -(void) drawRect:(NSRect)rect
5886   NSColor *col=[NSColor colorWithCalibratedRed:0.5 green:0.5 blue:0.5 alpha:1.0];
5887   [col set];
5888   
5889   CGRect r = CGRectMake(rect.origin.x,rect.origin.y,rect.size.width,rect.size.height);
5890   
5891   CGContextRef ctx = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
5892   
5893   CGContextFillRect(ctx,r);              
5894   
5896 @end
5898 // r=NULL to "free" handle
5899 // otherwise r is in hwndPar coordinates
5900 void SWELL_DrawFocusRect(HWND hwndPar, RECT *rct, void **handle)
5902   if (!handle) return;
5903   NSWindow *wnd = (NSWindow *)*handle;
5904   
5905   if (!rct)
5906   {
5907     if (wnd)
5908     {
5909       NSWindow *ow=[wnd parentWindow];
5910       if (ow) [ow removeChildWindow:wnd];
5911 //      [wnd setParentWindow:nil];
5912       [wnd close];
5913       *handle=0;
5914     }
5915   }
5916   else 
5917   {
5918     RECT r=*rct;
5919     if (hwndPar)
5920     {
5921       ClientToScreen(hwndPar,((LPPOINT)&r));
5922       ClientToScreen(hwndPar,((LPPOINT)&r)+1);
5923     }
5924     else
5925     {
5926       // todo: flip?
5927     }
5928     if (r.top>r.bottom) { int a=r.top; r.top=r.bottom;r.bottom=a; }
5929     NSRect rr=NSMakeRect(r.left,r.top,r.right-r.left,r.bottom-r.top);
5930     
5931     NSWindow *par=nil;
5932     if (hwndPar)
5933     {
5934       if ([(id)hwndPar isKindOfClass:[NSWindow class]]) par=(NSWindow *)hwndPar;
5935       else if ([(id)hwndPar isKindOfClass:[NSView class]]) par=[(NSView *)hwndPar window];
5936       else return;
5937     }
5938     
5939     if (wnd && ([wnd parentWindow] != par))
5940     {
5941       NSWindow *ow=[wnd parentWindow];
5942       if (ow) [ow removeChildWindow:wnd];
5943       //      [wnd setParentWindow:nil];
5944       [wnd close];
5945       *handle=0;
5946       wnd=0;    
5947     }
5948     
5949     if (!wnd)
5950     {
5951       *handle  = wnd = [[NSWindow alloc] initWithContentRect:rr styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
5952       [wnd setOpaque:YES];
5953       [wnd setAlphaValue:0.5];
5954       [wnd setExcludedFromWindowsMenu:YES];
5955       [wnd setIgnoresMouseEvents:YES];
5956       [wnd setContentView:[[SWELL_FocusRectWnd alloc] init]];
5957       
5958       if (par) [par addChildWindow:wnd ordered:NSWindowAbove];
5959       else 
5960       {
5961         [wnd setLevel:NSPopUpMenuWindowLevel];
5962         [wnd orderFront:wnd];
5963       }
5964       //    [wnd setParentWindow:par];
5965 //      [wnd orderWindow:NSWindowAbove relativeTo:[par windowNumber]];
5966     }
5967     
5968     [wnd setFrame:rr display:YES];    
5969   }
5973 @implementation SWELL_PopUpButton
5974 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
5976 -(void)setSwellStyle:(LONG)style { m_style=style; }
5977 -(LONG)getSwellStyle { return m_style; }
5978 @end
5980 @implementation SWELL_ComboBox
5981 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
5983 -(void)setSwellStyle:(LONG)style { m_style=style; }
5984 -(LONG)getSwellStyle { return m_style; }
5985 -(id)init { self = [super init]; if (self) { m_ids=new WDL_PtrList<char>; }  return self; }
5986 -(void)dealloc { delete m_ids; [super dealloc];  }
5987 - (BOOL)becomeFirstResponder;
5989   BOOL didBecomeFirstResponder = [super becomeFirstResponder];
5990   if (didBecomeFirstResponder) SendMessage(GetParent((HWND)self),WM_COMMAND,[self tag]|(EN_SETFOCUS<<16),(LPARAM)self);
5991   return didBecomeFirstResponder;
5993 @end
5998 bool SWELL_HandleMouseEvent(NSEvent *evt)
6000   NSEventType etype = [evt type];
6001   if (GetCapture()) return false;
6002   if (etype >= NSLeftMouseDown && etype <= NSRightMouseDragged)
6003   {
6004   }
6005   else return false;
6006   
6007   NSWindow *w = [evt window];
6008   if (w)
6009   {
6010     NSView *cview = [w contentView];
6011     NSView *besthit=NULL;
6012     if (cview)
6013     {
6014       NSPoint lpt = [evt locationInWindow];    
6015       NSView *hitv=[cview hitTest:lpt];
6016       lpt = [w convertBaseToScreen:lpt];
6017       
6018       int xpos=(int)floor(lpt.x);
6019       int ypos=(int)floor(lpt.y);
6020       
6021       while (hitv)
6022       {
6023         int ht=(int)sendSwellMessage(hitv,WM_NCHITTEST,0,MAKELPARAM(xpos,ypos));
6024         if (ht && ht != HTCLIENT) besthit=hitv;
6026         if (hitv==cview) break;
6027         hitv = [hitv superview];
6028       }
6029     }
6030     if (besthit)
6031     {
6032       if (etype == NSLeftMouseDown) [besthit mouseDown:evt];
6033       else if (etype == NSLeftMouseUp) [besthit mouseUp:evt];
6034       else if (etype == NSLeftMouseDragged) [besthit mouseDragged:evt];
6035       else if (etype == NSRightMouseDown) [besthit rightMouseDown:evt];
6036       else if (etype == NSRightMouseUp) [besthit rightMouseUp:evt];
6037       else if (etype == NSRightMouseDragged) [besthit rightMouseDragged:evt];
6038       else if (etype == NSMouseMoved) [besthit mouseMoved:evt];
6039       else return false;
6040       
6041       return true;
6042     }
6043   }
6044   return false;
6047 int SWELL_GetWindowWantRaiseAmt(HWND h)
6049   SWELL_ModelessWindow* mw=0;
6050   if ([(id)h isKindOfClass:[SWELL_ModelessWindow class]])
6051   {
6052     mw=(SWELL_ModelessWindow*)h;
6053   }
6054   else if ([(id)h isKindOfClass:[NSView class]])
6055   {
6056     NSWindow* wnd=[(NSView*)h window];
6057     if (wnd && [wnd isKindOfClass:[SWELL_ModelessWindow class]])
6058     {
6059       mw=(SWELL_ModelessWindow*)wnd;
6060     }
6061   }
6062   if (mw) return mw->m_wantraiseamt;  
6063   return 0; 
6066 void SWELL_SetWindowWantRaiseAmt(HWND h, int  amt)
6068   SWELL_ModelessWindow *mw=NULL;
6069   if ([(id)h isKindOfClass:[SWELL_ModelessWindow class]]) mw=(SWELL_ModelessWindow *)h;
6070   else if ([(id)h isKindOfClass:[NSView class]])
6071   {
6072     NSWindow *w = [(NSView *)h window];
6073     if (w && [w isKindOfClass:[SWELL_ModelessWindow class]]) mw = (SWELL_ModelessWindow*)w;
6074   }
6075   if (mw) 
6076   {
6077     int diff = amt - mw->m_wantraiseamt;
6078     mw->m_wantraiseamt = amt;
6079     if (diff && [NSApp isActive]) [mw setLevel:[mw level]+diff];
6080   }
6084 int SWELL_SetWindowLevel(HWND hwnd, int newlevel)
6086   NSWindow *w = (NSWindow *)hwnd;
6087   if (w && [w isKindOfClass:[NSView class]]) w= [(NSView *)w window];
6088   
6089   if (w && [w isKindOfClass:[NSWindow class]])
6090   {
6091     int ol = (int)[w level];
6092     [w setLevel:newlevel];
6093     return ol;
6094   }
6095   return 0;
6098 void SetAllowNoMiddleManRendering(HWND h, bool allow)
6100   if (!h || ![(id)h isKindOfClass:[SWELL_hwndChild class]]) return;
6101   SWELL_hwndChild* v = (SWELL_hwndChild*)h;
6102   v->m_allow_nomiddleman = allow;
6105 void SetOpaque(HWND h, bool opaque)
6107   if (!h || ![(id)h isKindOfClass:[SWELL_hwndChild class]]) return;
6108   SWELL_hwndChild* v = (SWELL_hwndChild*)h;
6109   [v setOpaque:opaque];
6112 void SetTransparent(HWND h)
6114   if (!h) return;
6115   NSWindow* wnd=0;
6116   if ([(id)h isKindOfClass:[NSWindow class]]) wnd=(NSWindow*)h;
6117   else if ([(id)h isKindOfClass:[NSView class]]) wnd=[(NSView*)h window];
6118   if (wnd) 
6119   {
6120     [wnd setBackgroundColor:[NSColor clearColor]];
6121     [wnd setOpaque:NO];
6122   }  
6125 int SWELL_GetDefaultButtonID(HWND hwndDlg, bool onlyIfEnabled)
6127   if (![(id)hwndDlg isKindOfClass:[NSView class]]) return 0;
6128   NSWindow *wnd = [(NSView *)hwndDlg window];
6129   NSButtonCell * cell = wnd ? [wnd defaultButtonCell] : nil;
6130   NSView *view;
6131   if (!cell || !(view=[cell controlView])) return 0;
6132   int cmdid = (int)[view tag];
6133   if (cmdid && onlyIfEnabled)
6134   {
6135     if (![cell isEnabled]) return 0;
6136   }
6137   return cmdid;
6141 void SWELL_SetWindowRepre(HWND hwnd, const char *fn, bool isDirty)
6143   if (!hwnd) return;
6144   NSWindow *w = NULL;
6145   if ([(id)hwnd isKindOfClass:[NSWindow class]]) w=(NSWindow *)hwnd;
6146   if ([(id)hwnd isKindOfClass:[NSView class]]) w=[(NSView *)hwnd window];
6147   
6148   if (w)
6149   {
6150     if (GetProp((HWND)[w contentView],"SWELL_DisableWindowRepre")) return;
6151     
6152     [w setDocumentEdited:isDirty];
6153     
6154     if (!fn || !*fn) [w setRepresentedFilename:@""];
6155     else
6156     {
6157       NSString *str = (NSString *)SWELL_CStringToCFString(fn);
6158       [w setRepresentedFilename:str];
6159       [str release];
6160     }
6161   }
6164 void SWELL_SetWindowShadow(HWND hwnd, bool shadow)
6166   if (!hwnd) return;
6167   NSWindow *w = (NSWindow *)hwnd;
6168   if ([w isKindOfClass:[NSView class]]) w = [(NSView *)w window];
6169   if (w && [w isKindOfClass:[NSWindow class]]) [w setHasShadow:shadow];
6172 #if 0 // not sure if this will interfere with coolSB
6173 BOOL ShowScrollBar(HWND hwnd, int nBar, BOOL vis)
6175   int v=0;
6176   if (nBar == SB_HORZ || nBar == SB_BOTH) v |= WS_HSCROLL;
6177   if (nBar == SB_VERT || nBar == SB_BOTH) v |= WS_VSCROLL;
6178   if (v)
6179   {
6180     int s=GetWindowLong(hwnd, GWL_STYLE);
6181     if (vis) s |= v;
6182     else s &= ~v;
6183     SetWindowLong(hwnd, GWL_STYLE, s);
6184     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
6185     return TRUE;
6186   }
6187   return FALSE;
6189 #endif
6192 void SWELL_GenerateDialogFromList(const void *_list, int listsz)
6194 #define SIXFROMLIST list->p1,list->p2,list->p3, list->p4, list->p5, list->p6
6195   SWELL_DlgResourceEntry *list = (SWELL_DlgResourceEntry*)_list;
6196   while (listsz>0)
6197   {
6198     if (!strcmp(list->str1,"__SWELL_BUTTON"))
6199     {
6200       SWELL_MakeButton(list->flag1,list->str2, SIXFROMLIST);
6201     } 
6202     else if (!strcmp(list->str1,"__SWELL_EDIT"))
6203     {
6204       SWELL_MakeEditField(SIXFROMLIST);
6205     }
6206     else if (!strcmp(list->str1,"__SWELL_COMBO"))
6207     {
6208       SWELL_MakeCombo(SIXFROMLIST);
6209     }
6210     else if (!strcmp(list->str1,"__SWELL_LISTBOX"))
6211     {
6212       SWELL_MakeListBox(SIXFROMLIST);
6213     }
6214     else if (!strcmp(list->str1,"__SWELL_GROUP"))
6215     {
6216       SWELL_MakeGroupBox(list->str2,SIXFROMLIST);
6217     }
6218     else if (!strcmp(list->str1,"__SWELL_CHECKBOX"))
6219     {
6220       SWELL_MakeCheckBox(list->str2,SIXFROMLIST);
6221     }
6222     else if (!strcmp(list->str1,"__SWELL_LABEL"))
6223     {
6224       SWELL_MakeLabel(list->flag1, list->str2, SIXFROMLIST);
6225     }
6226     else if (*list->str2)
6227     {
6228       SWELL_MakeControl(list->str1, list->flag1, list->str2, SIXFROMLIST);
6229     }
6230     listsz--;
6231     list++;
6232   }
6235 BOOL EnumChildWindows(HWND hwnd, BOOL (*cwEnumFunc)(HWND,LPARAM),LPARAM lParam)
6237   if (!hwnd || ![(id)hwnd isKindOfClass:[NSView class]]) return TRUE;
6238   NSArray *ar = [(NSView *)hwnd subviews];
6239   if (ar)
6240   {
6241     [ar retain];
6242     NSInteger x,n=[ar count];
6243     for (x=0;x<n;x++)
6244     {
6245       NSView *v = [ar objectAtIndex:x];
6246       if (v)
6247       {
6248         if ([v isKindOfClass:[NSScrollView class]])
6249         {
6250           NSView *sv=[(NSScrollView *)v documentView];
6251           if (sv) v=sv;
6252         }
6253         if ([v isKindOfClass:[NSClipView class]]) 
6254         {
6255           NSView *sv = [(NSClipView *)v documentView];
6256           if (sv) v=sv;
6257         }
6259         if (!cwEnumFunc((HWND)v,lParam) || !EnumChildWindows((HWND)v,cwEnumFunc,lParam)) 
6260         {
6261           [ar release];
6262           return FALSE;
6263         }
6264       }
6265     }
6266     [ar release];
6267   }
6268   return TRUE;
6271 void SWELL_GetDesiredControlSize(HWND hwnd, RECT *r)
6273   if (hwnd && r && [(id)hwnd isKindOfClass:[NSControl class]])
6274   {
6275     NSControl *c = (NSControl *)hwnd;
6276     NSRect fr = [c frame];
6277     [c sizeToFit];
6278     NSRect frnew=[c frame];
6279     [c setFrame:fr];
6280     r->left=r->top=0;
6281     r->right = (int)frnew.size.width;
6282     r->bottom = (int)frnew.size.height;
6283   }
6286 BOOL SWELL_IsGroupBox(HWND hwnd)
6288   if (hwnd && [(id)hwnd isKindOfClass:[SWELL_BoxView class]]) return TRUE;
6289   return FALSE;
6291 BOOL SWELL_IsButton(HWND hwnd)
6293   if (hwnd && [(id)hwnd isKindOfClass:[SWELL_Button class]]) return TRUE;
6294   return FALSE;
6296 BOOL SWELL_IsStaticText(HWND hwnd)
6298   if (hwnd && [(id)hwnd isKindOfClass:[NSTextField class]]) return TRUE;
6299   //todo
6300   return FALSE;
6304 bool SWELL_SetAppAutoHideMenuAndDock(int ah) 
6306   static char _init;
6307   static NSUInteger _defpres;
6308   if (!_init)
6309   {
6310     if (SWELL_GetOSXVersion()>=0x1060)
6311     {
6312       _init=1;
6313       _defpres = [(SWELL_AppExtensions*)[NSApplication sharedApplication] presentationOptions];
6314     }
6315     else
6316     {
6317       _init=-1;
6318     }
6319   }
6320   if (_init > 0)
6321   {
6322     const int NSApplicationPresentationAutoHideDock               = (1 <<  0),
6323               NSApplicationPresentationHideDock = (1<<1),
6324               NSApplicationPresentationAutoHideMenuBar            = (1 <<  2);
6326     if (ah>0) [(SWELL_AppExtensions*)[NSApplication sharedApplication] setPresentationOptions:((ah>=2?NSApplicationPresentationHideDock:NSApplicationPresentationAutoHideDock)|NSApplicationPresentationAutoHideMenuBar)];
6327     else [(SWELL_AppExtensions*)[NSApplication sharedApplication] setPresentationOptions:_defpres];
6328     return true;
6329   }
6330   return false;
6333 #endif