Merge pull request #110 from tesselode/fixes
[wdl/wdl-ol.git] / WDL / swell / swell-wnd.mm
blob36d3120196a8d0f5899bdee9f93e7c5813f01195
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       case WM_SETREDRAW:
934         if (wParam)
935         {
936           if (SWELL_GetOSXVersion() >= 0x1070 && [self respondsToSelector:@selector(endUpdates)])
937             [self endUpdates];
938         }
939         else
940         {
941           if (SWELL_GetOSXVersion() >= 0x1070 && [self respondsToSelector:@selector(beginUpdates)])
942             [self beginUpdates];
943         }
945         return 0;
946     }
947   return 0;
950 -(int)getSwellNotificationMode
952   return m_lbMode;
954 -(void)setSwellNotificationMode:(int)lbMode
956   m_lbMode=lbMode;
959 -(void)onSwellCommand:(int)cmd
961   // ignore commands
964 @end
966 @implementation SWELL_ImageButtonCell
967 - (NSRect)drawTitle:(NSAttributedString *)title withFrame:(NSRect)frame inView:(NSView *)controlView
969   return NSMakeRect(0,0,0,0);
971 @end
973 @implementation SWELL_ODButtonCell
974 - (BOOL)isTransparent
976   return YES;
978 - (BOOL)isOpaque
980   return NO;
983 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
985   NSView *ctl=[self controlView];
986   if (!ctl) { [super drawWithFrame:cellFrame inView:controlView]; return; }
987   
988   HDC hdc=GetDC((HWND)controlView);
989   if (hdc)
990   {
991     HWND notWnd = GetParent((HWND)ctl);
992     RECT r={(int)(cellFrame.origin.x+0.5),(int)(cellFrame.origin.y+0.5)};
993     r.right=r.left+(int)(cellFrame.size.width+0.5);
994     r.bottom=r.top+(int)(cellFrame.size.height+0.5);
995     DRAWITEMSTRUCT dis={ODT_BUTTON,(UINT)[ctl tag],0,0,0,(HWND)ctl,hdc,{0,},0};
996     dis.rcItem = r;
997     SendMessage(notWnd,WM_DRAWITEM,dis.CtlID,(LPARAM)&dis);
998   
999     ReleaseDC((HWND)controlView,hdc);
1000   }
1001   
1003 @end
1005 @implementation SWELL_ODListViewCell
1006 -(void)setOwnerControl:(SWELL_ListView *)t { m_ownctl=t; m_lastidx=0; }
1007 -(void)setItemIdx:(int)idx
1009   m_lastidx=idx;
1011 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
1013   if (!m_ownctl) { [super drawInteriorWithFrame:cellFrame inView:controlView]; return; }
1014   
1015   int itemidx=m_lastidx;
1016   LPARAM itemData=0;
1017   SWELL_ListView_Row *row=m_ownctl->m_items->Get(itemidx);
1018   if (row) itemData=row->m_param;
1020   HDC hdc=GetDC((HWND)controlView);
1021   if (hdc)
1022   {
1023     HWND notWnd = GetParent((HWND)m_ownctl);
1024     RECT r={(int)(cellFrame.origin.x+0.5),(int)(cellFrame.origin.y+0.5)};
1025     r.right=r.left+(int)(cellFrame.size.width+0.5);
1026     r.bottom=r.top+(int)(cellFrame.size.height+0.5);
1027     DRAWITEMSTRUCT dis={ODT_LISTBOX,(UINT)[m_ownctl tag],(UINT)itemidx,0,0,(HWND)m_ownctl,hdc,{0,},(DWORD_PTR)itemData};
1028     dis.rcItem = r;
1029     SendMessage(notWnd,WM_DRAWITEM,dis.CtlID,(LPARAM)&dis);
1030   
1031     ReleaseDC((HWND)controlView,hdc);
1032   }
1036 @end
1042 HWND GetDlgItem(HWND hwnd, int idx)
1044   if (!hwnd) return 0;
1046   NSView *v=0;
1047   id pid=(id)hwnd;
1048   if ([pid isKindOfClass:[NSWindow class]]) v=[((NSWindow *)pid) contentView];
1049   else if ([pid isKindOfClass:[NSView class]]) v=(NSView *)pid;
1050   
1051   if (!idx || !v) return (HWND)v;
1052   
1053   SWELL_BEGIN_TRY
1055   NSArray *ar = [v subviews];
1056   const NSInteger n=[ar count];
1057   for (NSInteger x=0;x<n;x++)
1058   {
1059     NSView *sv = [ar objectAtIndex:x];
1060     if (sv)
1061     {
1062       if ([sv respondsToSelector:@selector(tag)] && [sv tag] == idx) return (HWND)sv;
1064       if (sv && [sv isKindOfClass:[NSScrollView class]])
1065       {
1066         sv=[(NSScrollView *)sv documentView];
1067         if (sv && [sv respondsToSelector:@selector(tag)] && [sv tag] == idx) return (HWND)sv;
1068       }
1069       if (sv && [sv isKindOfClass:[NSClipView class]]) 
1070       {
1071         sv = [(NSClipView *)sv documentView];
1072         if (sv && [sv respondsToSelector:@selector(tag)] && [sv tag] == idx) return (HWND)sv;
1073       }
1074     }
1075   }
1076   // we might want to enable this for max compat with old code, but hopefully not:  return [v viewWithTag:idx]; 
1077   SWELL_END_TRY(;)
1078   return NULL;
1082 LONG_PTR SetWindowLong(HWND hwnd, int idx, LONG_PTR val)
1084   if (!hwnd) return 0;
1086   SWELL_BEGIN_TRY
1087   id pid=(id)hwnd;
1088   if (idx==GWL_EXSTYLE && [pid respondsToSelector:@selector(swellSetExtendedStyle:)])
1089   {
1090     LONG ret=(LONG) [(SWELL_hwndChild*)pid swellGetExtendedStyle];
1091     [(SWELL_hwndChild*)pid swellSetExtendedStyle:(LONG)val];
1092     return ret;
1093   }
1094   if (idx==GWL_USERDATA && [pid respondsToSelector:@selector(setSwellUserData:)])
1095   {
1096     LONG_PTR ret=(LONG_PTR)[(SWELL_hwndChild*)pid getSwellUserData];
1097     [(SWELL_hwndChild*)pid setSwellUserData:(LONG_PTR)val];
1098     return ret;
1099   }
1100     
1101   if (idx==GWL_ID && [pid respondsToSelector:@selector(tag)] && [pid respondsToSelector:@selector(setTag:)])
1102   {
1103     int ret= (int) [pid tag];
1104     [pid setTag:(int)val];
1105     return (LONG_PTR)ret;
1106   }
1107   
1108   if (idx==GWL_WNDPROC && [pid respondsToSelector:@selector(setSwellWindowProc:)])
1109   {
1110     WNDPROC ov=(WNDPROC)[pid getSwellWindowProc];
1111     [pid setSwellWindowProc:(WNDPROC)val];
1112     return (LONG_PTR)ov;
1113   }
1114   if (idx==DWL_DLGPROC && [pid respondsToSelector:@selector(setSwellDialogProc:)])
1115   {
1116     DLGPROC ov=(DLGPROC)[pid getSwellDialogProc];
1117     [pid setSwellDialogProc:(DLGPROC)val];
1118     return (LONG_PTR)ov;
1119   }
1120   
1121   if (idx==GWL_STYLE)
1122   {
1123     if ([pid respondsToSelector:@selector(setSwellStyle:)])
1124     {
1125       LONG ov=[pid getSwellStyle];
1126       [pid setSwellStyle:(LONG)val];
1127       return ov;
1128     }
1129     else if ([pid isKindOfClass:[NSButton class]]) 
1130     {
1131       int ret=(int)GetWindowLong(hwnd,idx);
1132       
1133       if ((val&0xf) == BS_AUTO3STATE)
1134       {
1135         [pid setButtonType:NSSwitchButton];
1136         [pid setAllowsMixedState:YES];
1137         if ([pid isKindOfClass:[SWELL_Button class]]) [pid swellSetRadioFlags:0];
1138       }    
1139       else if ((val & 0xf) == BS_AUTOCHECKBOX)
1140       {
1141         [pid setButtonType:NSSwitchButton];
1142         [pid setAllowsMixedState:NO];
1143         if ([pid isKindOfClass:[SWELL_Button class]]) [pid swellSetRadioFlags:0];
1144       }
1145       else if ((val &  0xf) == BS_AUTORADIOBUTTON)
1146       {
1147         [pid setButtonType:NSRadioButton];
1148         if ([pid isKindOfClass:[SWELL_Button class]]) [pid swellSetRadioFlags:(val&WS_GROUP)?3:1];
1149       }               
1150       
1151       return ret;
1152     }
1153     else 
1154     {
1155       if ([[pid window] contentView] == pid)
1156       {
1157         NSView *tv=(NSView *)pid;
1158         NSWindow *oldw = [tv window];
1159         NSUInteger smask = [oldw styleMask];
1160         int mf=0;
1161         if (smask & NSTitledWindowMask)
1162         {
1163           mf|=WS_CAPTION;
1164           if (smask & NSResizableWindowMask) mf|=WS_THICKFRAME;
1165         }
1166         if (mf != (val&(WS_CAPTION|WS_THICKFRAME)))
1167         {
1168           BOOL dovis = IsWindowVisible((HWND)oldw);
1169           NSWindow *oldpar = [oldw parentWindow];
1170           char oldtitle[2048];
1171           oldtitle[0]=0;
1172           GetWindowText(hwnd,oldtitle,sizeof(oldtitle));
1173           NSRect fr=[oldw frame];
1174           HWND oldOwner=NULL;
1175           if ([oldw respondsToSelector:@selector(swellGetOwner)]) oldOwner=(HWND)[(SWELL_ModelessWindow*)oldw swellGetOwner];
1176           NSInteger oldlevel = [oldw level];
1178           
1179           [tv retain];
1180           SWELL_hwndChild *tempview = [[SWELL_hwndChild alloc] initChild:nil Parent:(NSView *)oldw dlgProc:nil Param:0];          
1181           [tempview release];          
1182           
1183           unsigned int mask=0;
1184           
1185           if (val & WS_CAPTION)
1186           {
1187             mask|=NSTitledWindowMask;
1188             if (val & WS_THICKFRAME)
1189               mask|=NSMiniaturizableWindowMask|NSClosableWindowMask|NSResizableWindowMask;
1190           }
1191       
1192           HWND SWELL_CreateModelessFrameForWindow(HWND childW, HWND ownerW, unsigned int);
1193           HWND bla=SWELL_CreateModelessFrameForWindow((HWND)tv,(HWND)oldOwner,mask);
1194           
1195           if (bla)
1196           {
1197             [tv release];
1198             // move owned windows over
1199             if ([oldw respondsToSelector:@selector(swellGetOwnerWindowHead)])
1200             {
1201               void **p=(void **)[(SWELL_ModelessWindow*)oldw swellGetOwnerWindowHead];
1202               if (p && [(id)bla respondsToSelector:@selector(swellGetOwnerWindowHead)])
1203               {
1204                 void **p2=(void **)[(SWELL_ModelessWindow*)bla swellGetOwnerWindowHead];
1205                 if (p && p2) 
1206                 {
1207                   *p2=*p;
1208                   *p=0;
1209                   OwnedWindowListRec *rec = (OwnedWindowListRec *) *p2;
1210                   while (rec)
1211                   {
1212                     if (rec->hwnd && [rec->hwnd respondsToSelector:@selector(swellSetOwner:)])
1213                       [(SWELL_ModelessWindow *)rec->hwnd swellSetOwner:(id)bla];
1214                     rec=rec->_next;
1215                   }
1216                 }
1217               }
1218             }
1219             // move all child and owned windows over to new window
1220             NSArray *ar=[oldw childWindows];
1221             if (ar)
1222             {
1223               int x;
1224               for (x = 0; x < [ar count]; x ++)
1225               {
1226                 NSWindow *cw=[ar objectAtIndex:x];
1227                 if (cw)
1228                 {
1229                   [cw retain];
1230                   [oldw removeChildWindow:cw];
1231                   [(NSWindow *)bla addChildWindow:cw ordered:NSWindowAbove];
1232                   [cw release];
1233                   
1234                   
1235                 }
1236               }
1237             }
1238           
1239             if (oldpar) [oldpar addChildWindow:(NSWindow *)bla ordered:NSWindowAbove];
1240             if (oldtitle[0]) SetWindowText(hwnd,oldtitle);
1241             
1242             [(NSWindow *)bla setFrame:fr display:dovis];
1243             [(NSWindow *)bla setLevel:oldlevel];
1244             if (dovis) ShowWindow(bla,SW_SHOW);
1245       
1246             DestroyWindow((HWND)oldw);
1247           }
1248           else
1249           {
1250             [oldw setContentView:tv];
1251             [tv release];
1252           }  
1253       
1254         }
1255       }
1256     }
1257     return 0;
1258   }
1260   
1261   if ([pid respondsToSelector:@selector(setSwellExtraData:value:)])
1262   {
1263     LONG_PTR ov=0;
1264     if ([pid respondsToSelector:@selector(getSwellExtraData:)]) ov=(LONG_PTR)[pid getSwellExtraData:idx];
1266     [pid setSwellExtraData:idx value:val];
1267     
1268     return ov;
1269   }
1270    
1271   SWELL_END_TRY(;)
1272   return 0;
1275 LONG_PTR GetWindowLong(HWND hwnd, int idx)
1277   if (!hwnd) return 0;
1278   id pid=(id)hwnd;
1280   SWELL_BEGIN_TRY
1281   
1282   if (idx==GWL_EXSTYLE && [pid respondsToSelector:@selector(swellGetExtendedStyle)])
1283   {
1284     return (LONG_PTR)[pid swellGetExtendedStyle];
1285   }
1286   
1287   if (idx==GWL_USERDATA && [pid respondsToSelector:@selector(getSwellUserData)])
1288   {
1289     return (LONG_PTR)[pid getSwellUserData];
1290   }
1291   if (idx==GWL_USERDATA && [pid isKindOfClass:[NSText class]])
1292   {
1293     return 0xdeadf00b;
1294   }
1295   
1296   if (idx==GWL_ID && [pid respondsToSelector:@selector(tag)])
1297     return [pid tag];
1298   
1299   
1300   if (idx==GWL_WNDPROC && [pid respondsToSelector:@selector(getSwellWindowProc)])
1301   {
1302     return (LONG_PTR)[pid getSwellWindowProc];
1303   }
1304   if (idx==DWL_DLGPROC && [pid respondsToSelector:@selector(getSwellDialogProc)])
1305   {
1306     return (LONG_PTR)[pid getSwellDialogProc];
1307   }  
1308   if (idx==GWL_STYLE)
1309   {
1310     int ret=0;
1311     if ([pid respondsToSelector:@selector(getSwellStyle)])
1312     {
1313       return (LONG_PTR)[pid getSwellStyle];
1314     }    
1315     
1316     if ([pid isKindOfClass:[NSButton class]]) 
1317     {
1318       int tmp;
1319       if ([pid allowsMixedState]) ret |= BS_AUTO3STATE;
1320       else if ([pid isKindOfClass:[SWELL_Button class]] && (tmp = (int)[pid swellGetRadioFlags]))
1321       {
1322         ret |= BS_AUTORADIOBUTTON;
1323         if (tmp&2) ret|=WS_GROUP;
1324       }
1325       else ret |= BS_AUTOCHECKBOX; 
1326     }
1327     
1328     if ([pid isKindOfClass:[NSView class]])
1329     {
1330       if ([[pid window] contentView] != pid) ret |= WS_CHILDWINDOW;
1331       else
1332       {
1333         NSUInteger smask  =[[pid window] styleMask];
1334         if (smask & NSTitledWindowMask)
1335         {
1336           ret|=WS_CAPTION;
1337           if (smask & NSResizableWindowMask) ret|=WS_THICKFRAME;
1338         }
1339       }
1340     }
1341     
1342     return ret;
1343   }
1344   if ([pid respondsToSelector:@selector(getSwellExtraData:)])
1345   {
1346     return (LONG_PTR)[pid getSwellExtraData:idx];
1347   }
1348   
1349   SWELL_END_TRY(;)
1350   return 0;
1353 static bool IsWindowImpl(NSView *ch, NSView *par)
1355   if (!par || ![par isKindOfClass:[NSView class]]) return false;
1357   NSArray *ar = [par subviews];
1358   if (!ar) return false;
1359   [ar retain];
1360   NSInteger x,n=[ar count];
1361   for (x=0;x<n;x++)
1362     if ([ar objectAtIndex:x] == ch) 
1363     {
1364       [ar release];
1365       return true;
1366     }
1368   for (x=0;x<n;x++)
1369     if (IsWindowImpl(ch,[ar objectAtIndex:x])) 
1370     {
1371       [ar release];
1372       return true;
1373     }
1375   [ar release];
1376   return false;
1378 bool IsWindow(HWND hwnd)
1380   if (!hwnd) return false;
1381   // this is very costly, but required
1382   SWELL_BEGIN_TRY
1384   NSArray *ch=[NSApp windows];
1385   [ch retain];
1386   NSInteger x,n=[ch count];
1387   for(x=0;x<n; x ++)
1388   {
1389     @try { 
1390       NSWindow *w = [ch objectAtIndex:x]; 
1391       if (w == (NSWindow *)hwnd || [w contentView] == (NSView *)hwnd) 
1392       {
1393         [ch release];
1394         return true;
1395       }
1396     }
1397     @catch (NSException *ex) { 
1398     }
1399     @catch (id ex) {
1400     }
1401   }
1402   for(x=0;x<n; x ++)
1403   {
1404     @try { 
1405       NSWindow *w = [ch objectAtIndex:x];
1406       if (w && 
1407           // only validate children of our windows (maybe an option for this?)
1408           ([w isKindOfClass:[SWELL_ModelessWindow class]] || [w isKindOfClass:[SWELL_ModalDialog class]]) &&
1409           IsWindowImpl((NSView*)hwnd,[w contentView])) 
1410       {
1411         [ch release];
1412         return true;
1413       }
1414     } 
1415     @catch (NSException *ex) { 
1416     }
1417     @catch (id ex) {
1418     }
1419   }
1420   [ch release];
1422   SWELL_END_TRY(;)
1423   return false;
1426 bool IsWindowVisible(HWND hwnd)
1428   if (!hwnd) return false;
1430   SWELL_BEGIN_TRY
1431   id turd=(id)hwnd;
1432   if ([turd isKindOfClass:[NSView class]])
1433   {
1434     NSWindow *w = [turd window];
1435     if (w && ![w isVisible]) return false;
1436     
1437     return ![turd isHiddenOrHasHiddenAncestor];
1438   }
1439   if ([turd isKindOfClass:[NSWindow class]])
1440   {
1441     return !![turd isVisible];
1442   }
1443   SWELL_END_TRY(;)
1444   return true;
1448 bool IsWindowEnabled(HWND hwnd)
1450   if (!hwnd) return false;
1452   bool rv = true;
1454   SWELL_BEGIN_TRY
1456   id view = (id)hwnd;
1457   if ([view isKindOfClass:[NSWindow class]]) view = [view contentView];
1459   rv = view && [view respondsToSelector:@selector(isEnabled)] && [view isEnabled];
1461   SWELL_END_TRY(;)
1463   return rv;
1469 static void *__GetNSImageFromHICON(HICON ico) // local copy to not be link dependent on swell-gdi.mm
1471   HGDIOBJ__ *i = (HGDIOBJ__ *)ico;
1472   if (!i || i->type != TYPE_BITMAP) return 0;
1473   return i->bitmapptr;
1477 @implementation SWELL_Button : NSButton
1479 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
1481 -(id) init {
1482   self = [super init];
1483   if (self != nil) {
1484     m_userdata=0;
1485     m_swellGDIimage=0;
1486     m_radioflags=0;
1487   }
1488   return self;
1490 -(int)swellGetRadioFlags { return m_radioflags; }
1491 -(void)swellSetRadioFlags:(int)f { m_radioflags=f; }
1492 -(LONG_PTR)getSwellUserData { return m_userdata; }
1493 -(void)setSwellUserData:(LONG_PTR)val {   m_userdata=val; }
1495 -(void)setSwellGDIImage:(void *)par
1497   m_swellGDIimage=par;
1499 -(void *)getSwellGDIImage
1501   return m_swellGDIimage;
1504 @end
1506 LRESULT SendMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1508   if (!hwnd) return 0;
1510   SWELL_BEGIN_TRY
1511   id obj=(id)hwnd;
1512   if ([obj respondsToSelector:@selector(onSwellMessage:p1:p2:)])
1513   {
1514     return (LRESULT) [obj onSwellMessage:msg p1:wParam p2:lParam];
1515   }
1516   else 
1517   {
1518     if (msg == BM_GETCHECK && [obj isKindOfClass:[NSButton class]])
1519     {
1520       NSInteger a=[(NSButton*)obj state];
1521       if (a==NSMixedState) return BST_INDETERMINATE;
1522       return a!=NSOffState;
1523     }
1524     if (msg == BM_SETCHECK && [obj isKindOfClass:[NSButton class]])
1525     {
1526       [(NSButton*)obj setState:(wParam&BST_INDETERMINATE)?NSMixedState:((wParam&BST_CHECKED)?NSOnState:NSOffState)];
1527       return 0;
1528     }
1529     if ((msg==BM_GETIMAGE || msg == BM_SETIMAGE) && [obj isKindOfClass:[SWELL_Button class]])
1530     {
1531       if (wParam != IMAGE_BITMAP && wParam != IMAGE_ICON) return 0; // ignore unknown types
1532       LONG_PTR ret=(LONG_PTR) (void *)[obj getSwellGDIImage];
1533       if (msg==BM_SETIMAGE)
1534       {
1535         NSImage *img=NULL;
1536         if (lParam) img=(NSImage *)__GetNSImageFromHICON((HICON)lParam);
1537         [obj setImage:img];
1538         [obj setSwellGDIImage:(void *)(img?lParam:0)];
1539       }
1540       return ret;
1541     }
1542     else if (msg >= CB_ADDSTRING && msg <= CB_INITSTORAGE && ([obj isKindOfClass:[NSPopUpButton class]] || [obj isKindOfClass:[NSComboBox class]]))
1543     {
1544         switch (msg)
1545         {
1546           case CB_ADDSTRING: return SWELL_CB_AddString(hwnd,0,(char*)lParam); 
1547           case CB_DELETESTRING: SWELL_CB_DeleteString(hwnd,0,(int)wParam); return 1;
1548           case CB_GETCOUNT: return SWELL_CB_GetNumItems(hwnd,0);
1549           case CB_GETCURSEL: return SWELL_CB_GetCurSel(hwnd,0);
1550           case CB_GETLBTEXT: return SWELL_CB_GetItemText(hwnd,0,(int)wParam,(char *)lParam, 1<<20);
1551           case CB_GETLBTEXTLEN: return SWELL_CB_GetItemText(hwnd,0,(int)wParam,NULL,0);
1552           case CB_INSERTSTRING: return SWELL_CB_InsertString(hwnd,0,(int)wParam,(char *)lParam);
1553           case CB_RESETCONTENT: SWELL_CB_Empty(hwnd,0); return 0;
1554           case CB_SETCURSEL: SWELL_CB_SetCurSel(hwnd,0,(int)wParam); return 0;
1555           case CB_GETITEMDATA: return SWELL_CB_GetItemData(hwnd,0,(int)wParam);
1556           case CB_SETITEMDATA: SWELL_CB_SetItemData(hwnd,0,(int)wParam,lParam); return 0;
1557           case CB_FINDSTRING:
1558           case CB_FINDSTRINGEXACT:
1559             if (lParam) return SWELL_CB_FindString(hwnd,0,(int)wParam,(const char *)lParam,msg==CB_FINDSTRINGEXACT);
1560             return CB_ERR;
1561           case CB_INITSTORAGE: return 0;                                                      
1562         }
1563         return 0;
1564     }
1565     else if (msg >= TBM_GETPOS && msg <= TBM_SETRANGE && ([obj isKindOfClass:[NSSlider class]]))
1566     {
1567         switch (msg)
1568         {
1569           case TBM_GETPOS: return SWELL_TB_GetPos(hwnd,0);
1570           case TBM_SETTIC: SWELL_TB_SetTic(hwnd,0,(int)lParam); return 1;
1571           case TBM_SETPOS: SWELL_TB_SetPos(hwnd,0,(int)lParam); return 1;
1572           case TBM_SETRANGE: SWELL_TB_SetRange(hwnd,0,LOWORD(lParam),HIWORD(lParam)); return 1;
1573         }
1574         return 0;
1575     }
1576     else if ((msg == EM_SETSEL || msg == EM_GETSEL || msg == EM_SETPASSWORDCHAR) && ([obj isKindOfClass:[NSTextField class]]))
1577     { 
1578       if (msg == EM_GETSEL)
1579       {
1580         NSRange range={0,};
1581         NSResponder *rs = [[obj window] firstResponder];
1582         if ([rs isKindOfClass:[NSView class]] && [(NSView *)rs isDescendantOf:obj])
1583         {
1584           NSText* text=[[obj window] fieldEditor:YES forObject:(NSTextField*)obj];  
1585           if (text) range=[text selectedRange];
1586         }
1587         if (wParam) *(int*)wParam=(int)range.location;
1588         if (lParam) *(int*)lParam=(int)(range.location+range.length);
1589       }      
1590       else if (msg == EM_SETSEL)
1591       {        
1592         //        [(NSTextField*)obj selectText:obj]; // Force the window's text field editor onto this control
1593         // don't force it, just ignore EM_GETSEL/EM_SETSEL if not in focus
1594         NSResponder *rs = [[obj window] firstResponder];
1595         if ([rs isKindOfClass:[NSView class]] && [(NSView *)rs isDescendantOf:obj])
1596         {
1597           NSText* text = [[obj window] fieldEditor:YES forObject:(NSTextField*)obj]; // then get it from the window 
1598           NSUInteger sl = [[text string] length];
1599           if (wParam == -1) lParam = wParam = 0;
1600           else if (lParam == -1) lParam = sl;        
1601           if (wParam>sl) wParam=sl;
1602           if (lParam>sl) lParam=sl;      
1603           if (text) [text setSelectedRange:NSMakeRange(wParam, wdl_max(lParam-wParam,0))]; // and set the range
1604         }
1605       }
1606       else if (msg == EM_SETPASSWORDCHAR)
1607       {
1608         // not implemented, because it requires replacing obj within its parent window
1609         // instead caller explicitly destroy the edit control and create a new one with ES_PASSWORD
1610       }
1611       return 0;
1612     }
1613     else
1614     {
1615       NSWindow *w;
1616       NSView *v;
1617       // if content view gets unhandled message send to window
1618       if ([obj isKindOfClass:[NSView class]] && (w=[obj window]) && [w contentView] == obj && [w respondsToSelector:@selector(onSwellMessage:p1:p2:)])
1619       {
1620         return (LRESULT) [(SWELL_hwndChild *)w onSwellMessage:msg p1:wParam p2:lParam];
1621       }
1622       // if window gets unhandled message send to content view
1623       else if ([obj isKindOfClass:[NSWindow class]] && (v=[obj contentView]) && [v respondsToSelector:@selector(onSwellMessage:p1:p2:)])
1624       {
1625         return (LRESULT) [(SWELL_hwndChild *)v onSwellMessage:msg p1:wParam p2:lParam];
1626       }
1627     }
1628   }
1629   SWELL_END_TRY(;)
1630   return 0;
1633 void DestroyWindow(HWND hwnd)
1635   if (!hwnd) return;
1636   SWELL_BEGIN_TRY
1637   id pid=(id)hwnd;
1638   if ([pid isKindOfClass:[NSView class]])
1639   {
1640     KillTimer(hwnd,~(UINT_PTR)0);
1641     sendSwellMessage((id)pid,WM_DESTROY,0,0);
1642       
1643     NSWindow *pw = [(NSView *)pid window];
1644     if (pw && [pw contentView] == pid) // destroying contentview should destroy top level window
1645     {
1646       DestroyWindow((HWND)pw);
1647     }
1648     else 
1649     {
1650       if (pw && [NSApp keyWindow] == pw)
1651       {
1652         id foc=[pw firstResponder];
1653         if (foc && (foc == pid || IsChild((HWND)pid,(HWND)foc)))
1654         {
1655           HWND h=GetParent((HWND)pid);
1656           if (h) SetFocus(h);
1657         }
1658       }
1659       [(NSView *)pid removeFromSuperview];
1660     }
1661   }
1662   else if ([pid isKindOfClass:[NSWindow class]])
1663   {
1664     KillTimer(hwnd,~(UINT_PTR)0);
1665     sendSwellMessage([(id)pid contentView],WM_DESTROY,0,0);
1666     sendSwellMessage((id)pid,WM_DESTROY,0,0);
1667       
1668     if ([(id)pid respondsToSelector:@selector(swellDoDestroyStuff)])
1669       [(id)pid swellDoDestroyStuff];
1670       
1671     NSWindow *par=[(NSWindow*)pid parentWindow];
1672     if (par)
1673     {
1674       [par removeChildWindow:(NSWindow*)pid];
1675     }
1676     [(NSWindow *)pid close]; // this is probably bad, but close takes too long to close!
1677   }
1678   SWELL_END_TRY(;)
1681 void EnableWindow(HWND hwnd, int enable)
1683   if (!hwnd) return;
1684   SWELL_BEGIN_TRY
1685   id bla=(id)hwnd;
1686   if ([bla isKindOfClass:[NSWindow class]]) bla = [bla contentView];
1687     
1688   if (bla && [bla respondsToSelector:@selector(setEnabled:)])
1689   {
1690     if (enable == -1000 && [bla respondsToSelector:@selector(setEnabledSwellNoFocus)])
1691       [bla setEnabledSwellNoFocus];
1692     else
1693       [bla setEnabled:(enable?YES:NO)];
1694     if ([bla isKindOfClass:[SWELL_TextField class]])
1695     {
1696       NSTextField* txt = (NSTextField*)bla;
1697       if (![txt isEditable] && ![txt isBordered] && ![txt drawsBackground]) // looks like a static text control
1698       {
1699         NSColor* col = [txt textColor];
1700         float alpha = (enable ? 1.0f : 0.5f);
1701         [txt setTextColor:[col colorWithAlphaComponent:alpha]];
1702       }
1703     }    
1704   }
1705   SWELL_END_TRY(;)
1708 void SetForegroundWindow(HWND hwnd)
1710   SetFocus(hwnd);
1713 void SetFocus(HWND hwnd) // these take NSWindow/NSView, and return NSView *
1715   id r=(id) hwnd;
1716   if (!r) return;
1717   
1718   SWELL_BEGIN_TRY
1719   if ([r isKindOfClass:[NSWindow class]])
1720   {
1721     [(NSWindow *)r makeFirstResponder:[(NSWindow *)r contentView]]; 
1722     if ([(NSWindow *)r isVisible]) [(NSWindow *)r makeKeyAndOrderFront:nil];
1723   }
1724   else if ([r isKindOfClass:[NSView class]])
1725   {
1726     NSWindow *wnd=[(NSView *)r window];
1727     if (wnd)
1728     {
1729       [wnd makeFirstResponder:r];
1730       if ([wnd isVisible])
1731       {
1732         [wnd makeKeyAndOrderFront:nil];
1733       }
1734     }
1735   }
1736   SWELL_END_TRY(;)
1739 void SWELL_GetViewPort(RECT *r, const RECT *sourcerect, bool wantWork)
1741   SWELL_BEGIN_TRY
1743   NSArray *ar=[NSScreen screens];
1744   
1745   const NSInteger cnt=[ar count];
1746   int cx=0;
1747   int cy=0;
1748   if (sourcerect)
1749   {
1750     cx=(sourcerect->left+sourcerect->right)/2;
1751     cy=(sourcerect->top+sourcerect->bottom)/2;
1752   }
1753   for (NSInteger x = 0; x < cnt; x ++)
1754   {
1755     NSScreen *sc=[ar objectAtIndex:x];
1756     if (sc)
1757     {
1758       NSRect tr=wantWork ? [sc visibleFrame] : [sc frame];
1759       if (!x || (cx >= tr.origin.x && cx < tr.origin.x+tr.size.width  &&
1760                 cy >= tr.origin.y && cy < tr.origin.y+tr.size.height))
1761       {
1762         r->left=(int)tr.origin.x;
1763         r->right=(int)(tr.origin.x+tr.size.width+0.5);
1764         r->top=(int)tr.origin.y;
1765         r->bottom=(int)(tr.origin.y+tr.size.height+0.5);
1766       }
1767     }
1768   }
1769   if (!cnt)
1770   {
1771     r->left=r->top=0;
1772     r->right=1600;
1773     r->bottom=1200;
1774   }
1775   SWELL_END_TRY(;)
1778 void ScreenToClient(HWND hwnd, POINT *p)
1780   if (!hwnd) return;
1781   // no need to try/catch, this should never have an issue *wince*
1782   
1783   id ch=(id)hwnd;
1784   if ([ch isKindOfClass:[NSWindow class]]) ch=[((NSWindow *)ch) contentView];
1785   if (!ch || ![ch isKindOfClass:[NSView class]]) return;
1786   
1787   NSWindow *window=[ch window];
1788   
1789   NSPoint wndpt = [window convertScreenToBase:NSMakePoint(p->x,p->y)];
1790   
1791   // todo : WM_NCCALCSIZE 
1792   NSPoint po = [ch convertPoint:wndpt fromView:nil];
1793   
1794   p->x=(int)(po.x+0.5);
1795   p->y=(int)(po.y+0.5);
1798 void ClientToScreen(HWND hwnd, POINT *p)
1800   if (!hwnd) return;
1801   
1802   id ch=(id)hwnd;
1803   if ([ch isKindOfClass:[NSWindow class]]) ch=[((NSWindow *)ch) contentView];
1804   if (!ch || ![ch isKindOfClass:[NSView class]]) return;
1805   
1806   NSWindow *window=[ch window];
1807   
1808   NSPoint wndpt = [ch convertPoint:NSMakePoint(p->x,p->y) toView:nil];
1809   
1810   NSPoint po = [window convertBaseToScreen:wndpt];
1811   // todo : WM_NCCALCSIZE 
1812   
1813   p->x=(int)(po.x+0.5);
1814   p->y=(int)(po.y+0.5);
1817 static NSView *NavigateUpScrollClipViews(NSView *ch)
1819   NSView *par=[ch superview];
1820   if (par && [par isKindOfClass:[NSClipView class]]) 
1821   {
1822     par=[par superview];
1823     if (par && [par isKindOfClass:[NSScrollView class]])
1824     {
1825       ch=par;
1826     }
1827   }
1828   return ch;
1831 HWND SWELL_NavigateUpScrollClipViews(HWND h)
1833   NSView *v = 0;
1834   if (h && [(id)h isKindOfClass:[NSView class]]) v = (NSView *)h;
1835   else if (h && [(id)h isKindOfClass:[NSWindow class]]) v = [(NSWindow *)h contentView];
1836   if (v)
1837     return (HWND)NavigateUpScrollClipViews(v);
1838   return 0;
1841 bool GetWindowRect(HWND hwnd, RECT *r)
1843   r->left=r->top=r->right=r->bottom=0;
1844   if (!hwnd) return false;
1846   SWELL_BEGIN_TRY
1847   
1848   id ch=(id)hwnd;
1849   NSWindow *nswnd;
1850   if ([ch isKindOfClass:[NSView class]] && (nswnd=[(NSView *)ch window]) && [nswnd contentView]==ch)
1851     ch=nswnd;
1852     
1853   if ([ch isKindOfClass:[NSWindow class]]) 
1854   {
1855     NSRect b=[ch frame];
1856     r->left=(int)(b.origin.x);
1857     r->top=(int)(b.origin.y);
1858     r->right = (int)(b.origin.x+b.size.width+0.5);
1859     r->bottom= (int)(b.origin.y+b.size.height+0.5);
1860     return true;
1861   }
1862   if (![ch isKindOfClass:[NSView class]]) return false;
1863   ch=NavigateUpScrollClipViews(ch);
1864   NSRect b=[ch bounds];
1865   r->left=(int)(b.origin.x);
1866   r->top=(int)(b.origin.y);
1867   r->right = (int)(b.origin.x+b.size.width+0.5);
1868   r->bottom= (int)(b.origin.y+b.size.height+0.5);
1869   ClientToScreen((HWND)ch,(POINT *)r);
1870   ClientToScreen((HWND)ch,((POINT *)r)+1);
1871   SWELL_END_TRY(return false;)
1873   return true;
1876 void GetWindowContentViewRect(HWND hwnd, RECT *r)
1878   SWELL_BEGIN_TRY
1879   NSWindow *nswnd;
1880   if (hwnd && [(id)hwnd isKindOfClass:[NSView class]] && (nswnd=[(NSView *)hwnd window]) && [nswnd contentView]==(id)hwnd)
1881     hwnd=(HWND)nswnd;
1882     
1883   if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]])
1884   {
1885     NSView *ch=[(id)hwnd contentView];
1886     NSRect b=[ch bounds];
1887     r->left=(int)(b.origin.x);
1888     r->top=(int)(b.origin.y);
1889     r->right = (int)(b.origin.x+b.size.width+0.5);
1890     r->bottom= (int)(b.origin.y+b.size.height+0.5);
1891     ClientToScreen(hwnd,(POINT *)r);
1892     ClientToScreen(hwnd,((POINT *)r)+1);
1893   }
1894   else GetWindowRect(hwnd,r);
1895   SWELL_END_TRY(;)
1899 void GetClientRect(HWND hwnd, RECT *r)
1901   r->left=r->top=r->right=r->bottom=0;
1902   if (!hwnd) return;
1903   
1904   SWELL_BEGIN_TRY
1905   id ch=(id)hwnd;
1906   if ([ch isKindOfClass:[NSWindow class]]) ch=[((NSWindow *)ch) contentView];
1907   if (!ch || ![ch isKindOfClass:[NSView class]]) return;
1908   ch=NavigateUpScrollClipViews(ch);
1909   
1910   NSRect b=[ch bounds];
1911   r->left=(int)(b.origin.x);
1912   r->top=(int)(b.origin.y);
1913   r->right = (int)(b.origin.x+b.size.width+0.5);
1914   r->bottom= (int)(b.origin.y+b.size.height+0.5);
1916   // todo this may need more attention
1917   NCCALCSIZE_PARAMS tr={{*r,},};
1918   SendMessage(hwnd,WM_NCCALCSIZE,FALSE,(LPARAM)&tr);
1919   r->right = r->left + (tr.rgrc[0].right-tr.rgrc[0].left);
1920   r->bottom = r->top + (tr.rgrc[0].bottom-tr.rgrc[0].top);
1921   SWELL_END_TRY(;)
1926 void SetWindowPos(HWND hwnd, HWND hwndAfter, int x, int y, int cx, int cy, int flags)
1928   if (!hwnd) return;
1930   SWELL_BEGIN_TRY
1931   NSWindow *nswnd; // content views = move window
1932   if (hwnd && [(id)hwnd isKindOfClass:[NSView class]] && (nswnd=[(NSView *)hwnd window]) && [nswnd contentView]==(id)hwnd)
1933     hwnd=(HWND)nswnd;
1935  // todo: handle SWP_SHOWWINDOW
1936   id ch=(id)hwnd;
1937   bool isview=false;
1938   if ([ch isKindOfClass:[NSWindow class]] || (isview=[ch isKindOfClass:[NSView class]])) 
1939   {
1940     if (isview)
1941     {
1942       ch=NavigateUpScrollClipViews(ch);
1943       if (isview && !(flags&SWP_NOZORDER))
1944       {
1945         NSView *v = (NSView *)ch;
1946         NSView *par = [v superview];
1947         NSArray *subs = [par subviews];
1948         NSInteger idx = [subs indexOfObjectIdenticalTo:v], cnt=[subs count];
1949         
1950         NSView *viewafter = NULL;            
1951         NSWindowOrderingMode omode = NSWindowAbove;
1952         
1953         if (cnt>1 && hwndAfter != (HWND)ch)
1954         {
1955           if (hwndAfter==HWND_TOPMOST||hwndAfter==HWND_NOTOPMOST)
1956           {
1957           }
1958           else if (hwndAfter == HWND_TOP)
1959           {
1960             if (idx<cnt-1) viewafter = [subs objectAtIndex:cnt-1];
1961           }
1962           else if (hwndAfter == HWND_BOTTOM)
1963           {
1964             if (idx>0) viewafter = [subs objectAtIndex:0];
1965             omode = NSWindowBelow;
1966           }
1967           else 
1968           {
1969             NSInteger a=[subs indexOfObjectIdenticalTo:(NSView *)hwndAfter];
1970             if (a != NSNotFound && a != (idx-1)) viewafter = (NSView *)hwndAfter;
1971           }
1972         }
1973         
1974         if (viewafter)
1975         { 
1976           HWND h = GetCapture();
1977           if (!h || (h!=(HWND)v && !IsChild((HWND)v,h))) // if this window is captured don't reorder!
1978           {
1979             NSView *oldfoc = (NSView*)[[v window] firstResponder];
1980             if (!oldfoc || ![oldfoc isKindOfClass:[NSView class]] || 
1981                 (oldfoc != v && ![oldfoc isDescendantOf:v])) oldfoc=NULL;
1982           
1983             // better way to do this? maybe :/
1984             [v retain];
1985             [v removeFromSuperviewWithoutNeedingDisplay];
1986             [par addSubview:v positioned:omode relativeTo:viewafter];
1987             [v release];
1988           
1989             if (oldfoc) [[v window] makeFirstResponder:oldfoc];
1990           }
1991         }
1992       }
1993     }    
1994     NSRect f=[ch frame];
1995     bool repos=false;
1996     if (!(flags&SWP_NOMOVE))
1997     {
1998       f.origin.x=(float)x;
1999       f.origin.y=(float)y;
2000       repos=true;
2001     }
2002     if (!(flags&SWP_NOSIZE))
2003     {
2004       f.size.width=(float)cx;
2005       f.size.height=(float)cy;
2006       if (f.size.height<0)f.size.height=-f.size.height;
2007       repos=true;
2008     }
2009     if (repos)
2010     {
2011       if (!isview)
2012       {
2013         NSSize mins=[ch minSize];
2014         NSSize maxs=[ch maxSize];
2015         if (f.size.width  < mins.width) f.size.width=mins.width;
2016         else if (f.size.width > maxs.width) f.size.width=maxs.width;
2017         if (f.size.height < mins.height) f.size.height=mins.height;
2018         else if (f.size.height> maxs.height) f.size.height=maxs.height;
2019         [ch setFrame:f display:NO];
2020         [ch display];
2021       }
2022       else
2023       {
2024         // this doesnt seem to actually be a good idea anymore
2025   //      if ([[ch window] contentView] != ch && ![[ch superview] isFlipped])
2026 //          f.origin.y -= f.size.height;
2027         [ch setFrame:f];
2028         if ([ch isKindOfClass:[NSScrollView class]])
2029         {
2030           NSView *cv=[ch documentView];
2031           if (cv && [cv isKindOfClass:[NSTextView class]])
2032           {
2033             NSRect fr=[cv frame];
2034             NSSize sz=[ch contentSize];
2035             int a=0;
2036             if (![ch hasHorizontalScroller]) {a ++; fr.size.width=sz.width; }
2037             if (![ch hasVerticalScroller]) { a++; fr.size.height=sz.height; }
2038             if (a) [cv setFrame:fr];
2039           }
2040         }
2041       }
2042     }    
2043     return;
2044   }  
2045   SWELL_END_TRY(;)  
2048 BOOL EnumWindows(BOOL (*proc)(HWND, LPARAM), LPARAM lp)
2050   NSArray *ch=[NSApp windows];
2051   [ch retain];
2052   const NSInteger n=[ch count];
2053   for(NSInteger x=0;x<n; x ++)
2054   {
2055     NSWindow *w = [ch objectAtIndex:x];
2056     if (!proc((HWND)[w contentView],lp)) 
2057     {
2058       [ch release];
2059       return FALSE;
2060     }
2061   }
2062   [ch release];
2063   return TRUE;
2067 HWND GetWindow(HWND hwnd, int what)
2069   if (!hwnd) return 0;
2070   SWELL_BEGIN_TRY
2072   if ([(id)hwnd isKindOfClass:[NSWindow class]]) hwnd=(HWND)[(id)hwnd contentView];
2073   if (!hwnd || ![(id)hwnd isKindOfClass:[NSView class]]) return 0;
2074   
2075   NSView *v=(NSView *)hwnd;
2076   if (what == GW_CHILD)
2077   {
2078     NSArray *ar=[v subviews];
2079     if (ar && [ar count]>0)
2080     {
2081       return (HWND)[ar objectAtIndex:0];
2082     }
2083     return 0;
2084   }
2085   if (what == GW_OWNER)
2086   {
2087     v=NavigateUpScrollClipViews(v);
2088     if ([[v window] contentView] == v)
2089     {
2090       if ([[v window] respondsToSelector:@selector(swellGetOwner)])
2091       {
2092         return (HWND)[(SWELL_ModelessWindow*)[v window] swellGetOwner];
2093       }
2094       return 0;
2095     }
2096     return (HWND)[v superview];
2097   }
2098   
2099   if (what >= GW_HWNDFIRST && what <= GW_HWNDPREV)
2100   {
2101     v=NavigateUpScrollClipViews(v);
2102     if ([[v window] contentView] == v)
2103     {
2104       if (what <= GW_HWNDLAST) return (HWND)hwnd; // content view is only window
2105       
2106       return 0; // we're the content view so cant do next/prev
2107     }
2108     NSView *par=[v superview];
2109     if (par)
2110     {
2111       NSArray *ar=[par subviews];
2112       NSInteger cnt;
2113       if (ar && (cnt=[ar count]) > 0)
2114       {
2115         if (what == GW_HWNDFIRST)
2116           return (HWND)[ar objectAtIndex:0];
2117         if (what == GW_HWNDLAST)
2118           return (HWND)[ar objectAtIndex:(cnt-1)];
2119         
2120         NSInteger idx=[ar indexOfObjectIdenticalTo:v];
2121         if (idx == NSNotFound) return 0;
2123         if (what==GW_HWNDNEXT) idx++;
2124         else if (what==GW_HWNDPREV) idx--;
2125         
2126         if (idx<0 || idx>=cnt) return 0;
2127         
2128         return (HWND)[ar objectAtIndex:idx];
2129       }
2130     }
2131     return 0;
2132   }
2133   SWELL_END_TRY(;)
2134   return 0;
2138 HWND GetParent(HWND hwnd)
2139 {  
2140   SWELL_BEGIN_TRY
2141   if (hwnd && [(id)hwnd isKindOfClass:[NSView class]])
2142   {
2143     hwnd=(HWND)NavigateUpScrollClipViews((NSView *)hwnd);
2145     NSView *cv=[[(NSView *)hwnd window] contentView];
2146     if (cv == (NSView *)hwnd) hwnd=(HWND)[(NSView *)hwnd window]; // passthrough to get window parent
2147     else
2148     {
2149       HWND h=(HWND)[(NSView *)hwnd superview];
2150       return h;
2151     }
2152   }
2153   
2154   if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]]) 
2155   {
2156     HWND h= (HWND)[(NSWindow *)hwnd parentWindow];
2157     if (h) h=(HWND)[(NSWindow *)h contentView];
2158     if (h) return h;
2159   }
2160   
2161   if (hwnd && [(id)hwnd respondsToSelector:@selector(swellGetOwner)])
2162   {
2163     HWND h= (HWND)[(SWELL_ModelessWindow *)hwnd swellGetOwner];
2164     if (h && [(id)h isKindOfClass:[NSWindow class]]) h=(HWND)[(NSWindow *)h contentView];
2165     return h;  
2166   }
2167   
2168   SWELL_END_TRY(;)
2169   return 0;
2172 HWND SetParent(HWND hwnd, HWND newPar)
2174   SWELL_BEGIN_TRY
2175   NSView *v=(NSView *)hwnd;
2176   if (!v || ![(id)v isKindOfClass:[NSView class]]) return 0;
2177   v=NavigateUpScrollClipViews(v);
2178   
2179   if ([(id)hwnd isKindOfClass:[NSView class]])
2180   {
2181     NSView *tv=(NSView *)hwnd;
2182     if ([[tv window] contentView] == tv) // if we're reparenting a contentview (aka top level window)
2183     {
2184       if (!newPar) return NULL;
2185     
2186       NSView *npv = (NSView *)newPar;
2187       if ([npv isKindOfClass:[NSWindow class]]) npv=[(NSWindow *)npv contentView];
2188       if (!npv || ![npv isKindOfClass:[NSView class]])
2189         return NULL;
2190     
2191       char oldtitle[2048];
2192       oldtitle[0]=0;
2193       GetWindowText(hwnd,oldtitle,sizeof(oldtitle));
2194     
2195       NSWindow *oldwnd = [tv window];
2196       id oldown = NULL;
2197       if ([oldwnd respondsToSelector:@selector(swellGetOwner)]) oldown=[(SWELL_ModelessWindow*)oldwnd swellGetOwner];
2199       if ([tv isKindOfClass:[SWELL_hwndChild class]]) ((SWELL_hwndChild*)tv)->m_lastTopLevelOwner = oldown;
2200     
2201       [tv retain];
2202       SWELL_hwndChild *tmpview = [[SWELL_hwndChild alloc] initChild:nil Parent:(NSView *)oldwnd dlgProc:nil Param:0];          
2203       [tmpview release];
2204     
2205       [npv addSubview:tv];  
2206       [tv release];
2207     
2208       DestroyWindow((HWND)oldwnd); // close old window since its no longer used
2209       if (oldtitle[0]) SetWindowText(hwnd,oldtitle);
2210       return (HWND)npv;
2211     }
2212     else if (!newPar) // not content view, not parent (so making it a top level modeless dialog)
2213     {
2214       char oldtitle[2048];
2215       oldtitle[0]=0;
2216       GetWindowText(hwnd,oldtitle,sizeof(oldtitle));
2217       
2218       [tv retain];
2219       [tv removeFromSuperview];
2221     
2222       unsigned int wf=(NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask|NSResizableWindowMask);
2223       if ([tv respondsToSelector:@selector(swellCreateWindowFlags)])
2224         wf=(unsigned int)[(SWELL_hwndChild *)tv swellCreateWindowFlags];
2226       HWND newOwner=NULL;
2227       if ([tv isKindOfClass:[SWELL_hwndChild class]])
2228       {
2229          id oldown = ((SWELL_hwndChild*)tv)->m_lastTopLevelOwner;
2230          if (oldown)
2231          {
2232            NSArray *ch=[NSApp windows];
2233            const NSInteger n = [ch count];
2234            for(NSInteger x=0;x<n && !newOwner; x ++)
2235            {
2236              NSWindow *w = [ch objectAtIndex:x];
2237              if (w == (NSWindow *)oldown || [w contentView] == (NSView *)oldown) newOwner = (HWND)w;
2238            }
2239          }
2240       }
2242       HWND SWELL_CreateModelessFrameForWindow(HWND childW, HWND ownerW, unsigned int);
2243       HWND bla=SWELL_CreateModelessFrameForWindow((HWND)tv,(HWND)newOwner,wf);
2244       // create a new modeless frame 
2246      
2247       
2248       [(NSWindow *)bla display];
2249       
2250       [tv release];
2251       
2252       if (oldtitle[0]) SetWindowText(hwnd,oldtitle);
2253       
2254       return NULL;
2255       
2256     }
2257   }
2258   HWND ret=(HWND) [v superview];
2259   if (ret) 
2260   {
2261     [v retain];
2262     [v removeFromSuperview];
2263   }
2264   NSView *np=(NSView *)newPar;
2265   if (np && [np isKindOfClass:[NSWindow class]]) np=[(NSWindow *)np contentView];
2266   
2267   if (np && [np isKindOfClass:[NSView class]])
2268   {
2269     [np addSubview:v];
2270     [v release];
2271   }
2272   return ret;
2273   SWELL_END_TRY(;)
2274   return NULL;
2278 int IsChild(HWND hwndParent, HWND hwndChild)
2280   if (!hwndParent || !hwndChild || hwndParent == hwndChild) return 0;
2281   SWELL_BEGIN_TRY
2282   id par=(id)hwndParent;
2283   id ch=(id)hwndChild;
2284   if (![ch isKindOfClass:[NSView class]]) return 0;
2285   if ([par isKindOfClass:[NSWindow class]])
2286   {
2287     return [ch window] == par;
2288   }
2289   else if ([par isKindOfClass:[NSView class]])
2290   {
2291     return !![ch isDescendantOf:par];
2292   }
2293   SWELL_END_TRY(;)
2294   return 0;
2297 HWND GetForegroundWindow()
2299   SWELL_BEGIN_TRY
2300   NSWindow *window=[NSApp keyWindow];
2301   if (!window) return 0;
2302   id ret=[window firstResponder];
2303   if (ret && [ret isKindOfClass:[NSView class]]) 
2304   {
2305 //    if (ret == [window contentView]) return (HWND) window;
2306     return (HWND) ret;
2307   }
2308   return (HWND)window;
2309   SWELL_END_TRY(;)
2310   return NULL;
2313 HWND GetFocus()
2315   SWELL_BEGIN_TRY
2316   NSWindow *window=[NSApp keyWindow];
2317   if (!window) return 0;
2318   id ret=[window firstResponder];
2319   if (ret && [ret isKindOfClass:[NSView class]]) 
2320   {
2321 //    if (ret == [window contentView]) return (HWND) window;
2323     if ([ret isKindOfClass:[NSTextView class]] && [ret superview] && [[ret superview] superview])
2324     {
2325       NSView* v = [[ret superview] superview];
2326       if ([v isKindOfClass:[NSTextField class]]) return (HWND) v;
2327     }
2329     return (HWND) ret;
2330   }
2331   SWELL_END_TRY(;)
2332   return 0;
2335 bool IsEquivalentTextView(HWND h1, HWND h2)
2337   if (!h1 || !h2) return false;
2338   if (h1 == h2) return true;
2339   SWELL_BEGIN_TRY
2340   NSView* v1 = (NSView*)h1;
2341   NSView* v2 = (NSView*)h2;
2342   if ([v1 isKindOfClass:[NSTextField class]] && [v2 isKindOfClass:[NSTextView class]])
2343   {
2344     NSView* t = v1;
2345     v1 = v2;
2346     v2 = t;
2347   }
2348   if ([v1 isKindOfClass: [NSTextView class]] && [v2 isKindOfClass:[NSTextField class]])
2349   {
2350     if ([v1 superview] && [[v1 superview] superview] && [[[v1 superview] superview] superview] == v2) return true;
2351   }
2352   SWELL_END_TRY(;)
2353   return false;
2355   
2358 BOOL SetDlgItemText(HWND hwnd, int idx, const char *text)
2360   NSView *obj=(NSView *)(idx ? GetDlgItem(hwnd,idx) : hwnd);
2361   if (!obj) return false;
2362   
2363   SWELL_BEGIN_TRY
2364   NSWindow *nswnd;
2365   if ([(id)obj isKindOfClass:[NSView class]] && (nswnd=[(NSView *)obj window]) && [nswnd contentView]==(id)obj)
2366   {
2367     SetDlgItemText((HWND)nswnd,0,text); // also set window if setting content view
2368   }
2369   
2370   if ([obj respondsToSelector:@selector(onSwellSetText:)])
2371   {
2372     [(SWELL_hwndChild*)obj onSwellSetText:text];
2373     return TRUE;
2374   }
2375   
2376   BOOL rv=TRUE;  
2377   NSString *lbl=(NSString *)SWELL_CStringToCFString(text);
2378   if ([obj isKindOfClass:[NSWindow class]] || [obj isKindOfClass:[NSButton class]]) [(NSButton*)obj setTitle:lbl];
2379   else if ([obj isKindOfClass:[NSControl class]]) 
2380   {
2381     [(NSControl*)obj setStringValue:lbl];
2382     if ([obj isKindOfClass:[NSTextField class]] && [(NSTextField *)obj isEditable])
2383     {
2384       SendMessage(GetParent((HWND)obj),WM_COMMAND,[(NSControl *)obj tag]|(EN_CHANGE<<16),(LPARAM)obj);
2385     }
2386   }
2387   else if ([obj isKindOfClass:[NSText class]])  
2388   {
2389     // todo if there is a way to find out that the window's NSTextField is already assigned 
2390     // to another field, restore the assignment afterwards
2391     [(NSText*)obj setString:lbl];
2392     [obj setNeedsDisplay:YES]; // required on Sierra, it seems -- if the parent is hidden (e.g. DialogBox() + WM_INITDIALOG), the view is not drawn
2393   }
2394   else if ([obj isKindOfClass:[NSBox class]])
2395   {
2396     [(NSBox *)obj setTitle:lbl];
2397   }
2398   else
2399   {
2400     rv=FALSE;
2401   }
2402   
2403   [lbl release];
2404   return rv;
2405   SWELL_END_TRY(;)
2406   return FALSE;
2409 BOOL GetDlgItemText(HWND hwnd, int idx, char *text, int textlen)
2411   *text=0;
2412   NSView *pvw=(NSView *)(idx?GetDlgItem(hwnd,idx) : hwnd);
2413   if (!pvw) return false;
2415   SWELL_BEGIN_TRY
2416   
2417   if ([(id)pvw isKindOfClass:[NSView class]] && [[(id)pvw window] contentView] == pvw)
2418   {
2419     pvw=(NSView *)[(id)pvw window];
2420   }
2421   
2422   if ([(id)pvw respondsToSelector:@selector(onSwellGetText)])
2423   {  
2424     const char *p=(const char *)[(SWELL_hwndChild*)pvw onSwellGetText];
2425     lstrcpyn_safe(text,p?p:"",textlen);
2426     return TRUE;
2427   }
2428   
2429   NSString *s;
2430   
2431   if ([pvw isKindOfClass:[NSButton class]]||[pvw isKindOfClass:[NSWindow class]]) s=[((NSButton *)pvw) title];
2432   else if ([pvw isKindOfClass:[NSControl class]]) s=[((NSControl *)pvw) stringValue];
2433   else if ([pvw isKindOfClass:[NSText class]])  s=[(NSText*)pvw string];
2434   else if ([pvw isKindOfClass:[NSBox class]]) s=[(NSBox *)pvw title];
2435   else return FALSE;
2436   
2437   if (s) SWELL_CFStringToCString(s,text,textlen);
2438 //    [s getCString:text maxLength:textlen];
2439     
2440   return !!s;
2441   SWELL_END_TRY(;)
2442   return FALSE;
2445 void CheckDlgButton(HWND hwnd, int idx, int check)
2447   NSView *pvw=(NSView *)GetDlgItem(hwnd,idx);
2448   if (!pvw) return;
2449   if ([pvw isKindOfClass:[NSButton class]]) 
2450     [(NSButton*)pvw setState:(check&BST_INDETERMINATE)?NSMixedState:((check&BST_CHECKED)?NSOnState:NSOffState)];
2454 int IsDlgButtonChecked(HWND hwnd, int idx)
2456   NSView *pvw=(NSView *)GetDlgItem(hwnd,idx);
2457   if (pvw && [pvw isKindOfClass:[NSButton class]])
2458   {
2459     NSInteger a=[(NSButton*)pvw state];
2460     if (a==NSMixedState) return BST_INDETERMINATE;
2461     return a!=NSOffState;
2462   }
2463   return 0;
2466 void SWELL_TB_SetPos(HWND hwnd, int idx, int pos)
2468   NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2469   if (p  && [p isKindOfClass:[NSSlider class]]) 
2470   {
2471     [p setDoubleValue:(double)pos];
2472   }
2473   else 
2474   {
2475     sendSwellMessage(p,TBM_SETPOS,1,pos); 
2476   }
2479 void SWELL_TB_SetRange(HWND hwnd, int idx, int low, int hi)
2481   NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2482   if (p && [p isKindOfClass:[NSSlider class]])
2483   {
2484     [p setMinValue:low];
2485     [p setMaxValue:hi];
2486   }
2487   else 
2488   {
2489     sendSwellMessage(p,TBM_SETRANGE,1,((low&0xffff)|(hi<<16)));
2490   }
2491   
2494 int SWELL_TB_GetPos(HWND hwnd, int idx)
2496   NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2497   if (p && [p isKindOfClass:[NSSlider class]]) 
2498   {
2499     return (int) ([p doubleValue]+0.5);
2500   }
2501   else 
2502   {
2503     return (int) sendSwellMessage(p,TBM_GETPOS,0,0);
2504   }
2505   return 0;
2508 void SWELL_TB_SetTic(HWND hwnd, int idx, int pos)
2510   NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2511   sendSwellMessage(p,TBM_SETTIC,0,pos);
2514 void SWELL_CB_DeleteString(HWND hwnd, int idx, int wh)
2516   NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2517   if (!p) return;
2518   if ([p isKindOfClass:[SWELL_ComboBox class]])
2519   {
2520     if (wh>=0 && wh<[p numberOfItems])
2521     {
2522       [p removeItemAtIndex:wh];
2523       if (((SWELL_ComboBox*)p)->m_ids) ((SWELL_ComboBox*)p)->m_ids->Delete(wh);
2524     }
2525   }
2526   else if ( [p isKindOfClass:[NSPopUpButton class]])
2527   {
2528     NSMenu *menu = [p menu];
2529     if (menu)
2530     {
2531       if (wh >= 0 && wh < [menu numberOfItems])
2532         [menu removeItemAtIndex:wh];
2533     }
2534   }
2538 int SWELL_CB_FindString(HWND hwnd, int idx, int startAfter, const char *str, bool exact)
2540   NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);  
2541   if (!p) return 0;
2542   
2543   int pos = startAfter;
2544   if (pos<0)pos=0;
2545   else pos++;
2546   
2547   const size_t l1len = strlen(str);
2548   const int ni=(int)[p numberOfItems];
2549   
2550   if ([p isKindOfClass:[NSComboBox class]])
2551   {
2552     for(;pos<ni;pos++)
2553     {
2554       NSString *s=[p itemObjectValueAtIndex:pos];
2555       if (s)
2556       {
2557         char buf[4096];
2558         SWELL_CFStringToCString(s,buf,sizeof(buf));
2559         if (exact ? !stricmp(str,buf) : !strnicmp(str,buf,l1len))
2560           return pos;
2561       }
2562     }
2563   }
2564   else 
2565   {
2566     for(;pos<ni;pos++)
2567     {
2568       NSMenuItem *i=[(NSPopUpButton *)p itemAtIndex:pos];
2569       if (i)
2570       {
2571         NSString *s=[i title];
2572         if (s)          
2573         {
2574           char buf[4096];
2575           SWELL_CFStringToCString(s,buf,sizeof(buf));
2576           if (exact ? !stricmp(str,buf) : !strnicmp(str,buf,l1len))
2577             return pos;
2578         }
2579       }
2580     }
2581   }
2582   return -1;
2585 int SWELL_CB_GetItemText(HWND hwnd, int idx, int item, char *buf, int bufsz)
2587   NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2589   if (buf) *buf=0;
2590   if (!p) return CB_ERR;
2591   const int ni = (int)[p numberOfItems];
2592   if (item < 0 || item >= ni) return CB_ERR;
2593   
2594   if ([p isKindOfClass:[NSComboBox class]])
2595   {
2596     NSString *s=[p itemObjectValueAtIndex:item];
2597     if (s)
2598     {
2599       if (!buf) return (int) ([s lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 64);
2601       SWELL_CFStringToCString(s,buf,bufsz);
2602       return 1;
2603     }
2604   }
2605   else 
2606   {
2607     NSMenuItem *i=[(NSPopUpButton *)p itemAtIndex:item];
2608     if (i)
2609     {
2610       NSString *s=[i title];
2611       if (s)
2612       {
2613         if (!buf) return (int) ([s lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 64);
2615         SWELL_CFStringToCString(s,buf,bufsz);
2616         return 1;
2617       }
2618     }
2619   }
2620   return CB_ERR;
2624 int SWELL_CB_InsertString(HWND hwnd, int idx, int pos, const char *str)
2626   NSString *label=(NSString *)SWELL_CStringToCFString(str);
2627   NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2628   if (!p) return 0;
2629   
2630   bool isAppend=false;
2631   const int ni = (int)[p numberOfItems];
2632   if (pos == -1000) 
2633   {
2634     isAppend=true;
2635     pos=ni;
2636   }
2637   else if (pos < 0) pos=0;
2638   else if (pos > ni) pos=ni;
2639   
2640    
2641   if ([p isKindOfClass:[SWELL_ComboBox class]])
2642   {
2643     if (isAppend && (((int)[(SWELL_ComboBox*)p getSwellStyle]) & CBS_SORT))
2644     {
2645       pos=(int)arr_bsearch_mod(label,[p objectValues],_nsStringSearchProc);
2646     }
2647     
2648     if (pos==ni)
2649       [p addItemWithObjectValue:label];
2650     else
2651       [p insertItemWithObjectValue:label atIndex:pos];
2652   
2653     if (((SWELL_ComboBox*)p)->m_ids) ((SWELL_ComboBox*)p)->m_ids->Insert(pos,(char*)0);
2654     [p setNumberOfVisibleItems:(ni+1)];
2655   }
2656   else
2657   {
2658     NSMenu *menu = [(NSPopUpButton *)p menu];
2659     if (menu)
2660     {
2661       const bool needclearsel = [p indexOfSelectedItem] < 0;
2662       if (isAppend && [p respondsToSelector:@selector(getSwellStyle)] && (((int)[(SWELL_PopUpButton*)p getSwellStyle]) & CBS_SORT))
2663       {
2664         pos=(int)arr_bsearch_mod(label,[menu itemArray],_nsMenuSearchProc);
2665       }
2666       NSMenuItem *item=[menu insertItemWithTitle:label action:NULL keyEquivalent:@"" atIndex:pos];
2667       [item setEnabled:YES];      
2668       if (needclearsel) [(NSPopUpButton *)p selectItemAtIndex:-1];
2669     }
2670   }
2671   [label release];
2672   return pos;
2673   
2676 int SWELL_CB_AddString(HWND hwnd, int idx, const char *str)
2678   return SWELL_CB_InsertString(hwnd,idx,-1000,str);
2681 int SWELL_CB_GetCurSel(HWND hwnd, int idx)
2683   NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2684   if (!p) return -1;
2685   return (int)[p indexOfSelectedItem];
2688 void SWELL_CB_SetCurSel(HWND hwnd, int idx, int item)
2690   NSComboBox *cb = (NSComboBox *)GetDlgItem(hwnd,idx);
2691   if (!cb) return;
2693   if (item < 0 || item >= [cb numberOfItems])
2694   {
2695     // combo boxes can be NSComboBox or NSPopupButton, NSComboBox needs
2696     // a different deselect method (selectItemAtIndex:-1 throws an exception)
2697     if ([cb isKindOfClass:[NSComboBox class]])
2698     {
2699       const NSInteger sel = [cb indexOfSelectedItem];
2700       if (sel>=0) [cb deselectItemAtIndex:sel];
2701     }
2702     else if ([cb isKindOfClass:[NSPopUpButton class]])
2703       [(NSPopUpButton*)cb selectItemAtIndex:-1];
2704   }
2705   else
2706     [cb selectItemAtIndex:item];
2709 int SWELL_CB_GetNumItems(HWND hwnd, int idx)
2711   NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2712   if (!p) return 0;
2713   return (int)[p numberOfItems];
2718 void SWELL_CB_SetItemData(HWND hwnd, int idx, int item, LONG_PTR data)
2720   id cb=(id)GetDlgItem(hwnd,idx);
2721   if (!cb) return;
2723   if ([cb isKindOfClass:[NSPopUpButton class]])
2724   {
2725     if (item < 0 || item >= [cb numberOfItems]) return;
2726     NSMenuItem *it=[(NSPopUpButton*)cb itemAtIndex:item];
2727     if (!it) return;
2728   
2729     SWELL_DataHold *p=[[SWELL_DataHold alloc] initWithVal:(void *)data];  
2730     [it setRepresentedObject:p];
2731     [p release];
2732   }
2733   else if ([cb isKindOfClass:[SWELL_ComboBox class]])
2734   {
2735     if (item < 0 || item >= [cb numberOfItems]) return;
2736     if (((SWELL_ComboBox*)cb)->m_ids) ((SWELL_ComboBox*)cb)->m_ids->Set(item,(char*)data);
2737   }
2740 LONG_PTR SWELL_CB_GetItemData(HWND hwnd, int idx, int item)
2742   id cb=(id)GetDlgItem(hwnd,idx);
2743   if (!cb) return 0;
2744   if ([cb isKindOfClass:[NSPopUpButton class]])
2745   {
2746     if (item < 0 || item >= [cb numberOfItems]) return 0;
2747     NSMenuItem *it=[(NSPopUpButton*)cb itemAtIndex:item];
2748     if (!it) return 0;
2749     id p= [it representedObject];
2750     if (!p || ![p isKindOfClass:[SWELL_DataHold class]]) return 0;
2751     return (LONG_PTR) (void *)[p getValue];
2752   }
2753   else if ([cb isKindOfClass:[SWELL_ComboBox class]])
2754   {
2755     if (item < 0 || item >= [cb numberOfItems]) return 0;
2756     if (((SWELL_ComboBox*)cb)->m_ids) return (LONG_PTR) ((SWELL_ComboBox*)cb)->m_ids->Get(item);    
2757   }
2758   return 0;
2761 void SWELL_CB_Empty(HWND hwnd, int idx)
2763   id cb=(id)GetDlgItem(hwnd,idx);
2764   if (!cb) return;  
2765   if ([cb isKindOfClass:[NSPopUpButton class]] ||
2766       [cb isKindOfClass:[NSComboBox class]]) [cb removeAllItems];
2767   
2768   if ([cb isKindOfClass:[SWELL_ComboBox class]])
2769   {
2770     if (((SWELL_ComboBox*)cb)->m_ids) ((SWELL_ComboBox*)cb)->m_ids->Empty(); 
2771   }
2775 BOOL SetDlgItemInt(HWND hwnd, int idx, int val, int issigned)
2777   char buf[128];
2778   sprintf(buf,issigned?"%d":"%u",val);
2779   return SetDlgItemText(hwnd,idx,buf);
2782 int GetDlgItemInt(HWND hwnd, int idx, BOOL *translated, int issigned)
2784   char buf[128];
2785   if (!GetDlgItemText(hwnd,idx,buf,sizeof(buf)))
2786   {
2787     if (translated) *translated=0;
2788     return 0;
2789   }
2790   char *p=buf;
2791   while (*p == ' ' || *p == '\t') p++;
2792   int a=atoi(p);
2793   if ((a<0 && !issigned) || (!a && p[0] != '0')) { if (translated) *translated=0; return 0; }
2794   if (translated) *translated=1;
2795   return a;
2798 void SWELL_HideApp()
2800   [NSApp hide:NSApp];
2804 BOOL SWELL_GetGestureInfo(LPARAM lParam, GESTUREINFO* gi)
2806   if (!lParam || !gi) return FALSE;
2807   memcpy(gi, (GESTUREINFO*)lParam, sizeof(GESTUREINFO));
2808   return TRUE;
2810   
2812 void ShowWindow(HWND hwnd, int cmd)
2814   id pid=(id)hwnd;
2815   
2816   if (pid && [pid isKindOfClass:[NSWindow class]])
2817   {
2818     if (cmd == SW_SHOWNA && [pid isKindOfClass:[SWELL_ModelessWindow class]])
2819     {
2820       if (((SWELL_ModelessWindow *)pid)->m_wantInitialKeyWindowOnShow)
2821       {
2822         ((SWELL_ModelessWindow *)pid)->m_wantInitialKeyWindowOnShow=false;
2823         cmd = SW_SHOW;
2824       }
2825     }
2826     if (cmd==SW_SHOW)
2827     {
2828       [pid makeKeyAndOrderFront:pid];
2829     }
2830     else if (cmd==SW_SHOWNA)
2831     {
2832       [pid orderFront:pid];
2833     }
2834     else if (cmd==SW_HIDE)
2835     {
2836       [pid orderOut:pid];
2837     }
2838     else if (cmd == SW_SHOWMINIMIZED)
2839     {   
2840       // this ought to work
2841       //if ([NSApp mainWindow] == pid)
2842       //{
2843       //  [NSApp hide:pid];
2844       //}
2845       //else
2846       //{
2847         [pid miniaturize:pid];
2848       //}
2849     }
2850     return;
2851   }
2852   if (!pid || ![pid isKindOfClass:[NSView class]]) return;
2853   
2854   pid=NavigateUpScrollClipViews(pid);
2855   
2856   switch (cmd)
2857   {
2858     case SW_SHOW:
2859     case SW_SHOWNA:
2860       [((NSView *)pid) setHidden:NO];
2861     break;
2862     case SW_HIDE:
2863       {
2864         NSWindow *pw=[pid window];
2865         if (pw && [NSApp keyWindow] == pw)
2866         {
2867           id foc=[pw firstResponder];
2868           if (foc && (foc == pid || IsChild((HWND)pid,(HWND)foc)))
2869           {
2870             HWND h=GetParent((HWND)pid);
2871             if (h) SetFocus(h);
2872           }
2873         }
2874         if (![((NSView *)pid) isHidden])
2875         {
2876           if ((NSView *)pid != [pw contentView])
2877           {
2878             HWND par = (HWND) [(NSView *)pid superview];
2879             if (par)
2880             {
2881               RECT r;
2882               GetWindowRect((HWND)pid,&r);
2883               ScreenToClient(par,(LPPOINT)&r);
2884               ScreenToClient(par,((LPPOINT)&r)+1);
2885               InvalidateRect(par,&r,FALSE);
2886             }
2887           }
2888           [((NSView *)pid) setHidden:YES];
2889         }
2890     }
2891     break;
2892   }
2893   
2894   NSWindow *nswnd;
2895   if ((nswnd=[(NSView *)pid window]) && [nswnd contentView]==(id)pid)
2896   {
2897     ShowWindow((HWND)nswnd,cmd);
2898   }
2901 void *SWELL_ModalWindowStart(HWND hwnd)
2903   if (hwnd && [(id)hwnd isKindOfClass:[NSView class]]) hwnd=(HWND)[(NSView *)hwnd window];
2904   if (!hwnd) return 0;
2905   return (void *)[NSApp beginModalSessionForWindow:(NSWindow *)hwnd];
2908 bool SWELL_ModalWindowRun(void *ctx, int *ret) // returns false and puts retval in *ret when done
2910   if (!ctx) return false;
2911   NSInteger r=[NSApp runModalSession:(NSModalSession)ctx];
2912   if (r==NSRunContinuesResponse) return true;
2913   if (ret) *ret=(int)r;
2914   return false;
2917 void SWELL_ModalWindowEnd(void *ctx)
2919   if (ctx) 
2920   {
2921     if ([NSApp runModalSession:(NSModalSession)ctx] == NSRunContinuesResponse)
2922     {    
2923       [NSApp stopModal];
2924       while ([NSApp runModalSession:(NSModalSession)ctx]==NSRunContinuesResponse) Sleep(10);
2925     }
2926     [NSApp endModalSession:(NSModalSession)ctx];
2927   }
2930 void SWELL_CloseWindow(HWND hwnd)
2932   if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]])
2933   {
2934     [((NSWindow*)hwnd) close];
2935   }
2936   else if (hwnd && [(id)hwnd isKindOfClass:[NSView class]])
2937   {
2938     [[(NSView*)hwnd window] close];
2939   }
2943 #include "swell-dlggen.h"
2945 static id m_make_owner;
2946 static NSRect m_transform;
2947 static float m_parent_h;
2948 static bool m_doautoright;
2949 static NSRect m_lastdoauto;
2950 static bool m_sizetofits;
2951 static int m_make_radiogroupcnt;
2953 #define ACTIONTARGET (m_make_owner)
2955 void SWELL_MakeSetCurParms(float xscale, float yscale, float xtrans, float ytrans, HWND parent, bool doauto, bool dosizetofit)
2957   m_make_radiogroupcnt=0;
2958   m_sizetofits=dosizetofit;
2959   m_lastdoauto.origin.x = 0;
2960   m_lastdoauto.origin.y = -100;
2961   m_lastdoauto.size.width = 0;
2962   m_doautoright=doauto;
2963   m_transform.origin.x=xtrans;
2964   m_transform.origin.y=ytrans;
2965   m_transform.size.width=xscale;
2966   m_transform.size.height=yscale;
2967   m_make_owner=(id)parent;
2968   if ([m_make_owner isKindOfClass:[NSWindow class]]) m_make_owner=[(NSWindow *)m_make_owner contentView];
2969   m_parent_h=100.0;
2970   if ([(id)m_make_owner isKindOfClass:[NSView class]])
2971   {
2972     m_parent_h=[(NSView *)m_make_owner bounds].size.height;
2973     if (m_transform.size.height > 0 && [(id)parent isFlipped])
2974       m_transform.size.height*=-1;
2975   }
2978 static void UpdateAutoCoords(NSRect r)
2980   m_lastdoauto.size.width=r.origin.x + r.size.width - m_lastdoauto.origin.x;
2983 static NSRect MakeCoords(int x, int y, int w, int h, bool wantauto, bool ignorevscaleheight=false)
2985   if (w<0&&h<0)
2986   {
2987     return NSMakeRect(-x,-y,-w,-h);
2988   }
2989   float ysc=m_transform.size.height;
2990   float ysc2 = ignorevscaleheight ? 1.0 : ysc;
2991   int newx=(int)((x+m_transform.origin.x)*m_transform.size.width + 0.5);
2992   int newy=(int)((ysc >= 0.0 ? m_parent_h - ((y+m_transform.origin.y) )*ysc + h*ysc2 : 
2993                          ((y+m_transform.origin.y) )*-ysc) + 0.5);
2994                          
2995   NSRect ret= NSMakeRect(newx,  
2996                          newy,                  
2997                         (int) (w*m_transform.size.width+0.5),
2998                         (int) (h*fabs(ysc2)+0.5));
2999                         
3000   NSRect oret=ret;
3001   if (wantauto && m_doautoright)
3002   {
3003     float dx = ret.origin.x - m_lastdoauto.origin.x;
3004     if (fabs(dx)<32 && m_lastdoauto.origin.y >= ret.origin.y && m_lastdoauto.origin.y < ret.origin.y + ret.size.height)
3005     {
3006       ret.origin.x += (int) m_lastdoauto.size.width;
3007     }
3008     
3009     m_lastdoauto.origin.x = oret.origin.x + oret.size.width;
3010     m_lastdoauto.origin.y = ret.origin.y + ret.size.height*0.5;
3011     m_lastdoauto.size.width=0;
3012   }
3013   return ret;
3016 static const double minwidfontadjust=1.81;
3017 #define TRANSFORMFONTSIZE (m_transform.size.width<1?8:m_transform.size.width<2?10:12)
3018 /// these are for swell-dlggen.h
3019 HWND SWELL_MakeButton(int def, const char *label, int idx, int x, int y, int w, int h, int flags)
3020 {  
3021   UINT_PTR a=(UINT_PTR)label;
3022   if (a < 65536) label = "ICONTEMP";
3023   SWELL_Button *button=[[SWELL_Button alloc] init];
3024   if (flags & BS_BITMAP)
3025   {
3026     SWELL_ImageButtonCell * cell = [[SWELL_ImageButtonCell alloc] init];
3027     [button setCell:cell];
3028     [cell release];
3029   }
3030   
3031   if (m_transform.size.width < minwidfontadjust)
3032   {
3033     [button setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3034   }
3035   
3036   [button setTag:idx];
3037   if (g_swell_want_nice_style==1)
3038     [button setBezelStyle:NSShadowlessSquareBezelStyle ];
3039   else
3040     [button setBezelStyle:NSRoundedBezelStyle ];
3041   NSRect tr=MakeCoords(x,y,w,h,true);
3042   
3043   
3044   if (g_swell_want_nice_style!=1 && tr.size.height >= 18 && tr.size.height<24)
3045   {
3046     tr.size.height=24;
3047   }
3048   
3049   [button setFrame:tr];
3050   NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(label);
3051   [button setTitle:labelstr];
3052   [button setTarget:ACTIONTARGET];
3053   [button setAction:@selector(onSwellCommand:)];
3054   if (flags & BS_LEFT) [button setAlignment:NSLeftTextAlignment];
3055   if (flags&SWELL_NOT_WS_VISIBLE) [button setHidden:YES];
3056   [m_make_owner addSubview:button];
3057   if (m_doautoright) UpdateAutoCoords([button frame]);
3058   if (def) [[m_make_owner window] setDefaultButtonCell:(NSButtonCell*)button];
3059   [labelstr release];
3060   [button release];
3061   return (HWND) button;
3065 @implementation SWELL_TextView
3067 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
3069 -(NSInteger) tag
3071   return m_tag;
3074 -(void) setTag:(NSInteger)tag
3076   m_tag=tag;
3079 -(LRESULT)onSwellMessage:(UINT)msg p1:(WPARAM)wParam p2:(LPARAM)lParam
3081   switch (msg)
3082   {
3083     case EM_SCROLL:
3084       if (wParam == SB_TOP)
3085       {
3086         [self scrollRangeToVisible:NSMakeRange(0, 0)];
3087       }
3088       else if (wParam == SB_BOTTOM)
3089       {
3090         NSUInteger len = [[self string] length];
3091         [self scrollRangeToVisible:NSMakeRange(len, 0)];
3092       }
3093     return 0;
3094     
3095     case EM_SETSEL:    
3096     {
3097       NSUInteger sl =  [[self string] length];
3098       if (wParam == -1) lParam = wParam = 0;
3099       else if (lParam == -1) lParam = sl;
3100       
3101       if (wParam>sl)wParam=sl;
3102       if (lParam>sl)lParam=sl;
3103       [self setSelectedRange:NSMakeRange(wParam, lParam>wParam ? lParam-wParam : 0)];
3104     }
3105     return 0;
3106     
3107     case EM_GETSEL:
3108     {
3109       NSRange r = [self selectedRange];
3110       if (wParam) *(int*)wParam = (int)r.location;
3111       if (lParam) *(int*)lParam = (int)(r.location+r.length);
3112     }
3113     return 0;
3114       
3115     case WM_SETFONT:
3116     {
3117       HGDIOBJ__* obj = (HGDIOBJ__*)wParam;
3118       if (obj && obj->type == TYPE_FONT)
3119       {
3120         if (obj->ct_FontRef)
3121         {
3122           [self setFont:(NSFont *)obj->ct_FontRef];
3123         }
3124 #ifdef SWELL_ATSUI_TEXT_SUPPORT
3125         else if (obj->atsui_font_style)
3126         {
3127           ATSUFontID fontid = kATSUInvalidFontID;      
3128           Fixed fsize = 0;          
3129           Boolean isbold = NO;
3130           Boolean isital = NO;
3131           Boolean isunder = NO;          
3132           if (ATSUGetAttribute(obj->atsui_font_style, kATSUFontTag, sizeof(ATSUFontID), &fontid, 0) == noErr &&
3133               ATSUGetAttribute(obj->atsui_font_style, kATSUSizeTag, sizeof(Fixed), &fsize, 0) == noErr && fsize &&
3134               ATSUGetAttribute(obj->atsui_font_style, kATSUQDBoldfaceTag, sizeof(Boolean), &isbold, 0) == noErr && 
3135               ATSUGetAttribute(obj->atsui_font_style, kATSUQDItalicTag, sizeof(Boolean), &isital, 0) == noErr &&
3136               ATSUGetAttribute(obj->atsui_font_style, kATSUQDUnderlineTag, sizeof(Boolean), &isunder, 0) == noErr)
3137           {
3138             char name[255];
3139             name[0]=0;
3140             ByteCount namelen=0;
3141             if (ATSUFindFontName(fontid, kFontFullName, (FontPlatformCode)kFontNoPlatform, kFontNoScriptCode, kFontNoLanguageCode, sizeof(name), name, &namelen, 0) == noErr && name[0] && namelen)
3142             {
3143               namelen /= 2;
3144               int i;
3145               for (i = 0; i < namelen; ++i) name[i] = name[2*i];
3146               name[namelen]=0;
3148               // todo bold/ital/underline
3149               NSString* str = (NSString*)SWELL_CStringToCFString(name);
3150               CGFloat sz = Fix2Long(fsize);
3151               NSFont* font = [NSFont fontWithName:str size:sz];
3152               [str release];
3153               if (font) 
3154               {
3155                 [self setFont:font];
3156               }
3157             }
3158           }            
3159         }
3160 #endif
3161       }
3162     }
3163     return 0;
3164   }
3165   return 0;
3168 - (BOOL)becomeFirstResponder;
3170   BOOL didBecomeFirstResponder = [super becomeFirstResponder];
3171   if (didBecomeFirstResponder) SendMessage(GetParent((HWND)self),WM_COMMAND,[self tag]|(EN_SETFOCUS<<16),(LPARAM)self);
3172   return didBecomeFirstResponder;
3174 @end
3177 @implementation SWELL_TextField
3178 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
3180 - (BOOL)becomeFirstResponder;
3182   BOOL didBecomeFirstResponder = [super becomeFirstResponder];
3183   if (didBecomeFirstResponder) SendMessage(GetParent((HWND)self),WM_COMMAND,[self tag]|(EN_SETFOCUS<<16),(LPARAM)self);
3184   return didBecomeFirstResponder;
3186 @end
3190 HWND SWELL_MakeEditField(int idx, int x, int y, int w, int h, int flags)
3191 {  
3192   if ((flags&WS_VSCROLL) || (flags&WS_HSCROLL)) // || (flags & ES_READONLY))
3193   {
3194     SWELL_TextView *obj=[[SWELL_TextView alloc] init];
3195     [obj setEditable:(flags & ES_READONLY)?NO:YES];
3196     if (m_transform.size.width < minwidfontadjust)
3197       [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3198     [obj setTag:idx];
3199     [obj setDelegate:ACTIONTARGET];
3200   
3201     [obj setHorizontallyResizable:NO];
3202     
3203     if (flags & WS_VSCROLL)
3204     {
3205       NSRect fr=MakeCoords(x,y,w,h,true);
3206       
3207       [obj setVerticallyResizable:YES];
3208       NSScrollView *obj2=[[NSScrollView alloc] init];
3209       [obj2 setFrame:fr];
3210       if (flags&WS_VSCROLL) [obj2 setHasVerticalScroller:YES];
3211       if (flags&WS_HSCROLL) 
3212       {
3213         [obj2 setHasHorizontalScroller:YES];
3214         [obj setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
3215         [obj setHorizontallyResizable:YES];
3216         [[obj textContainer] setWidthTracksTextView:NO];
3217         [[obj textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];
3218       }
3219       [obj2 setAutohidesScrollers:YES];
3220       [obj2 setDrawsBackground:NO];
3221       [obj2 setDocumentView:obj];
3222       [m_make_owner addSubview:obj2];
3223       if (m_doautoright) UpdateAutoCoords([obj2 frame]);
3224       if (flags&SWELL_NOT_WS_VISIBLE) [obj2 setHidden:YES];
3225       [obj2 release];
3226       
3227       NSRect tr;
3228       memset(&tr,0,sizeof(tr));
3229       tr.size = [obj2 contentSize];
3230       [obj setFrame:tr];
3231       [obj release];
3232       
3233       return (HWND)obj2;
3234     }
3235     else
3236     {
3237       [obj setFrame:MakeCoords(x,y,w,h,true)];
3238       [obj setVerticallyResizable:NO];
3239       if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3240       [m_make_owner addSubview:obj];
3241       if (m_doautoright) UpdateAutoCoords([obj frame]);
3242       [obj release];
3243       return (HWND)obj;
3244     }  
3245   }  
3246   
3247   NSTextField *obj;
3248   
3249   if (flags & ES_PASSWORD) obj=[[NSSecureTextField alloc] init];
3250   else obj=[[SWELL_TextField alloc] init];
3251   [obj setEditable:(flags & ES_READONLY)?NO:YES];
3252   if (flags & ES_READONLY) [obj setSelectable:YES];
3253   if (m_transform.size.width < minwidfontadjust)
3254     [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3255   
3256   NSCell* cell = [obj cell];  
3257   if (flags&ES_CENTER) [cell setAlignment:NSCenterTextAlignment];
3258   else if (flags&ES_RIGHT) [cell setAlignment:NSRightTextAlignment];
3259   if (abs(h) < 20)
3260   {
3261     [cell setWraps:NO];
3262     [cell setScrollable:YES];
3263   }
3264   [obj setTag:idx];
3265   [obj setTarget:ACTIONTARGET];
3266   [obj setAction:@selector(onSwellCommand:)];
3267   [obj setDelegate:ACTIONTARGET];
3268   
3269   [obj setFrame:MakeCoords(x,y,w,h,true)];
3270   if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3271   [m_make_owner addSubview:obj];
3272   if (m_doautoright) UpdateAutoCoords([obj frame]);
3273   [obj release];
3275   return (HWND)obj;
3278 HWND SWELL_MakeLabel( int align, const char *label, int idx, int x, int y, int w, int h, int flags)
3280   NSTextField *obj=[[SWELL_TextField alloc] init];
3281   [obj setEditable:NO];
3282   [obj setSelectable:NO];
3283   [obj setBordered:NO];
3284   [obj setBezeled:NO];
3285   [obj setDrawsBackground:NO];
3286   if (m_transform.size.width < minwidfontadjust)
3287     [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3289   if (flags & SS_NOTIFY)
3290   {
3291     [obj setTarget:ACTIONTARGET];
3292     [obj setAction:@selector(onSwellCommand:)];
3293   }
3294   
3295   NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(label);
3296   [obj setStringValue:labelstr];
3297   [obj setAlignment:(align<0?NSLeftTextAlignment:align>0?NSRightTextAlignment:NSCenterTextAlignment)];
3298   
3299   [[obj cell] setWraps:(h>12 ? YES : NO)];
3300   
3301   [obj setTag:idx];
3302   [obj setFrame:MakeCoords(x,y,w,h,true)];
3303   if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3304   [m_make_owner addSubview:obj];
3305   if (m_sizetofits && strlen(label)>1)[obj sizeToFit];
3306   if (m_doautoright) UpdateAutoCoords([obj frame]);
3307   [obj release];
3308   [labelstr release];
3309   return (HWND)obj;
3313 HWND SWELL_MakeCheckBox(const char *name, int idx, int x, int y, int w, int h, int flags=0)
3315   return SWELL_MakeControl(name,idx,"Button",BS_AUTOCHECKBOX|flags,x,y,w,h,0);
3318 HWND SWELL_MakeListBox(int idx, int x, int y, int w, int h, int styles)
3320   HWND hw=SWELL_MakeControl("",idx,"SysListView32_LB",styles,x,y,w,h,0);
3321 /*  if (hw)
3322   {
3323     LVCOLUMN lvc={0,};
3324     RECT r;
3325     GetClientRect(hw,&r);
3326     lvc.cx=300;//yer.right-r.left;
3327     lvc.pszText="";
3328     ListView_InsertColumn(hw,0,&lvc);
3329   }
3330   */
3331   return hw;
3335 typedef struct ccprocrec
3337   SWELL_ControlCreatorProc proc;
3338   int cnt;
3339   struct ccprocrec *next;
3340 } ccprocrec;
3342 static ccprocrec *m_ccprocs;
3344 void SWELL_RegisterCustomControlCreator(SWELL_ControlCreatorProc proc)
3346   if (!proc) return;
3347   
3348   ccprocrec *p=m_ccprocs;
3349   while (p && p->next)
3350   {
3351     if (p->proc == proc)
3352     {
3353       p->cnt++;
3354       return;
3355     }
3356     p=p->next;
3357   }
3358   ccprocrec *ent = (ccprocrec*)malloc(sizeof(ccprocrec));
3359   ent->proc=proc;
3360   ent->cnt=1;
3361   ent->next=0;
3362   
3363   if (p) p->next=ent;
3364   else m_ccprocs=ent;
3367 void SWELL_UnregisterCustomControlCreator(SWELL_ControlCreatorProc proc)
3369   if (!proc) return;
3370   
3371   ccprocrec *lp=NULL;
3372   ccprocrec *p=m_ccprocs;
3373   while (p)
3374   {
3375     if (p->proc == proc)
3376     {
3377       if (--p->cnt <= 0)
3378       {
3379         if (lp) lp->next=p->next;
3380         else m_ccprocs=p->next;
3381         free(p);
3382       }
3383       return;
3384     }
3385     lp=p;
3386     p=p->next;
3387   }
3391 HWND SWELL_MakeControl(const char *cname, int idx, const char *classname, int style, int x, int y, int w, int h, int exstyle)
3393   if (m_ccprocs)
3394   {
3395     NSRect wcr=MakeCoords(x,y,w,h,false);
3396     ccprocrec *p=m_ccprocs;
3397     while (p)
3398     {
3399       HWND hwnd=p->proc((HWND)m_make_owner,cname,idx,classname,style,
3400           (int)(wcr.origin.x+0.5),(int)(wcr.origin.y+0.5),(int)(wcr.size.width+0.5),(int)(wcr.size.height+0.5));
3401       if (hwnd) 
3402       {
3403         if (exstyle) SetWindowLong(hwnd,GWL_EXSTYLE,exstyle);
3404         return hwnd;
3405       }
3406       p=p->next;
3407     }
3408   }
3409   if (!stricmp(classname,"SysTabControl32"))
3410   {
3411     SWELL_TabView *obj=[[SWELL_TabView alloc] init];
3412     if (1) // todo: only if on 10.4 maybe?
3413     {
3414       y-=1;
3415       h+=6;
3416     }
3417     [obj setTag:idx];
3418     [obj setDelegate:(id)obj];
3419     [obj setAllowsTruncatedLabels:YES];
3420     [obj setNotificationWindow:ACTIONTARGET];
3421     [obj setHidden:NO];
3422     [obj setFrame:MakeCoords(x,y,w,h,false)];
3423     if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3424     [m_make_owner addSubview:obj];
3425     SetAllowNoMiddleManRendering((HWND)m_make_owner,FALSE);
3426     [obj release];
3427     return (HWND)obj;
3428   }
3429   else if (!stricmp(classname, "SysListView32")||!stricmp(classname, "SysListView32_LB"))
3430   {
3431     SWELL_ListView *obj = [[SWELL_ListView alloc] init];
3432     [obj setColumnAutoresizingStyle:NSTableViewNoColumnAutoresizing];
3433     [obj setFocusRingType:NSFocusRingTypeNone];
3434     [obj setDataSource:(id)obj];
3435     obj->style=style;
3437     BOOL isLB=!stricmp(classname, "SysListView32_LB");
3438     [obj setSwellNotificationMode:isLB];
3439     
3440     if (isLB)
3441     {
3442       [obj setHeaderView:nil];
3443       [obj setAllowsMultipleSelection:!!(style & LBS_EXTENDEDSEL)];
3444     }
3445     else
3446     {
3447       if ((style & LVS_NOCOLUMNHEADER) || !(style & LVS_REPORT))  [obj setHeaderView:nil];
3448       [obj setAllowsMultipleSelection:!(style & LVS_SINGLESEL)];
3449     }
3450     [obj setAllowsColumnReordering:NO];
3451     [obj setAllowsEmptySelection:YES];
3452     [obj setTag:idx];
3453     [obj setHidden:NO];
3454     id target=ACTIONTARGET;
3455     [obj setDelegate:target];
3456     [obj setTarget:target];
3457     [obj setAction:@selector(onSwellCommand:)];
3458     if ([target respondsToSelector:@selector(swellOnControlDoubleClick:)])
3459     {
3460       [obj setDoubleAction:@selector(swellOnControlDoubleClick:)];
3461     }
3462     else
3463     {
3464       [obj setDoubleAction:@selector(onSwellCommand:)];
3465     }
3466     NSScrollView *obj2=[[NSScrollView alloc] init];
3467     NSRect tr=MakeCoords(x,y,w,h,false);
3468     [obj2 setFrame:tr];
3469     [obj2 setDocumentView:obj];
3470     [obj2 setHasVerticalScroller:YES];
3471     if (!isLB) [obj2 setHasHorizontalScroller:YES];
3472     [obj2 setAutohidesScrollers:YES];
3473     [obj2 setDrawsBackground:NO];
3474     [obj release];
3475     if (style&SWELL_NOT_WS_VISIBLE) [obj2 setHidden:YES];
3476     [m_make_owner addSubview:obj2];
3477     [obj2 release];
3478     
3479     if (isLB || !(style & LVS_REPORT))
3480     {
3481       LVCOLUMN lvc={0,};
3482       lvc.mask=LVCF_TEXT|LVCF_WIDTH;
3483       lvc.cx=(int)ceil(wdl_max(tr.size.width - 4.0,isLB ? 1200.0 : 300.0));
3484       lvc.pszText=(char*)"";
3485       ListView_InsertColumn((HWND)obj,0,&lvc);
3486       if (isLB && (style & LBS_OWNERDRAWFIXED))
3487       {
3488         NSArray *ar=[obj tableColumns];
3489         NSTableColumn *c;
3490         if (ar && [ar count] && (c=[ar objectAtIndex:0]))
3491         {
3492           SWELL_ODListViewCell *t=[[SWELL_ODListViewCell alloc] init];
3493           [c setDataCell:t];
3494           [t setOwnerControl:obj];
3495           [t release];
3496         }
3497       }
3498     }
3499     
3500     return (HWND)obj;
3501   }
3502   else if (!stricmp(classname, "SysTreeView32"))
3503   {
3504     SWELL_TreeView *obj = [[SWELL_TreeView alloc] init];
3505     [obj setFocusRingType:NSFocusRingTypeNone];
3506     [obj setDataSource:(id)obj];
3507     obj->style=style;
3508     id target=ACTIONTARGET;
3509     [obj setHeaderView:nil];    
3510     [obj setDelegate:target];
3511     [obj setAllowsColumnReordering:NO];
3512     [obj setAllowsMultipleSelection:NO];
3513     [obj setAllowsEmptySelection:YES];
3514     [obj setTag:idx];
3515     [obj setHidden:NO];
3516     [obj setTarget:target];
3517     [obj setAction:@selector(onSwellCommand:)];
3518     if ([target respondsToSelector:@selector(swellOnControlDoubleClick:)])
3519       [obj setDoubleAction:@selector(swellOnControlDoubleClick:)];
3520     else
3521       [obj setDoubleAction:@selector(onSwellCommand:)];
3522     NSScrollView *obj2=[[NSScrollView alloc] init];
3523     NSRect tr=MakeCoords(x,y,w,h,false);
3524     [obj2 setFrame:tr];
3525     [obj2 setDocumentView:obj];
3526     [obj2 setHasVerticalScroller:YES];
3527     [obj2 setAutohidesScrollers:YES];
3528     [obj2 setDrawsBackground:NO];
3529     [obj release];
3530     if (style&SWELL_NOT_WS_VISIBLE) [obj2 setHidden:YES];
3531     [m_make_owner addSubview:obj2];
3532     [obj2 release];
3534     {
3535       NSTableColumn *col=[[NSTableColumn alloc] init];
3536       SWELL_ListViewCell *cell = [[SWELL_ListViewCell alloc] initTextCell:@""];
3537       [col setDataCell:cell];
3538       [cell release];
3540       [col setWidth:(int)ceil(wdl_max(tr.size.width,300.0))];
3541       [col setEditable:NO];
3542       [[col dataCell] setWraps:NO];     
3543       [obj addTableColumn:col];
3544       [obj setOutlineTableColumn:col];
3546       [col release];
3547     }
3548 ///    [obj setIndentationPerLevel:10.0];
3549     
3550     return (HWND)obj;
3551   }
3552   else if (!stricmp(classname, "msctls_progress32"))
3553   {
3554     SWELL_ProgressView *obj=[[SWELL_ProgressView alloc] init];
3555     [obj setStyle:NSProgressIndicatorBarStyle];
3556     [obj setIndeterminate:NO];
3557     [obj setTag:idx];
3558     [obj setFrame:MakeCoords(x,y,w,h,false)];
3559     if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3560     [m_make_owner addSubview:obj];
3561     [obj release];
3562     return (HWND)obj;
3563   }
3564   else if (!stricmp(classname,"Edit"))
3565   {
3566     return SWELL_MakeEditField(idx,x,y,w,h,style);
3567   }
3568   else if (!stricmp(classname, "static"))
3569   {
3570     NSTextField *obj=[[SWELL_TextField alloc] init];
3571     [obj setEditable:NO];
3572     [obj setSelectable:NO];
3573     [obj setBordered:NO];
3574     [obj setBezeled:NO];
3575     [obj setDrawsBackground:NO];
3576     if (m_transform.size.width < minwidfontadjust)
3577       [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3579     if (cname && *cname)
3580     {
3581       NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(cname);
3582       [obj setStringValue:labelstr];
3583       [labelstr release];
3584     }
3585     
3586     if ((style&SS_TYPEMASK) == SS_LEFTNOWORDWRAP) [[obj cell] setWraps:NO];
3587     else if ((style&SS_TYPEMASK) == SS_CENTER) [[obj cell] setAlignment:NSCenterTextAlignment];
3588     else if ((style&SS_TYPEMASK) == SS_RIGHT) [[obj cell] setAlignment:NSRightTextAlignment];
3590     [obj setTag:idx];
3591     [obj setFrame:MakeCoords(x,y,w,h,true)];
3592     if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3593     [m_make_owner addSubview:obj];
3594     if ((style & SS_TYPEMASK) == SS_BLACKRECT)
3595     {
3596       [obj setHidden:YES];
3597     }
3598     [obj release];
3599     return (HWND)obj;
3600   }
3601   else if (!stricmp(classname,"Button"))
3602   {
3603     if (style & BS_GROUPBOX)
3604     {
3605       return SWELL_MakeGroupBox(cname, idx, x, y, w, h, style &~BS_GROUPBOX);
3606     }
3607     if (style & BS_DEFPUSHBUTTON)
3608     {
3609        return SWELL_MakeButton(1, cname, idx, x,y,w,h,style &~BS_DEFPUSHBUTTON);
3610     }
3611     if (style & BS_PUSHBUTTON)
3612     {
3613        return SWELL_MakeButton(0, cname, idx, x,y,w,h,style &~BS_PUSHBUTTON);
3614     }
3615     SWELL_Button *button=[[SWELL_Button alloc] init];
3616     [button setTag:idx];
3617     NSRect fr=MakeCoords(x,y,w,h,true);
3618     SEL actionSel = @selector(onSwellCommand:);
3619     if ((style & 0xf) == BS_AUTO3STATE)
3620     {
3621       [button setButtonType:NSSwitchButton];
3622       [button setAllowsMixedState:YES];
3623     }    
3624     else if ((style & 0xf) == BS_AUTOCHECKBOX)
3625     {
3626       [button setButtonType:NSSwitchButton];
3627       [button setAllowsMixedState:NO];
3628     }
3629     else if ((style & 0xf) == BS_AUTORADIOBUTTON)
3630     {
3631 #ifdef MAC_OS_X_VERSION_10_8
3632       // Compiling with the OSX 10.8+ SDK and running on 10.8+ causes radio buttons with a common action selector to
3633       // be treated as a group. This works around that. if you need more than 8 groups (seriously?!), add the extra 
3634       // functions in swell-dlg.mm and in the switch below
3635       {
3636         NSView *v;
3637         NSArray *sv;
3638         if ((style & WS_GROUP) ||
3639               !(sv = [m_make_owner subviews]) || 
3640               ![sv count] ||
3641               !(v = [sv lastObject]) ||
3642               ![v isKindOfClass:[SWELL_Button class]] ||
3643               ([(SWELL_Button *)v swellGetRadioFlags]&2)) m_make_radiogroupcnt++;
3644       }
3645       switch (m_make_radiogroupcnt & 7)
3646       {
3647         case 0: actionSel = @selector(onSwellCommand0:); break;
3648         case 1: break; // default
3649         case 2: actionSel = @selector(onSwellCommand2:); break;
3650         case 3: actionSel = @selector(onSwellCommand3:); break;
3651         case 4: actionSel = @selector(onSwellCommand4:); break;
3652         case 5: actionSel = @selector(onSwellCommand5:); break;
3653         case 6: actionSel = @selector(onSwellCommand6:); break;
3654         case 7: actionSel = @selector(onSwellCommand7:); break;
3655       }
3656 #endif
3657      
3658       [button setButtonType:NSRadioButton];
3659       [button swellSetRadioFlags:(style & WS_GROUP)?3:1];
3660     }
3661     else if ((style & 0xf) == BS_OWNERDRAW)
3662     {
3663       SWELL_ODButtonCell *cell = [[SWELL_ODButtonCell alloc] init];
3664       [button setCell:cell];
3665       [cell release];
3666       //NSButtonCell
3667     }
3668     else // normal button
3669     {
3670       if (style & BS_BITMAP)
3671       {
3672         SWELL_ImageButtonCell * cell = [[SWELL_ImageButtonCell alloc] init];
3673         [button setCell:cell];
3674         [cell release];
3675       }
3676       if (style & BS_LEFT) [button setAlignment:NSLeftTextAlignment];
3677 //      fr.size.width+=8;
3678     }
3679     
3680     if (m_transform.size.width < minwidfontadjust)
3681       [button setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3682     [button setFrame:fr];
3683     NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(cname);
3684     [button setTitle:labelstr];
3685     [button setTarget:ACTIONTARGET];
3686     [button setAction:actionSel];
3687     if (style&BS_LEFTTEXT) [button setImagePosition:NSImageRight];
3688     if (style&SWELL_NOT_WS_VISIBLE) [button setHidden:YES];
3689     [m_make_owner addSubview:button];
3690     if (m_sizetofits && (style & 0xf) != BS_OWNERDRAW) [button sizeToFit];
3691     if (m_doautoright) UpdateAutoCoords([button frame]);
3692     [labelstr release];
3693     [button release];
3694     return (HWND)button;
3695   }
3696   else if (!stricmp(classname,"REAPERhfader")||!stricmp(classname,"msctls_trackbar32"))
3697   {
3698     NSSlider *obj=[[NSSlider alloc] init];
3699     [obj setTag:idx];
3700     [obj setMinValue:0.0];
3701     [obj setMaxValue:1000.0];
3702     [obj setFrame:MakeCoords(x,y,w,h,false)];
3703     if (!stricmp(classname, "msctls_trackbar32"))
3704     {
3705       [[obj cell] setControlSize:NSMiniControlSize];
3706     }
3707     [obj setTarget:ACTIONTARGET];
3708     [obj setAction:@selector(onSwellCommand:)];
3709     if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3710     [m_make_owner addSubview:obj];
3711     [obj release];
3712     return (HWND)obj;
3713   }
3714   else if (!stricmp(classname,"COMBOBOX"))
3715   {
3716     return SWELL_MakeCombo(idx, x, y, w, h, style);
3717   }
3718   return 0;
3721 HWND SWELL_MakeCombo(int idx, int x, int y, int w, int h, int flags)
3723   if ((flags & 0x3) == CBS_DROPDOWNLIST)
3724   {
3725     SWELL_PopUpButton *obj=[[SWELL_PopUpButton alloc] init];
3726     [obj setTag:idx];
3727     [obj setFont:[NSFont systemFontOfSize:10.0f]];
3728     NSRect rc=MakeCoords(x,y,w,18,true,true);
3729         
3730     [obj setSwellStyle:flags];
3731     [obj setFrame:rc];
3732     [obj setAutoenablesItems:NO];
3733     [obj setTarget:ACTIONTARGET];
3734     [obj setAction:@selector(onSwellCommand:)];
3736     if (g_swell_want_nice_style==1)
3737     {
3738       [obj setBezelStyle:NSShadowlessSquareBezelStyle ];
3739       [[obj cell] setArrowPosition:NSPopUpArrowAtBottom];
3740     }
3741     if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3742     [m_make_owner addSubview:obj];
3743     if (m_doautoright) UpdateAutoCoords([obj frame]);
3744     [obj release];
3745     return (HWND)obj;
3746   }
3747   else
3748   {
3749     SWELL_ComboBox *obj=[[SWELL_ComboBox alloc] init];
3750     [obj setFocusRingType:NSFocusRingTypeNone];
3751     [obj setFont:[NSFont systemFontOfSize:10.0f]];
3752     [obj setEditable:(flags & 0x3) == CBS_DROPDOWNLIST?NO:YES];
3753     [obj setSwellStyle:flags];
3754     [obj setTag:idx];
3755     [obj setFrame:MakeCoords(x,y-1,w,22,true,true)];
3756     [obj setTarget:ACTIONTARGET];
3757     [obj setAction:@selector(onSwellCommand:)];
3758     [obj setDelegate:ACTIONTARGET];
3759     if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3760     [m_make_owner addSubview:obj];
3761     if (m_doautoright) UpdateAutoCoords([obj frame]);
3762     [obj release];
3763     return (HWND)obj;
3764   }
3767 @implementation SWELL_BoxView
3769 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
3771 -(NSInteger) tag
3773   return m_tag;
3775 -(void) setTag:(NSInteger)tag
3777   m_tag=tag;
3779 @end
3781 HWND SWELL_MakeGroupBox(const char *name, int idx, int x, int y, int w, int h, int style)
3783   SWELL_BoxView *obj=[[SWELL_BoxView alloc] init];
3784   
3785   // this just doesn't work, you can't color the border unless it's NSBoxCustom, 
3786   // and I can't get it to show the title text if it's NSBoxCustom
3787   //[obj setBoxType:(NSBoxType)4];   // NSBoxCustom, so we can color the border 
3788   //[obj setTitlePosition:(NSTitlePosition)2];  // NSAtTop, default but NSBoxCustom unsets it
3789   
3790 //  [obj setTag:idx];
3791   if (1) // todo: only if on 10.4 maybe?
3792   {
3793     y-=1;
3794     h+=3;
3795   }
3796   NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(name);
3797   [obj setTitle:labelstr];
3798   [obj setTag:idx];
3799   [labelstr release];
3800   if (style & BS_CENTER)
3801   {
3802     [[obj titleCell] setAlignment:NSCenterTextAlignment];
3803   }
3804   [obj setFrame:MakeCoords(x,y,w,h,false)];
3805   [m_make_owner addSubview:obj positioned:NSWindowBelow relativeTo:nil];
3806   [obj release];
3807   return (HWND)obj;
3811 int TabCtrl_GetItemCount(HWND hwnd)
3813   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return 0;
3814   SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3815   return (int)[tv numberOfTabViewItems];
3818 BOOL TabCtrl_AdjustRect(HWND hwnd, BOOL fLarger, RECT *r)
3820   if (!r || !hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return FALSE;
3821   
3822   int sign=fLarger?-1:1;
3823   r->left+=sign*7; // todo: correct this?
3824   r->right-=sign*7;
3825   r->top+=sign*26;
3826   r->bottom-=sign*3;
3827   return TRUE;
3831 BOOL TabCtrl_DeleteItem(HWND hwnd, int idx)
3833   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return 0;
3834   SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3835   if (idx<0 || idx>= [tv numberOfTabViewItems]) return 0;
3836   [tv removeTabViewItem:[tv tabViewItemAtIndex:idx]];
3837   return TRUE;
3840 int TabCtrl_InsertItem(HWND hwnd, int idx, TCITEM *item)
3842   if (!item || !hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return -1;
3843   if (!(item->mask & TCIF_TEXT) || !item->pszText) return -1;
3844   SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3846   const int ni = (int)[tv numberOfTabViewItems];
3847   if (idx<0) idx=0;
3848   else if (idx>ni) idx=ni;
3849   
3850   NSTabViewItem *tabitem=[[NSTabViewItem alloc] init];
3851   NSString *str=(NSString *)SWELL_CStringToCFString(item->pszText);  
3852   [tabitem setLabel:str];
3853   [str release];
3854   id turd=[tv getNotificationWindow];
3855   [tv setNotificationWindow:nil];
3856   [tv insertTabViewItem:tabitem atIndex:idx];
3857   [tv setNotificationWindow:turd];
3858   [tabitem release];
3859   return idx;
3862 int TabCtrl_SetCurSel(HWND hwnd, int idx)
3864   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return -1;
3865   SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3866   int ret=TabCtrl_GetCurSel(hwnd);
3867   if (idx>=0 && idx < [tv numberOfTabViewItems])
3868   {
3869     [tv selectTabViewItemAtIndex:idx];
3870   }
3871   return ret;
3874 int TabCtrl_GetCurSel(HWND hwnd)
3876   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return 0;
3877   SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3878   NSTabViewItem *item=[tv selectedTabViewItem];
3879   if (!item) return 0;
3880   return (int)[tv indexOfTabViewItem:item];
3883 void ListView_SetExtendedListViewStyleEx(HWND h, int mask, int style)
3885   if (!h) return;
3886   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
3887   SWELL_ListView *tv=(SWELL_ListView*)h;
3888   
3889   if (mask&LVS_EX_GRIDLINES)
3890   {
3891     int s=0;
3892     if (style&LVS_EX_GRIDLINES) 
3893     {
3894       s=NSTableViewSolidVerticalGridLineMask|NSTableViewSolidHorizontalGridLineMask;
3895     }
3896     [tv setGridStyleMask:s];
3897   }
3898   
3899   if (mask&LVS_EX_HEADERDRAGDROP)
3900   {
3901     [tv setAllowsColumnReordering:!!(style&LVS_EX_HEADERDRAGDROP)];
3902   }
3903   
3904   
3905   // todo LVS_EX_FULLROWSELECT (enabled by default on OSX)
3908 void SWELL_SetListViewFastClickMask(HWND hList, int mask)
3910   if (!hList || ![(id)hList isKindOfClass:[SWELL_ListView class]]) return;
3911   SWELL_ListView *lv = (SWELL_ListView *)hList;
3912   lv->m_fastClickMask=mask;
3917 void ListView_SetImageList(HWND h, HIMAGELIST imagelist, int which)
3919   if (!h) return;
3920   
3921   SWELL_ListView *v=(SWELL_ListView *)h;
3922   
3923   v->m_status_imagelist_type=which;
3924   v->m_status_imagelist=(WDL_PtrList<HGDIOBJ__> *)imagelist;
3925   if (v->m_cols && v->m_cols->GetSize()>0)
3926   {
3927     NSTableColumn *col=(NSTableColumn*)v->m_cols->Get(0);
3928     if (![col isKindOfClass:[SWELL_StatusCell class]])
3929     {
3930       SWELL_StatusCell *cell=[[SWELL_StatusCell alloc] initNewCell];
3931       [cell setWraps:NO];
3932       [col setDataCell:cell];
3933       [cell release];
3934     }
3935   }  
3938 int ListView_GetColumnWidth(HWND h, int pos)
3940   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
3941   SWELL_ListView *v=(SWELL_ListView *)h;
3942   if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return 0;
3943   
3944   NSTableColumn *col=v->m_cols->Get(pos);
3945   if (!col) return 0;
3946   
3947   if ([col respondsToSelector:@selector(isHidden)] && [(SWELL_TableColumnExtensions*)col isHidden]) return 0;
3948   return (int) floor(0.5+[col width]);
3951 void ListView_InsertColumn(HWND h, int pos, const LVCOLUMN *lvc)
3953   if (!h || !lvc) return;
3954   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
3956   SWELL_BEGIN_TRY
3958   SWELL_ListView *v=(SWELL_ListView *)h;
3959   NSTableColumn *col=[[NSTableColumn alloc] init];
3960   // note, not looking at lvc->mask at all
3962   [col setEditable:NO];
3963   // [col setResizingMask:2];  // user resizable, this seems to be the default
3964   
3965   if (lvc->fmt == LVCFMT_CENTER) [[col headerCell] setAlignment:NSCenterTextAlignment];
3966   else if (lvc->fmt == LVCFMT_RIGHT) [[col headerCell] setAlignment:NSRightTextAlignment];
3967   
3968   if (!v->m_lbMode && !(v->style & LVS_NOCOLUMNHEADER))
3969   {
3970     NSString *lbl=(NSString *)SWELL_CStringToCFString(lvc->pszText);  
3971     [[col headerCell] setStringValue:lbl];
3972     [lbl release];
3973   }
3974   
3975   if (!pos && v->m_status_imagelist) 
3976   {
3977     SWELL_StatusCell *cell=[[SWELL_StatusCell alloc] initNewCell];
3978     [cell setWraps:NO];
3979     [col setDataCell:cell];
3980     [cell release];
3981   }
3982   else
3983   {  
3984     SWELL_ListViewCell *cell = [[SWELL_ListViewCell alloc] initTextCell:@""];
3985     [col setDataCell:cell];
3986     [cell setWraps:NO];
3987    
3988     if (lvc->fmt == LVCFMT_CENTER) [cell setAlignment:NSCenterTextAlignment];
3989     else if (lvc->fmt == LVCFMT_RIGHT) [cell setAlignment:NSRightTextAlignment];
3990     [cell release];
3991   }
3993   [v addTableColumn:col];
3994   v->m_cols->Add(col);
3995   [col release];
3997   if (lvc->mask&LVCF_WIDTH)
3998   {
3999     ListView_SetColumnWidth(h,pos,lvc->cx);
4000   }
4001   SWELL_END_TRY(;)
4004 void ListView_SetColumn(HWND h, int pos, const LVCOLUMN *lvc)
4006   if (!h || !lvc || ![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4007   SWELL_ListView *v=(SWELL_ListView *)h;
4008   if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return;
4009   
4010   NSTableColumn *col=v->m_cols->Get(pos);
4011   if (!col) return;
4012   
4013   if (lvc->mask&LVCF_FMT)
4014   {
4015     if (lvc->fmt == LVCFMT_LEFT) [[col headerCell] setAlignment:NSLeftTextAlignment];
4016     else if (lvc->fmt == LVCFMT_CENTER) [[col headerCell] setAlignment:NSCenterTextAlignment];
4017     else if (lvc->fmt == LVCFMT_RIGHT) [[col headerCell] setAlignment:NSRightTextAlignment];
4018   }
4019   if (lvc->mask&LVCF_WIDTH)
4020   {
4021     if (!lvc->cx)
4022     {
4023       if ([col respondsToSelector:@selector(setHidden:)])  [(SWELL_TableColumnExtensions*)col setHidden:YES];
4024     }
4025     else 
4026     {
4027       if ([col respondsToSelector:@selector(setHidden:)])  [(SWELL_TableColumnExtensions*)col setHidden:NO];
4028       [col setWidth:lvc->cx];
4029     }
4030   }
4031   if (lvc->mask&LVCF_TEXT)
4032   {
4033     if (!v->m_lbMode && !(v->style&LVS_NOCOLUMNHEADER))
4034     {
4035       NSString *lbl=(NSString *)SWELL_CStringToCFString(lvc->pszText);  
4036       [[col headerCell] setStringValue:lbl];
4037       [lbl release]; 
4038     }
4039   }
4042 bool ListView_DeleteColumn(HWND h, int pos)
4044         if (!h) return false;
4045         if (![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
4046         SWELL_ListView *v=(SWELL_ListView *)h;
4047         if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return false;
4048         [v removeTableColumn:v->m_cols->Get(pos)];
4049         v->m_cols->Delete(pos);
4050         return true;
4053 void ListView_GetItemText(HWND hwnd, int item, int subitem, char *text, int textmax)
4055   LVITEM it={LVIF_TEXT,item,subitem,0,0,text,textmax,};
4056   ListView_GetItem(hwnd,&it);
4059 int ListView_InsertItem(HWND h, const LVITEM *item)
4061   if (!h || !item || item->iSubItem) return 0;
4062   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4063   
4064   SWELL_ListView *tv=(SWELL_ListView*)h;
4065   if (!tv->m_lbMode && (tv->style & LVS_OWNERDATA)) return -1;
4066   if (!tv->m_items) return -1;
4067     
4068   int a=item->iItem;
4069   if (a<0)a=0;
4070   else if (a > tv->m_items->GetSize()) a=tv->m_items->GetSize();
4071   
4072   if (!tv->m_lbMode && (item->mask & LVIF_TEXT))
4073   {
4074     if (tv->style & LVS_SORTASCENDING)
4075     {
4076        a=ptrlist_bsearch_mod((char *)item->pszText,tv->m_items,_listviewrowSearchFunc,NULL);
4077     }
4078     else if (tv->style & LVS_SORTDESCENDING)
4079     {
4080        a=ptrlist_bsearch_mod((char *)item->pszText,tv->m_items,_listviewrowSearchFunc2,NULL);
4081     }
4082   }
4083   
4084   SWELL_ListView_Row *nr=new SWELL_ListView_Row;
4085   nr->m_vals.Add(strdup((item->mask & LVIF_TEXT) ? item->pszText : ""));
4086   if (item->mask & LVIF_PARAM) nr->m_param = item->lParam;
4087   tv->m_items->Insert(a,nr);
4088   
4090   
4091   if ((item->mask&LVIF_STATE) && (item->stateMask & (0xff<<16)))
4092   {
4093     nr->m_imageidx=(item->state>>16)&0xff;
4094   }
4095   
4096   [tv reloadData];
4097   
4098   if (a < tv->m_items->GetSize()-1)
4099   {
4100     NSIndexSet *sel=[tv selectedRowIndexes];
4101     if (sel && [sel count])
4102     {
4103       NSMutableIndexSet *ms = [[NSMutableIndexSet alloc] initWithIndexSet:sel];
4104       [ms shiftIndexesStartingAtIndex:a by:1];
4105       [tv selectRowIndexes:ms byExtendingSelection:NO];
4106       [ms release];
4107     }
4108   }
4109   
4110   if (item->mask & LVIF_STATE)
4111   {
4112     if (item->stateMask & LVIS_SELECTED)
4113     {
4114       if (item->state&LVIS_SELECTED)
4115       {
4116         bool isSingle = tv->m_lbMode ? !(tv->style & LBS_EXTENDEDSEL) : !!(tv->style&LVS_SINGLESEL);
4117         [tv selectRowIndexes:[NSIndexSet indexSetWithIndex:a] byExtendingSelection:isSingle?NO:YES];        
4118       }
4119     }
4120   }
4121   
4122   return a;
4125 void ListView_SetItemText(HWND h, int ipos, int cpos, const char *txt)
4127   if (!h || cpos < 0 || cpos >= 32) return;
4128   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4129   
4130   SWELL_ListView *tv=(SWELL_ListView*)h;
4131   if (!tv->m_lbMode && (tv->style & LVS_OWNERDATA)) return;
4132   if (!tv->m_items) return;
4133   
4134   SWELL_ListView_Row *p=tv->m_items->Get(ipos);
4135   if (!p) return;
4136   int x;
4137   for (x = p->m_vals.GetSize(); x < cpos; x ++)
4138   {
4139     p->m_vals.Add(strdup(""));
4140   }
4141   if (cpos < p->m_vals.GetSize())
4142   {
4143     free(p->m_vals.Get(cpos));
4144     p->m_vals.Set(cpos,strdup(txt));
4145   }
4146   else p->m_vals.Add(strdup(txt));
4147     
4148   [tv reloadData];
4151 int ListView_GetNextItem(HWND h, int istart, int flags)
4153   if (flags==LVNI_FOCUSED||flags==LVNI_SELECTED)
4154   {
4155     if (!h) return -1;
4156     if (![(id)h isKindOfClass:[SWELL_ListView class]]) return -1;
4157     
4158     SWELL_ListView *tv=(SWELL_ListView*)h;
4159     
4160     if (flags==LVNI_SELECTED)
4161     {
4162       //int orig_start=istart;
4163       if (istart++<0)istart=0;
4164       const int n = (int)[tv numberOfRows];
4165       while (istart < n)
4166       {
4167         if ([tv isRowSelected:istart]) return istart;
4168         istart++;
4169       }
4170       return -1;
4171     }
4172     
4173     return (int)[tv selectedRow];
4174   }
4175   return -1;
4178 bool ListView_SetItem(HWND h, LVITEM *item)
4180   if (!item) return false;
4181   if (!h) return false;
4182   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
4183     
4184   SWELL_ListView *tv=(SWELL_ListView*)h;
4185   if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4186   {
4187     if (!tv->m_items) return false;
4188     SWELL_ListView_Row *row=tv->m_items->Get(item->iItem);
4189     if (!row) return false;  
4190   
4191     if (item->mask & LVIF_PARAM) 
4192     {
4193       row->m_param=item->lParam;
4194     }
4195     if ((item->mask & LVIF_TEXT) && item->pszText) 
4196     {
4197       ListView_SetItemText(h,item->iItem,item->iSubItem,item->pszText);
4198     }
4199     if ((item->mask&LVIF_IMAGE) && item->iImage >= 0)
4200     {
4201       row->m_imageidx=item->iImage+1;
4202       ListView_RedrawItems(h, item->iItem, item->iItem);
4203     }
4204   }
4205   if ((item->mask & LVIF_STATE) && item->stateMask)
4206   {
4207     ListView_SetItemState(h,item->iItem,item->state,item->stateMask); 
4208   }
4210   return true;
4213 bool ListView_GetItem(HWND h, LVITEM *item)
4215   if (!item) return false;
4216   if ((item->mask&LVIF_TEXT)&&item->pszText && item->cchTextMax > 0) item->pszText[0]=0;
4217   item->state=0;
4218   if (!h) return false;
4219   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
4220   
4221   
4222   SWELL_ListView *tv=(SWELL_ListView*)h;
4223   if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4224   {
4225     if (!tv->m_items) return false;
4226     
4227     SWELL_ListView_Row *row=tv->m_items->Get(item->iItem);
4228     if (!row) return false;  
4229   
4230     if (item->mask & LVIF_PARAM) item->lParam=row->m_param;
4231     if (item->mask & LVIF_TEXT) if (item->pszText && item->cchTextMax>0)
4232     {
4233       char *p=row->m_vals.Get(item->iSubItem);
4234       lstrcpyn_safe(item->pszText,p?p:"",item->cchTextMax);
4235     }
4236       if (item->mask & LVIF_STATE)
4237       {
4238         if (item->stateMask & (0xff<<16))
4239         {
4240           item->state|=row->m_imageidx<<16;
4241         }
4242       }
4243   }
4244   else
4245   {
4246     if (item->iItem <0 || item->iItem >= tv->ownermode_cnt) return false;
4247   }
4248   if (item->mask & LVIF_STATE)
4249   {
4250      if ((item->stateMask&LVIS_SELECTED) && [tv isRowSelected:item->iItem]) item->state|=LVIS_SELECTED;
4251      if ((item->stateMask&LVIS_FOCUSED) && [tv selectedRow] == item->iItem) item->state|=LVIS_FOCUSED;
4252   }
4254   return true;
4256 int ListView_GetItemState(HWND h, int ipos, UINT mask)
4258   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4259   SWELL_ListView *tv=(SWELL_ListView*)h;
4260   UINT flag=0;
4261   if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4262   {
4263     if (!tv->m_items) return 0;
4264     SWELL_ListView_Row *row=tv->m_items->Get(ipos);
4265     if (!row) return 0;  
4266     if (mask & (0xff<<16))
4267     {
4268       flag|=row->m_imageidx<<16;
4269     }
4270   }
4271   else
4272   {
4273     if (ipos<0 || ipos >= tv->ownermode_cnt) return 0;
4274   }
4275   
4276   if ((mask&LVIS_SELECTED) && [tv isRowSelected:ipos]) flag|=LVIS_SELECTED;
4277   if ((mask&LVIS_FOCUSED) && [tv selectedRow]==ipos) flag|=LVIS_FOCUSED;
4278   return flag;  
4281 bool ListView_SetItemState(HWND h, int ipos, UINT state, UINT statemask)
4283   int doref=0;
4284   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
4285   SWELL_ListView *tv=(SWELL_ListView*)h;
4286   static int _is_doing_all;
4287   
4288   if (ipos == -1)
4289   {
4290     int x;
4291     int n=ListView_GetItemCount(h);
4292     _is_doing_all++;
4293     for (x = 0; x < n; x ++)
4294       ListView_SetItemState(h,x,state,statemask);
4295     _is_doing_all--;
4296     ListView_RedrawItems(h,0,n-1);
4297     return true;
4298   }
4300   if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4301   {
4302     if (!tv->m_items) return false;
4303     SWELL_ListView_Row *row=tv->m_items->Get(ipos);
4304     if (!row) return false;  
4305     if (statemask & (0xff<<16))
4306     {
4307       if (row->m_imageidx!=((state>>16)&0xff))
4308       {
4309         row->m_imageidx=(state>>16)&0xff;
4310         doref=1;
4311       }
4312     }
4313   }
4314   else
4315   {
4316     if (ipos<0 || ipos >= tv->ownermode_cnt) return 0;
4317   }
4318   bool didsel=false;
4319   if (statemask & LVIS_SELECTED)
4320   {
4321     if (state & LVIS_SELECTED)
4322     {      
4323       bool isSingle = tv->m_lbMode ? !(tv->style & LBS_EXTENDEDSEL) : !!(tv->style&LVS_SINGLESEL);
4324       if (![tv isRowSelected:ipos]) { didsel=true;  [tv selectRowIndexes:[NSIndexSet indexSetWithIndex:ipos] byExtendingSelection:isSingle?NO:YES]; }
4325     }
4326     else
4327     {
4328       if ([tv isRowSelected:ipos]) { didsel=true; [tv deselectRow:ipos];  }
4329     }
4330   }
4331   if (statemask & LVIS_FOCUSED)
4332   {
4333     if (state&LVIS_FOCUSED)
4334     {
4335     }
4336     else
4337     {
4338       
4339     }
4340   }
4341   
4342   if (!_is_doing_all)
4343   {
4344     if (didsel)
4345     {
4346       static int __rent;
4347       if (!__rent)
4348       {
4349         __rent=1;
4350         NMLISTVIEW nm={{(HWND)h,(UINT_PTR)[tv tag],LVN_ITEMCHANGED},ipos,0,state,};
4351         SendMessage(GetParent(h),WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
4352         __rent=0;
4353       }
4354     }
4355     if (doref)
4356       ListView_RedrawItems(h,ipos,ipos);
4357   }
4358   return true;
4361 void ListView_RedrawItems(HWND h, int startitem, int enditem)
4363   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4364   SWELL_ListView *tv=(SWELL_ListView*)h;
4365   if (!tv->m_items) return;
4366   [tv reloadData];
4369 void ListView_DeleteItem(HWND h, int ipos)
4371   if (!h) return;
4372   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4373   
4374   SWELL_ListView *tv=(SWELL_ListView*)h;
4375   if (!tv->m_items) return;
4376   
4377   if (ipos >=0 && ipos < tv->m_items->GetSize())
4378   {
4379     if (ipos != tv->m_items->GetSize()-1)
4380     {
4381       NSIndexSet *sel=[tv selectedRowIndexes];
4382       if (sel && [sel count])
4383       {
4384         NSMutableIndexSet *ms = [[NSMutableIndexSet alloc] initWithIndexSet:sel];
4385         [ms shiftIndexesStartingAtIndex:ipos+1 by:-1];
4386         [tv selectRowIndexes:ms byExtendingSelection:NO];
4387         [ms release];
4388       }
4389     }
4390     tv->m_items->Delete(ipos,true);
4391     
4392     [tv reloadData];
4393     
4394   }
4397 void ListView_DeleteAllItems(HWND h)
4399   if (!h) return;
4400   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4401   
4402   SWELL_ListView *tv=(SWELL_ListView*)h;
4403   tv->ownermode_cnt=0;
4404   if (tv->m_items) tv->m_items->Empty(true);
4405   
4406   [tv reloadData];
4409 int ListView_GetSelectedCount(HWND h)
4411   if (!h) return 0;
4412   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4413   
4414   SWELL_ListView *tv=(SWELL_ListView*)h;
4415   return (int)[tv numberOfSelectedRows];
4418 int ListView_GetItemCount(HWND h)
4420   if (!h) return 0;
4421   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4422   
4423   SWELL_ListView *tv=(SWELL_ListView*)h;
4424   if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4425   {
4426     if (!tv->m_items) return 0;
4427   
4428     return tv->m_items->GetSize();
4429   }
4430   return tv->ownermode_cnt;
4433 int ListView_GetSelectionMark(HWND h)
4435   if (!h) return 0;
4436   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4437   
4438   SWELL_ListView *tv=(SWELL_ListView*)h;
4439   return (int)[tv selectedRow];
4442 int SWELL_GetListViewHeaderHeight(HWND h)
4444   if (!h) return 0;
4445   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4446   
4447   SWELL_ListView* tv=(SWELL_ListView*)h;
4448   NSTableHeaderView* hv=[tv headerView];
4449   NSRect r=[hv bounds];
4450   return (int)(r.size.height+0.5);
4453 void ListView_SetColumnWidth(HWND h, int pos, int wid)
4455   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4456   SWELL_ListView *v=(SWELL_ListView *)h;
4457   if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return;
4458   
4459   NSTableColumn *col=v->m_cols->Get(pos);
4460   if (!col) return;
4461   
4462   if (!wid)
4463   {
4464     if ([col respondsToSelector:@selector(setHidden:)])  [(SWELL_TableColumnExtensions*)col setHidden:YES];
4465   }
4466   else 
4467   {
4468     if ([col respondsToSelector:@selector(setHidden:)])  [(SWELL_TableColumnExtensions*)col setHidden:NO];
4469     [col setWidth:wid];
4470   }
4473 BOOL ListView_GetColumnOrderArray(HWND h, int cnt, int* arr)
4475   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return FALSE;
4476   SWELL_ListView* lv=(SWELL_ListView*)h;
4477   if (!lv->m_cols || lv->m_cols->GetSize() != cnt) return FALSE;
4478   
4479   int i;
4480   for (i=0; i < cnt; ++i)
4481   {
4482     arr[i]=[lv getColumnPos:i];
4483   }
4485   return TRUE;
4488 BOOL ListView_SetColumnOrderArray(HWND h, int cnt, int* arr)
4490   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return FALSE;
4491   SWELL_ListView* lv=(SWELL_ListView*)h;
4492   if (!lv->m_cols || lv->m_cols->GetSize() != cnt) return FALSE;
4493   
4494   int i;
4495   for (i=0; i < cnt; ++i)
4496   {
4497     int pos=[lv getColumnPos:i];
4498     int dest=arr[i];
4499     if (dest>=0 && dest<cnt) [lv moveColumn:pos toColumn:dest];
4500   }
4502   return TRUE;
4505 HWND ListView_GetHeader(HWND h)
4507   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4508   return h;
4511 int Header_GetItemCount(HWND h)
4513   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4514   SWELL_ListView* lv=(SWELL_ListView*)h;
4515   if (lv->m_cols) return lv->m_cols->GetSize();
4516   return 0;
4519 BOOL Header_GetItem(HWND h, int col, HDITEM* hi)
4521   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]] || !hi) return FALSE;
4522   SWELL_ListView* lv=(SWELL_ListView*)h;
4523   if (!lv->m_cols || col < 0 || col >= lv->m_cols->GetSize()) return FALSE;
4524   NSTableColumn* hcol=lv->m_cols->Get(col);
4525   if (!hcol) return FALSE;
4526   
4527   if (hi->mask&HDI_FORMAT)
4528   {
4529     hi->fmt=0;
4530     NSImage* img=[lv indicatorImageInTableColumn:hcol];
4531     if (img)
4532     {
4533       NSString* imgname=[img name];
4534       if (imgname)
4535       {
4536         if ([imgname isEqualToString:@"NSAscendingSortIndicator"]) hi->fmt |= HDF_SORTUP;
4537         else if ([imgname isEqualToString:@"NSDescendingSortIndicator"]) hi->fmt |= HDF_SORTDOWN;
4538       }
4539     }
4540   }
4541   // etc todo
4542   
4543   return TRUE;
4546 BOOL Header_SetItem(HWND h, int col, HDITEM* hi)
4548   if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]] || !hi) return FALSE;
4549   SWELL_ListView* lv=(SWELL_ListView*)h;
4550   if (!lv->m_cols || col < 0 || col >= lv->m_cols->GetSize()) return FALSE;
4551   NSTableColumn* hcol=lv->m_cols->Get(col);
4552   if (!hcol) return FALSE;
4553   
4554   if (hi->mask&HDI_FORMAT)
4555   {
4556     NSImage* img=0;
4557     if (hi->fmt&HDF_SORTUP) img=[NSImage imageNamed:@"NSAscendingSortIndicator"];
4558     else if (hi->fmt&HDF_SORTDOWN) img=[NSImage imageNamed:@"NSDescendingSortIndicator"];
4559     [lv setIndicatorImage:img inTableColumn:hcol];
4560   }
4561   // etc todo
4562   
4563   return TRUE;
4566 int ListView_HitTest(HWND h, LVHITTESTINFO *pinf)
4568   if (!h || !pinf) return -1;
4569   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return -1;
4570   
4571   SWELL_ListView *tv=(SWELL_ListView*)h;
4572   // return index
4573   pinf->flags=0;
4574   pinf->iItem=-1;
4575   
4576   // rowAtPoint will return a row even if it is scrolled out of the clip view
4577   NSScrollView* sv=(NSScrollView *)NavigateUpScrollClipViews(tv);
4578   if (![sv isKindOfClass:[NSScrollView class]] && ![sv isKindOfClass:[NSClipView class]]) sv=NULL;
4579   
4580   NSRect r=[sv documentVisibleRect];
4581   int x=pinf->pt.x-r.origin.x;
4582   int y=pinf->pt.y-r.origin.y;
4584   if (x < 0) pinf->flags |= LVHT_TOLEFT;
4585   if (x >= r.size.width) pinf->flags |= LVHT_TORIGHT;
4586   if (y < 0) pinf->flags |= LVHT_ABOVE;
4587   if (y >= r.size.height) pinf->flags |= LVHT_BELOW;
4588   
4589   if (!pinf->flags)
4590   {
4591     NSPoint pt = NSMakePoint( pinf->pt.x, pinf->pt.y );
4592     pinf->iItem=(int)[(NSTableView *)h rowAtPoint:pt];
4593     if (pinf->iItem >= 0)
4594     {
4595       if (tv->m_status_imagelist && pt.x <= [tv rowHeight])
4596       {
4597         pinf->flags=LVHT_ONITEMSTATEICON;
4598       }
4599       else 
4600       {
4601         pinf->flags=LVHT_ONITEMLABEL;
4602       }
4603     }
4604     else 
4605     {
4606       pinf->flags=LVHT_NOWHERE;
4607     }
4608   }
4609   
4610   return pinf->iItem;
4613 int ListView_SubItemHitTest(HWND h, LVHITTESTINFO *pinf)
4615   int row = ListView_HitTest(h, pinf);
4617   NSPoint pt=NSMakePoint(pinf->pt.x,pinf->pt.y);
4618   if (row < 0 && pt.y < 0)
4619   { // Fake the point in the client area of the listview to get the column # (like win32)
4620     pt.y = 0;
4621   }
4622   pinf->iSubItem=(int)[(NSTableView *)h columnAtPoint:pt];
4623   return row;
4626 void ListView_SetItemCount(HWND h, int cnt)
4628   if (!h) return;
4629   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4630   
4631   SWELL_ListView *tv=(SWELL_ListView*)h;
4632   if (!tv->m_lbMode && (tv->style & LVS_OWNERDATA))
4633   {
4634     tv->ownermode_cnt=cnt;
4635     [tv noteNumberOfRowsChanged];
4636   }
4639 void ListView_EnsureVisible(HWND h, int i, BOOL pok)
4641   if (!h) return;
4642   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4643   
4644   SWELL_ListView *tv=(SWELL_ListView*)h;
4645   
4646   if (i<0)i=0;
4647   if (!tv->m_lbMode && (tv->style & LVS_OWNERDATA))
4648   {
4649     if (i >=tv->ownermode_cnt-1) i=tv->ownermode_cnt-1;
4650   }
4651   else
4652   {
4653     if (tv->m_items && i >= tv->m_items->GetSize()) i=tv->m_items->GetSize()-1;
4654   }
4655   if (i>=0)
4656   {
4657     [tv scrollRowToVisible:i];
4658   }  
4661 static bool ListViewGetRectImpl(HWND h, int item, int subitem, RECT* r) // subitem<0 for full item rect
4663   if (!h) return false;
4664   if (![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
4665   if (item < 0 || item > ListView_GetItemCount(h)) return false;
4666   SWELL_ListView *tv=(SWELL_ListView*)h;
4667   
4668   if (subitem >= 0 && (!tv->m_cols || subitem >= tv->m_cols->GetSize())) return false;
4669   subitem=[tv getColumnPos:subitem];
4670   
4671   NSRect ar;
4672   if (subitem < 0) ar = [tv rectOfRow:item];
4673   else ar=[tv frameOfCellAtColumn:subitem row:item];
4674   NSSize sp=[tv intercellSpacing];
4675   
4676   r->left=(int)ar.origin.x;
4677   r->top=(int)ar.origin.y;
4678   r->right=(int)(ar.origin.x+ar.size.width+sp.width);
4679   r->bottom=(int)(ar.origin.y+ar.size.height+sp.height);
4680   
4681   return true;
4684 bool ListView_GetSubItemRect(HWND h, int item, int subitem, int code, RECT *r)
4686   return ListViewGetRectImpl(h, item, subitem, r);
4689 bool ListView_GetItemRect(HWND h, int item, RECT *r, int code)
4691   return ListViewGetRectImpl(h, item, -1, r);
4694 int ListView_GetTopIndex(HWND h)
4696   NSTableView* tv = (NSTableView*)h;
4697   if (!tv) return -1;
4698   NSScrollView* sv = [tv enclosingScrollView];
4699   if (!sv) return -1;  
4700   
4701   NSPoint pt = { 0, 0 };
4702   NSView *hdr = [tv headerView];
4703   if (hdr && ![hdr isHidden])
4704   {
4705     NSRect fr=[hdr frame];
4706     if (fr.size.height > 0.0) pt.y = fr.origin.y + fr.size.height;
4707   }
4708   pt.y += [sv documentVisibleRect].origin.y;
4709   return (int)[tv rowAtPoint:pt];      
4712 int ListView_GetCountPerPage(HWND h)
4714   NSTableView* tv = (NSTableView*)h;
4715   if (!tv) return 0;
4716   NSScrollView* sv = [tv enclosingScrollView];
4717   if (!sv) return 0;  
4718   
4719   NSRect tvr = [sv documentVisibleRect];
4720   int rowh = [tv rowHeight];
4721   return tvr.size.height/rowh;
4724 bool ListView_Scroll(HWND h, int xscroll, int yscroll)
4726   NSTableView* tv = (NSTableView*)h;
4727   NSScrollView* sv = [tv enclosingScrollView];
4728   if (!sv) return false;
4729   
4730   NSRect tvr = [sv documentVisibleRect];
4731   NSPoint pt = { tvr.origin.x, tvr.origin.y };
4732   if (xscroll > 0) pt.x += tvr.size.width-1;
4733   if (yscroll > 0) pt.y += tvr.size.height-1;
4734   
4735   const NSInteger nr = [tv numberOfRows];
4736   NSInteger rowidx = [tv rowAtPoint:pt];
4737   if (rowidx < 0) rowidx=0;
4738   else if (rowidx >= nr) rowidx=nr-1;
4739   
4740   const NSInteger nc = [tv numberOfColumns];
4741   NSInteger colidx = [tv columnAtPoint:pt];
4742   if (colidx < 0) colidx=0;
4743   else if (colidx >= nc) colidx = nc-1;
4745   // colidx is our column index, not the display order, convert
4746   if ([tv isKindOfClass:[SWELL_ListView class]]) colidx = [(SWELL_ListView*)tv getColumnPos:(int)colidx];
4748   NSRect ir = [tv frameOfCellAtColumn:colidx row:rowidx];
4750   if (yscroll)
4751   {
4752     if (ir.size.height) rowidx += yscroll / ir.size.height;
4754     if (rowidx < 0) rowidx=0;
4755     else if (rowidx >= nr) rowidx = nr-1;
4756     [tv scrollRowToVisible:rowidx];
4757   }
4758   
4759   if (xscroll)
4760   {
4761     if (ir.size.width) colidx += xscroll / ir.size.width;
4762    
4763     if (colidx < 0) colidx=0;
4764     else if (colidx >= nc) colidx = nc-1;
4766     // scrollColumnToVisible takes display order, which we have here
4767     [tv scrollColumnToVisible:colidx];
4768   }
4769   
4770   
4771   return true;
4774 bool ListView_GetScroll(HWND h, POINT* p)
4776   NSTableView* tv = (NSTableView*)h;
4777   NSScrollView* sv = [tv enclosingScrollView];
4778   if (sv)
4779   {
4780     NSRect cr = [sv documentVisibleRect];
4781     p->x = cr.origin.x;
4782     p->y = cr.origin.y;
4783     return true;
4784   }
4785   p->x=p->y=0;
4786   return false;
4789 void ListView_SortItems(HWND hwnd, PFNLVCOMPARE compf, LPARAM parm)
4791   if (!hwnd) return;
4792   if (![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
4793   SWELL_ListView *tv=(SWELL_ListView*)hwnd;
4794   if (tv->m_lbMode || (tv->style & LVS_OWNERDATA) || !tv->m_items) return;
4795     
4796   WDL_HeapBuf tmp;
4797   tmp.Resize(tv->m_items->GetSize()*sizeof(void *));
4798   int x;
4799   int sc=0;
4800   for(x=0;x<tv->m_items->GetSize();x++)
4801   {
4802     SWELL_ListView_Row *r = tv->m_items->Get(x);
4803     if (r) 
4804     {
4805       r->m_tmp = !![tv isRowSelected:x];
4806       sc++;
4807     }
4808   }
4809   __listview_mergesort_internal(tv->m_items->GetList(),tv->m_items->GetSize(),sizeof(void *),compf,parm,(char*)tmp.Get());
4810   if (sc)
4811   {
4812     NSMutableIndexSet *indexSet = [[NSMutableIndexSet  alloc] init];
4813     
4814     for(x=0;x<tv->m_items->GetSize();x++)
4815     {
4816       SWELL_ListView_Row *r = tv->m_items->Get(x);
4817       if (r && (r->m_tmp&1)) [indexSet addIndex:x];
4818     }
4819     [tv selectRowIndexes:indexSet byExtendingSelection:NO];
4820     [indexSet release];
4821   }
4822   
4823   [tv reloadData];
4827 HWND WindowFromPoint(POINT p)
4829   NSArray *windows=[NSApp orderedWindows];
4830   const NSInteger cnt=windows ? [windows count] : 0;
4832   NSWindow *kw = [NSApp keyWindow];
4833   if (kw && windows && [windows containsObject:kw]) kw=NULL;
4835   NSWindow *bestwnd=0;
4836   for (NSInteger x = kw ? -1 : 0; x < cnt; x ++)
4837   {
4838     NSWindow *wnd = kw;
4839     if (x>=0) wnd=[windows objectAtIndex:x];
4840     if (wnd && [wnd isVisible])
4841     {
4842       NSRect fr=[wnd frame];
4843       if (p.x >= fr.origin.x && p.x < fr.origin.x + fr.size.width &&
4844           p.y >= fr.origin.y && p.y < fr.origin.y + fr.size.height)
4845       {
4846         bestwnd=wnd;
4847         break;
4848       }    
4849     }
4850   }
4851   
4852   if (!bestwnd) return 0;
4853   NSPoint pt=NSMakePoint(p.x,p.y);
4854   NSPoint lpt=[bestwnd convertScreenToBase:pt];
4855   NSView *v=[[bestwnd contentView] hitTest:lpt];
4856   if (v) return (HWND)v;
4857   return (HWND)[bestwnd contentView]; 
4860 void UpdateWindow(HWND hwnd)
4862   if (hwnd && [(id)hwnd isKindOfClass:[NSView class]] && [(NSView *)hwnd needsDisplay])
4863   {
4864     NSWindow *wnd = [(NSView *)hwnd window];
4865     [wnd displayIfNeeded];
4866   }
4869 void SWELL_FlushWindow(HWND h)
4871   if (h)
4872   {
4873     NSWindow *w=NULL;
4874     if ([(id)h isKindOfClass:[NSView class]]) 
4875     {
4876       if ([(NSView *)h needsDisplay]) return;
4877       
4878       w = [(NSView *)h window];
4879     }
4880     else if ([(id)h isKindOfClass:[NSWindow class]]) w = (NSWindow *)h;
4881     
4882     if (w && ![w viewsNeedDisplay])
4883     {
4884       [w flushWindow];
4885     }
4886   }
4889 static void InvalidateSuperViews(NSView *view)
4891   if (!view) return;
4892   view = [view superview];
4893   while (view)
4894   {
4895     if ([view isKindOfClass:[SWELL_hwndChild class]]) 
4896     {
4897       if (((SWELL_hwndChild *)view)->m_isdirty&2) break;
4898       ((SWELL_hwndChild *)view)->m_isdirty|=2;
4899     }
4900     view = [view superview];
4901   }
4903            
4904 BOOL InvalidateRect(HWND hwnd, const RECT *r, int eraseBk)
4906   if (!hwnd) return FALSE;
4907   id view=(id)hwnd;
4908   if ([view isKindOfClass:[NSWindow class]]) view=[view contentView];
4909   if ([view isKindOfClass:[NSView class]]) 
4910   {
4912     NSView *sv = view;
4913     
4914     bool skip_parent_invalidate=false;
4915     if ([view isKindOfClass:[SWELL_hwndChild class]])
4916     {
4917       if (!(((SWELL_hwndChild *)view)->m_isdirty&1))
4918       {
4919         ((SWELL_hwndChild *)view)->m_isdirty|=1;
4920       }
4921       else skip_parent_invalidate=true; // if already dirty, then assume parents are already dirty too
4922     }
4923     if (!skip_parent_invalidate)
4924     {
4925       InvalidateSuperViews(view);
4926     }
4927     if (r)
4928     {
4929       RECT tr=*r;
4930       if (tr.top>tr.bottom)
4931       {
4932         int a = tr.top; tr.top=tr.bottom; tr.bottom=a;
4933       }
4934       [sv setNeedsDisplayInRect:NSMakeRect(tr.left,tr.top,tr.right-tr.left,tr.bottom-tr.top)]; 
4935     }
4936     else [sv setNeedsDisplay:YES];
4937     
4938   }
4939   return TRUE;
4942 static HWND m_fakeCapture;
4943 static BOOL m_capChangeNotify;
4944 HWND GetCapture()
4947   return m_fakeCapture;
4950 HWND SetCapture(HWND hwnd)
4952   HWND oc=m_fakeCapture;
4953   int ocn=m_capChangeNotify;
4954   m_fakeCapture=hwnd;
4955   m_capChangeNotify = hwnd && [(id)hwnd respondsToSelector:@selector(swellCapChangeNotify)] && [(SWELL_hwndChild*)hwnd swellCapChangeNotify];
4957   if (ocn && oc && oc != hwnd) SendMessage(oc,WM_CAPTURECHANGED,0,(LPARAM)hwnd);
4958   return oc;
4962 void ReleaseCapture()
4964   HWND h=m_fakeCapture;
4965   m_fakeCapture=NULL;
4966   if (m_capChangeNotify && h)
4967   {
4968     SendMessage(h,WM_CAPTURECHANGED,0,0);
4969   }
4973 HDC BeginPaint(HWND hwnd, PAINTSTRUCT *ps)
4975   if (!ps) return 0;
4976   memset(ps,0,sizeof(PAINTSTRUCT));
4977   if (!hwnd) return 0;
4978   id turd = (id)hwnd;
4979   if (![turd respondsToSelector:@selector(getSwellPaintInfo:)]) return 0;
4981   [(SWELL_hwndChild*)turd getSwellPaintInfo:(PAINTSTRUCT *)ps];
4982   return ps->hdc;
4985 BOOL EndPaint(HWND hwnd, PAINTSTRUCT *ps)
4987   return TRUE;
4990 LRESULT DefWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4992   if (msg==WM_RBUTTONUP||msg==WM_NCRBUTTONUP)
4993   {  
4994     POINT p={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
4995     HWND hwndDest=hwnd;
4996     if (msg==WM_RBUTTONUP)
4997     {
4998       ClientToScreen(hwnd,&p);
4999       HWND h=WindowFromPoint(p);
5000       if (h && IsChild(hwnd,h)) hwndDest=h;
5001     }
5002     SendMessage(hwnd,WM_CONTEXTMENU,(WPARAM)hwndDest,(p.x&0xffff)|(p.y<<16));
5003     return 1;
5004   }
5005   else if (msg==WM_CONTEXTMENU || msg == WM_MOUSEWHEEL || msg == WM_MOUSEHWHEEL || msg == WM_GESTURE)
5006   {
5007     if ([(id)hwnd isKindOfClass:[NSView class]])
5008     {
5009       NSView *h=(NSView *)hwnd;
5010       while (h && [[h window] contentView] != h)
5011       {
5012         h=[h superview];
5013         if (h && [h respondsToSelector:@selector(onSwellMessage:p1:p2:)]) 
5014         {
5015            return SendMessage((HWND)h,msg,wParam,lParam);    
5016         }
5017       }
5018     }
5019   }
5020   else if (msg==WM_NCHITTEST) 
5021   {
5022     int rv=HTCLIENT;
5023     SWELL_BEGIN_TRY
5024     RECT r;
5025     GetWindowRect(hwnd,&r);
5026     POINT pt={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
5028     if (r.top > r.bottom) 
5029     { 
5030       pt.y = r.bottom + (r.top - pt.y); // translate coordinate into flipped-window
5032       int a=r.top; r.top=r.bottom; r.bottom=a; 
5033     }
5034     NCCALCSIZE_PARAMS p={{r,}};
5035     SendMessage(hwnd,WM_NCCALCSIZE,FALSE,(LPARAM)&p);
5036     if (!PtInRect(&p.rgrc[0],pt)) rv=HTNOWHERE;
5037     SWELL_END_TRY(;)
5038     return rv;
5039   }
5040   else if (msg==WM_KEYDOWN || msg==WM_KEYUP) return 69;
5041   else if (msg == WM_DISPLAYCHANGE)
5042   {
5043     if ([(id)hwnd isKindOfClass:[NSView class]])
5044     {
5045       NSArray *ch = [(NSView *)hwnd subviews];
5046       if (ch)
5047       {
5048         int x;
5049         for(x=0;x<[ch count]; x ++)
5050         {
5051           NSView *v = [ch objectAtIndex:x];
5052           sendSwellMessage(v,WM_DISPLAYCHANGE,wParam,lParam);
5053         }
5054         if (x)
5055         {
5056           void SWELL_DoDialogColorUpdates(HWND hwnd, DLGPROC d, bool isUpdate);
5057           DLGPROC d = (DLGPROC)GetWindowLong(hwnd,DWL_DLGPROC);
5058           if (d) SWELL_DoDialogColorUpdates(hwnd,d,true);
5059         }
5060       }
5061     }
5062   }
5063   return 0;
5066 void SWELL_BroadcastMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
5068   int x;
5069   NSArray *ch=[NSApp orderedWindows];
5070   for(x=0;x<[ch count]; x ++)
5071   {
5072     NSView *v = [[ch objectAtIndex:x] contentView];
5073     if (v && [v respondsToSelector:@selector(onSwellMessage:p1:p2:)])
5074     {
5075       [(SWELL_hwndChild *)v onSwellMessage:uMsg p1:wParam p2:lParam];
5076       
5077       if (uMsg == WM_DISPLAYCHANGE)
5078         InvalidateRect((HWND)v,NULL,FALSE);
5079     }
5080   }  
5096 ///////////////// clipboard compatability (NOT THREAD SAFE CURRENTLY)
5099 BOOL DragQueryPoint(HDROP hDrop,LPPOINT pt)
5101   if (!hDrop) return 0;
5102   DROPFILES *df=(DROPFILES*)GlobalLock(hDrop);
5103   BOOL rv=!df->fNC;
5104   *pt=df->pt;
5105   GlobalUnlock(hDrop);
5106   return rv;
5109 void DragFinish(HDROP hDrop)
5111 //do nothing for now (caller will free hdrops)
5114 UINT DragQueryFile(HDROP hDrop, UINT wf, char *buf, UINT bufsz)
5116   if (!hDrop) return 0;
5117   DROPFILES *df=(DROPFILES*)GlobalLock(hDrop);
5119   size_t rv=0;
5120   char *p=(char*)df + df->pFiles;
5121   if (wf == 0xFFFFFFFF)
5122   {
5123     while (*p)
5124     {
5125       rv++;
5126       p+=strlen(p)+1;
5127     }
5128   }
5129   else
5130   {
5131     while (*p)
5132     {
5133       if (!wf--)
5134       {
5135         if (buf)
5136         {
5137           lstrcpyn_safe(buf,p,bufsz);
5138           rv=strlen(buf);
5139         }
5140         else rv=strlen(p);
5141           
5142         break;
5143       }
5144       p+=strlen(p)+1;
5145     }
5146   }
5147   GlobalUnlock(hDrop);
5148   return (UINT)rv;
5161 static WDL_PtrList<void> m_clip_recs;
5162 static WDL_PtrList<NSString> m_clip_fmts;
5163 static WDL_PtrList<char> m_clip_curfmts;
5164 struct swell_pendingClipboardStates
5166   UINT type;
5167   HANDLE h;
5168   swell_pendingClipboardStates(UINT _type, HANDLE _h)
5169   {
5170     type = _type;
5171     h = _h;
5172   }
5173   ~swell_pendingClipboardStates()
5174   {
5175     GlobalFree(h);
5176   }
5179 static WDL_PtrList<swell_pendingClipboardStates> m_clipsPending;
5181 bool OpenClipboard(HWND hwndDlg)
5183   m_clipsPending.Empty(true);
5185   CF_TEXT; // ensure this type is registered
5186   
5187   NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:@"SWELL_APP"];
5188   m_clip_curfmts.Empty();
5189   NSArray *ar=[pasteboard types];
5191   
5192   if (ar && [ar count])
5193   {
5194     int x;
5195     
5196     for (x = 0; x < [ar count]; x ++)
5197     {
5198       NSString *s=[ar objectAtIndex:x];
5199       if (!s) continue;
5200       int y;
5201       for (y = 0; y < m_clip_fmts.GetSize(); y ++)
5202       {
5203         if ([s compare:(NSString *)m_clip_fmts.Get(y)]==NSOrderedSame)
5204         {
5205           if (m_clip_curfmts.Find((char*)(INT_PTR)(y+1))<0)
5206             m_clip_curfmts.Add((char*)(INT_PTR)(y+1));
5207           break;
5208         }
5209       }
5210       
5211     }
5212   }
5213   return true;
5216 void CloseClipboard() // frees any remaining items in clipboard
5218   m_clip_recs.Empty(GlobalFree);
5219   
5220   if (m_clipsPending.GetSize())
5221   {
5222     int x;
5223     for (x=0;x<m_clipsPending.GetSize() && m_clipsPending.Get(x)->type != CF_TEXT;x++);
5224     NSPasteboard *pasteboard = x<m_clipsPending.GetSize() ? [NSPasteboard generalPasteboard] : [NSPasteboard pasteboardWithName:@"SWELL_APP"];
5225     
5226     NSMutableArray *ar = [[NSMutableArray alloc] initWithCapacity:m_clipsPending.GetSize()];
5227     
5228     for (x=0;x<m_clipsPending.GetSize();x++)
5229     {
5230       swell_pendingClipboardStates *cs=m_clipsPending.Get(x);
5231       NSString *fmt=m_clip_fmts.Get(cs->type-1);
5232       if (fmt) [ar addObject:fmt];
5233     }
5234     if ([ar count])
5235     {
5236       [pasteboard declareTypes:ar owner:nil];
5237       for (x=0;x<m_clipsPending.GetSize();x++)
5238       {
5239         swell_pendingClipboardStates *cs=m_clipsPending.Get(x);
5240         NSString *fmt=m_clip_fmts.Get(cs->type-1);
5241         if (!fmt) continue;
5242         
5243         void *buf=GlobalLock(cs->h);
5244         if (buf)
5245         {
5246           int bufsz=GlobalSize(cs->h);
5247           if (cs->type == CF_TEXT)
5248           {
5249             char *t = (char *)malloc(bufsz+1);
5250             if (t)
5251             {
5252               memcpy(t,buf,bufsz);
5253               t[bufsz]=0;
5254               NSString *s = (NSString*)SWELL_CStringToCFString(t);
5255               [pasteboard setString:s forType:fmt];
5256               [s release];
5257               free(t);
5258             }
5259           }
5260           else
5261           {
5262             NSData *data=[NSData dataWithBytes:buf length:bufsz];
5263             [pasteboard setData:data forType:fmt];
5264           }
5265           GlobalUnlock(cs->h);
5266         }
5267       }
5268     }
5269     [ar release];
5270     m_clipsPending.Empty(true);
5271   }  
5274 UINT EnumClipboardFormats(UINT lastfmt) // won't enumerate CF_TEXT (since thats a separate pasteboard)
5276   if (!m_clip_curfmts.GetSize()) return 0;
5277   if (lastfmt == 0) return (UINT)(INT_PTR)m_clip_curfmts.Get(0);
5278   int x;
5279   for (x = m_clip_curfmts.GetSize()-2; x >= 0; x--) // scan backwards to avoid dupes causing infinite loops
5280   {
5281     if ((UINT)(INT_PTR)m_clip_curfmts.Get(x) == lastfmt)
5282       return (UINT)(INT_PTR)m_clip_curfmts.Get(x+1);
5283   }
5284   return 0;
5287 HANDLE GetClipboardData(UINT type)
5289   NSString *fmt=m_clip_fmts.Get(type-1);
5290   if (!fmt) return 0;
5291   NSPasteboard *pasteboard = type == CF_TEXT ? [NSPasteboard generalPasteboard] : [NSPasteboard pasteboardWithName:@"SWELL_APP"];
5292   
5293   HANDLE h=0;
5294   if (type == CF_TEXT)
5295   {
5296     [pasteboard types];
5297     NSString *str = [pasteboard stringForType:fmt];
5298     if (str)
5299     {
5300       int l = (int) ([str length]*4 + 32);
5301       char *buf = (char *)malloc(l);
5302       if (!buf) return 0;
5303       SWELL_CFStringToCString(str,buf,l);
5304       buf[l-1]=0;
5305       l = (int) (strlen(buf)+1);
5306       h=GlobalAlloc(0,l);  
5307       memcpy(GlobalLock(h),buf,l);
5308       GlobalUnlock(h);
5309       free(buf);
5310     }
5311   }
5312   else
5313   {
5314     
5315     NSData *data=[pasteboard dataForType:fmt];
5316     if (!data) return 0; 
5317     int l = (int)[data length];
5318     h=GlobalAlloc(0,l);  
5319     if (h) memcpy(GlobalLock(h),[data bytes],l);
5320     GlobalUnlock(h);
5321   }
5322   
5323   if (h) m_clip_recs.Add(h);
5324         return h;
5327 void EmptyClipboard()
5329   m_clipsPending.Empty(true);
5333 void SetClipboardData(UINT type, HANDLE h)
5335   m_clipsPending.Add(new swell_pendingClipboardStates(type,h));    
5338 UINT RegisterClipboardFormat(const char *desc)
5340   NSString *s=NULL;
5341   if (!strcmp(desc,"SWELL__CF_TEXT")) 
5342   {
5343     s=NSStringPboardType;
5344     [s retain];
5345   }
5346   if (!s) s=(NSString*)SWELL_CStringToCFString(desc);
5347   int x;
5348   for (x = 0; x < m_clip_fmts.GetSize(); x ++)
5349   {
5350     NSString *ts=m_clip_fmts.Get(x);
5351     if ([ts compare:s]==NSOrderedSame)
5352     {
5353       [s release];
5354       return x+1;
5355     }
5356   }
5357   m_clip_fmts.Add(s);
5358   return m_clip_fmts.GetSize();
5361 int EnumPropsEx(HWND hwnd, PROPENUMPROCEX proc, LPARAM lParam)
5363   if (!hwnd || ![(id)hwnd respondsToSelector:@selector(swellEnumProps:lp:)]) return -1;
5364   return (int)[(SWELL_hwndChild *)hwnd swellEnumProps:proc lp:lParam];
5367 HANDLE GetProp(HWND hwnd, const char *name)
5369   if (!hwnd || ![(id)hwnd respondsToSelector:@selector(swellGetProp:wantRemove:)]) return NULL;
5370   return (HANDLE)[(SWELL_hwndChild *)hwnd swellGetProp:name wantRemove:NO];
5373 BOOL SetProp(HWND hwnd, const char *name, HANDLE val)
5375   if (!hwnd || ![(id)hwnd respondsToSelector:@selector(swellSetProp:value:)]) return FALSE;
5376   return (BOOL)!![(SWELL_hwndChild *)hwnd swellSetProp:name value:val];
5379 HANDLE RemoveProp(HWND hwnd, const char *name)
5381   if (!hwnd || ![(id)hwnd respondsToSelector:@selector(swellGetProp:wantRemove:)]) return NULL;
5382   return (HANDLE)[(SWELL_hwndChild *)hwnd swellGetProp:name wantRemove:YES];
5386 int GetSystemMetrics(int p)
5388 switch (p)
5390 case SM_CXSCREEN:
5391 case SM_CYSCREEN:
5393   NSScreen *s=[NSScreen mainScreen];
5394   if (!s) return 1024;
5395   return p==SM_CXSCREEN ? [s frame].size.width : [s frame].size.height;
5397 case SM_CXHSCROLL: return 16;
5398 case SM_CYHSCROLL: return 16;
5399 case SM_CXVSCROLL: return 16;
5400 case SM_CYVSCROLL: return 16;
5402 return 0;
5405 BOOL ScrollWindow(HWND hwnd, int xamt, int yamt, const RECT *lpRect, const RECT *lpClipRect)
5407   if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]]) hwnd=(HWND)[(id)hwnd contentView];
5408   if (!hwnd || ![(id)hwnd isKindOfClass:[NSView class]]) return FALSE;
5410   if (!xamt && !yamt) return FALSE;
5411   
5412   // move child windows only
5413   if (1)
5414   {
5415     if (xamt || yamt)
5416     {
5417       NSArray *ar=[(NSView*)hwnd subviews];
5418       NSInteger i,c=[ar count];
5419       for(i=0;i<c;i++)
5420       {
5421         NSView *v=(NSView *)[ar objectAtIndex:i];
5422         NSRect r=[v frame];
5423         r.origin.x+=xamt;
5424         r.origin.y+=yamt;
5425         [v setFrame:r];
5426       }
5427     }
5428     [(id)hwnd setNeedsDisplay:YES];
5429   }
5430   else
5431   {
5432     NSRect r=[(NSView*)hwnd bounds];
5433     r.origin.x -= xamt;
5434     r.origin.y -= yamt;
5435     [(id)hwnd setBoundsOrigin:r.origin];
5436     [(id)hwnd setNeedsDisplay:YES];
5437   }
5438   return TRUE;
5441 HWND FindWindowEx(HWND par, HWND lastw, const char *classname, const char *title)
5443   // note: this currently is far far far from fully functional, bleh
5444   if (!par)
5445   {
5446     if (!title) return NULL;
5448     // get a list of top level windows, find any that match
5449     // (this does not scan child windows, which is a todo really)
5450     HWND rv=NULL;
5451     NSArray *ch=[NSApp windows];
5452     NSInteger x=0,n=[ch count];
5453     if (lastw)
5454     {
5455       for(;x<n; x ++)
5456       {
5457         NSWindow *w = [ch objectAtIndex:x]; 
5458         if ((HWND)w == lastw || (HWND)[w contentView] == lastw) break;
5459       }
5460       x++;
5461     }
5463     NSString *srch=(NSString*)SWELL_CStringToCFString(title);
5464     for(;x<n && !rv; x ++)
5465     {
5466       NSWindow *w = [ch objectAtIndex:x]; 
5467       if ([[w title] isEqualToString:srch]) rv=(HWND)[w contentView];
5468     }
5469     [srch release]; 
5471     return rv;
5472   }
5473   HWND h=lastw?GetWindow(lastw,GW_HWNDNEXT):GetWindow(par,GW_CHILD);
5474   while (h)
5475   {
5476     bool isOk=true;
5477     if (title)
5478     {
5479       char buf[512];
5480       buf[0]=0;
5481       GetWindowText(h,buf,sizeof(buf));
5482       if (strcmp(title,buf)) isOk=false;
5483     }
5484     if (classname)
5485     {
5486       if (!stricmp(classname,"Static") && ![(id)h isKindOfClass:[NSTextField class]]) isOk=false;
5487       // todo: other classname translations
5488     }
5489     
5490     if (isOk) return h;
5491     h=GetWindow(h,GW_HWNDNEXT);
5492   }
5493   return h;
5496 BOOL TreeView_SetIndent(HWND hwnd, int indent)
5498   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return 0;
5499   SWELL_TreeView* tv = (SWELL_TreeView*)hwnd;  
5500   [tv setIndentationPerLevel:(float)indent];  
5501   return TRUE;
5504 HTREEITEM TreeView_InsertItem(HWND hwnd, TV_INSERTSTRUCT *ins)
5506   if (!hwnd || !ins) return 0;
5507   if (![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return 0;
5508   
5509   SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5511   HTREEITEM__ *par=NULL;
5512   int inspos=0;
5513   
5514   if (ins->hParent && ins->hParent != TVI_ROOT && ins->hParent != TVI_FIRST && ins->hParent != TVI_LAST && ins->hParent != TVI_SORT)
5515   {
5516     if ([tv findItem:ins->hParent parOut:&par idxOut:&inspos])
5517     {
5518       par = (HTREEITEM__ *)ins->hParent; 
5519     }
5520     else return 0;
5521   }
5522   
5523   if (ins->hInsertAfter == TVI_FIRST) inspos=0;
5524   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;
5525   else inspos = par ? par->m_children.Find((HTREEITEM__*)ins->hInsertAfter)+1 : tv->m_items ? tv->m_items->Find((HTREEITEM__*)ins->hInsertAfter)+1 : 0;      
5526   
5527   HTREEITEM__ *item=new HTREEITEM__;
5528   if (ins->item.mask & TVIF_CHILDREN)
5529     item->m_haschildren = !!ins->item.cChildren;
5530   if (ins->item.mask & TVIF_PARAM) item->m_param = ins->item.lParam;
5531   if (ins->item.mask & TVIF_TEXT) item->m_value = strdup(ins->item.pszText);
5532   if (!par)
5533   {
5534     if (!tv->m_items) tv->m_items = new WDL_PtrList<HTREEITEM__>;
5535     tv->m_items->Insert(inspos,item);
5536   }
5537   else par->m_children.Insert(inspos,item);
5538   
5539   [tv reloadData];
5540   return (HTREEITEM) item;
5543 BOOL TreeView_Expand(HWND hwnd, HTREEITEM item, UINT flag)
5545   if (!hwnd || !item) return false;
5546   
5547   if (![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return false;
5548   
5549   SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5550   
5551   id itemid=((HTREEITEM__*)item)->m_dh;
5552   bool isExp=!![tv isItemExpanded:itemid];
5553   
5554   if (flag == TVE_EXPAND && !isExp) [tv expandItem:itemid];
5555   else if (flag == TVE_COLLAPSE && isExp) [tv collapseItem:itemid];
5556   else if (flag==TVE_TOGGLE) 
5557   {
5558     if (isExp) [tv collapseItem:itemid];
5559     else [tv expandItem:itemid];
5560   }
5561   else return FALSE;
5563   return TRUE;
5564   
5567 HTREEITEM TreeView_GetSelection(HWND hwnd)
5569   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return NULL;
5570   
5571   SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5572   NSInteger idx=[tv selectedRow];
5573   if (idx<0) return NULL;
5574   
5575   SWELL_DataHold *t=[tv itemAtRow:idx];
5576   if (t) return (HTREEITEM)[t getValue];
5577   return NULL;
5578   
5581 void TreeView_DeleteItem(HWND hwnd, HTREEITEM item)
5583   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5584   SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5585   
5586   HTREEITEM__ *par=NULL;
5587   int idx=0;
5588   
5589   if ([tv findItem:item parOut:&par idxOut:&idx])
5590   {
5591     if (par)
5592     {
5593       par->m_children.Delete(idx,true);
5594     }
5595     else if (tv->m_items)
5596     {
5597       tv->m_items->Delete(idx,true);
5598     }
5599     [tv reloadData];
5600   }
5603 void TreeView_DeleteAllItems(HWND hwnd)
5605   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5606   SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5607   
5608   if (tv->m_items) tv->m_items->Empty(true);
5609   [tv reloadData];
5612 void TreeView_SelectItem(HWND hwnd, HTREEITEM item)
5614   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5615   
5616   NSInteger row=[(SWELL_TreeView*)hwnd rowForItem:((HTREEITEM__*)item)->m_dh];
5617   if (row>=0)
5618     [(SWELL_TreeView*)hwnd selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];            
5619   static int __rent;
5620   if (!__rent)
5621   {
5622     __rent=1;
5623     NMTREEVIEW nm={{(HWND)hwnd,(UINT_PTR)[(SWELL_TreeView*)hwnd tag],TVN_SELCHANGED},};
5624     SendMessage(GetParent(hwnd),WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
5625     __rent=0;
5626   }
5629 BOOL TreeView_GetItem(HWND hwnd, LPTVITEM pitem)
5631   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]] || !pitem || !(pitem->mask & TVIF_HANDLE) || !(pitem->hItem)) return FALSE;
5632   
5633   HTREEITEM__ *ti = (HTREEITEM__*)pitem->hItem;
5634   pitem->cChildren = ti->m_haschildren ? 1:0;
5635   pitem->lParam = ti->m_param;
5636   if ((pitem->mask&TVIF_TEXT)&&pitem->pszText&&pitem->cchTextMax>0)
5637   {
5638     lstrcpyn_safe(pitem->pszText,ti->m_value?ti->m_value:"",pitem->cchTextMax);
5639   }
5640   pitem->state=0;
5641   
5642   
5643   NSInteger itemRow = [(SWELL_TreeView*)hwnd rowForItem:ti->m_dh];
5644   if (itemRow >= 0 && [(SWELL_TreeView*)hwnd isRowSelected:itemRow])
5645     pitem->state |= TVIS_SELECTED;   
5646   if ([(SWELL_TreeView*)hwnd isItemExpanded:ti->m_dh])
5647     pitem->state |= TVIS_EXPANDED;   
5648   
5649   return TRUE;
5652 BOOL TreeView_SetItem(HWND hwnd, LPTVITEM pitem)
5654   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]] || !pitem || !(pitem->mask & TVIF_HANDLE) || !(pitem->hItem)) return FALSE;
5655   
5656   HTREEITEM__ *par=NULL;
5657   int idx=0;
5658   
5659   if (![(SWELL_TreeView*)hwnd findItem:pitem->hItem parOut:&par idxOut:&idx]) return FALSE;
5660   
5661   HTREEITEM__ *ti = (HTREEITEM__*)pitem->hItem;
5662   
5663   if (pitem->mask & TVIF_CHILDREN) ti->m_haschildren = pitem->cChildren?1:0;
5664   if (pitem->mask & TVIF_PARAM)  ti->m_param =  pitem->lParam;
5665   
5666   if ((pitem->mask&TVIF_TEXT)&&pitem->pszText)
5667   {
5668     free(ti->m_value);
5669     ti->m_value=strdup(pitem->pszText);
5670     InvalidateRect(hwnd, 0, FALSE);
5671   }
5673   if (pitem->stateMask & TVIS_SELECTED)
5674   {
5675     NSInteger itemRow = [(SWELL_TreeView*)hwnd rowForItem:ti->m_dh];
5676     if (itemRow >= 0)
5677     {
5678       if (pitem->state&TVIS_SELECTED)
5679       {
5680         [(SWELL_TreeView*)hwnd selectRowIndexes:[NSIndexSet indexSetWithIndex:itemRow] byExtendingSelection:NO];
5681         
5682         static int __rent;
5683         if (!__rent)
5684         {
5685           __rent=1;
5686           NMTREEVIEW nm={{(HWND)hwnd,(UINT_PTR)[(SWELL_TreeView*)hwnd tag],TVN_SELCHANGED},};
5687           SendMessage(GetParent(hwnd),WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
5688           __rent=0;
5689         }
5690         
5691       }
5692       else
5693       {
5694         // todo figure out unselect?!
5695 //         [(SWELL_TreeView*)hwnd selectRowIndexes:[NSIndexSet indexSetWithIndex:itemRow] byExtendingSelection:NO];
5696       }
5697     }
5698   }
5699   
5700   if (pitem->stateMask & TVIS_EXPANDED)
5701     TreeView_Expand(hwnd,pitem->hItem,(pitem->state&TVIS_EXPANDED)?TVE_EXPAND:TVE_COLLAPSE);
5702     
5703   
5704   return TRUE;
5707 HTREEITEM TreeView_HitTest(HWND hwnd, TVHITTESTINFO *hti)
5709   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]] || !hti) return NULL;
5710   SWELL_TreeView* tv = (SWELL_TreeView*)hwnd;
5711   int x = hti->pt.x;
5712   int y = hti->pt.y;
5713   
5714   int i; 
5715   for (i = 0; i < [tv numberOfRows]; ++i)
5716   {
5717     NSRect r = [tv rectOfRow:i];
5718     if (x >= r.origin.x && x < r.origin.x+r.size.width && y >= r.origin.y && y < r.origin.y+r.size.height)
5719     {
5720       SWELL_DataHold* t = [tv itemAtRow:i];
5721       if (t) return (HTREEITEM)[t getValue];
5722       return 0;
5723     }
5724   }
5725   
5726   return NULL; // not hit
5729 HTREEITEM TreeView_GetRoot(HWND hwnd)
5731   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return NULL;
5732   SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5733   
5734   if (!tv->m_items) return 0;
5735   return (HTREEITEM) tv->m_items->Get(0);
5738 HTREEITEM TreeView_GetChild(HWND hwnd, HTREEITEM item)
5740   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return NULL;
5742   HTREEITEM__ *titem=(HTREEITEM__ *)item;
5743   if (!titem) return TreeView_GetRoot(hwnd);
5744   
5745   return (HTREEITEM) titem->m_children.Get(0);
5747 HTREEITEM TreeView_GetNextSibling(HWND hwnd, HTREEITEM item)
5749   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return NULL;
5750   SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5752   if (!item) return TreeView_GetRoot(hwnd);
5753   
5754   HTREEITEM__ *par=NULL;
5755   int idx=0;  
5756   if ([tv findItem:item parOut:&par idxOut:&idx])
5757   {
5758     if (par)
5759     {
5760       return par->m_children.Get(idx+1);
5761     }    
5762     if (tv->m_items) return tv->m_items->Get(idx+1);
5763   }
5764   return 0;
5767 void TreeView_SetBkColor(HWND hwnd, int color)
5769   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5770   [(NSOutlineView*)hwnd setBackgroundColor:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f 
5771               green:GetGValue(color)/255.0f 
5772               blue:GetBValue(color)/255.0f alpha:1.0f]];
5774 void TreeView_SetTextColor(HWND hwnd, int color)
5776   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5778   SWELL_TreeView *f = (SWELL_TreeView *)hwnd;
5779   [f->m_fgColor release];
5780   f->m_fgColor = [NSColor colorWithCalibratedRed:GetRValue(color)/255.0f 
5781               green:GetGValue(color)/255.0f 
5782               blue:GetBValue(color)/255.0f alpha:1.0f];
5783   [f->m_fgColor retain];
5785 void ListView_SetBkColor(HWND hwnd, int color)
5787   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
5788   [(NSTableView*)hwnd setBackgroundColor:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f 
5789               green:GetGValue(color)/255.0f 
5790               blue:GetBValue(color)/255.0f alpha:1.0f]];
5793 void ListView_SetSelColors(HWND hwnd, int *colors, int ncolors) // this works for SWELL_ListView as well as SWELL_TreeView
5795   if (!hwnd) return;
5796   NSMutableArray *ar=[[NSMutableArray alloc] initWithCapacity:ncolors];
5797   
5798   while (ncolors-->0)
5799   {
5800     const int color = colors ? *colors++ : 0;
5801     [ar addObject:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f
5802                                               green:GetGValue(color)/255.0f 
5803                                                blue:GetBValue(color)/255.0f alpha:1.0f]]; 
5804   }
5806   if ([(id)hwnd isKindOfClass:[SWELL_ListView class]]) 
5807   {
5808     SWELL_ListView *lv = (SWELL_ListView*)hwnd;
5809     [lv->m_selColors release];
5810     lv->m_selColors=ar;
5811   }
5812   else if ([(id)hwnd isKindOfClass:[SWELL_TreeView class]]) 
5813   {
5814     SWELL_TreeView *lv = (SWELL_TreeView*)hwnd;
5815     [lv->m_selColors release];
5816     lv->m_selColors=ar;
5817   }
5818   else 
5819   {
5820     [ar release];
5821   }
5823 void ListView_SetGridColor(HWND hwnd, int color)
5825   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
5826   [(NSTableView*)hwnd setGridColor:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f 
5827               green:GetGValue(color)/255.0f 
5828               blue:GetBValue(color)/255.0f alpha:1.0f]];
5830 void ListView_SetTextBkColor(HWND hwnd, int color)
5832   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
5833   // not implemented atm
5835 void ListView_SetTextColor(HWND hwnd, int color)
5837   if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
5839   SWELL_ListView *f = (SWELL_ListView *)hwnd;
5840   [f->m_fgColor release];
5841   f->m_fgColor = [NSColor colorWithCalibratedRed:GetRValue(color)/255.0f 
5842               green:GetGValue(color)/255.0f 
5843               blue:GetBValue(color)/255.0f alpha:1.0f];
5844   [f->m_fgColor retain];
5848 BOOL ShellExecute(HWND hwndDlg, const char *action,  const char *content1, const char *content2, const char *content3, int blah)
5850   if (content1 && !strnicmp(content1,"http://",7))
5851   {
5852      NSWorkspace *wk = [NSWorkspace sharedWorkspace];
5853      if (!wk) return FALSE;
5854      NSString *fnstr=(NSString *)SWELL_CStringToCFString(content1);
5855      BOOL ret=[wk openURL:[NSURL URLWithString:fnstr]];
5856      [fnstr release];
5857      return ret;
5858   }
5859   
5860   if (content1 && !stricmp(content1,"explorer.exe")) content1="";
5861   else if (content1 && (!stricmp(content1,"notepad.exe")||!stricmp(content1,"notepad"))) content1="TextEdit.app";
5862   
5863   if (content2 && !stricmp(content2,"explorer.exe")) content2="";
5865   if (content1 && content2 && *content1 && *content2)
5866   {
5867       NSWorkspace *wk = [NSWorkspace sharedWorkspace];
5868       if (!wk) return FALSE;
5869       NSString *appstr=(NSString *)SWELL_CStringToCFString(content1);
5870       NSString *fnstr=(NSString *)SWELL_CStringToCFString(content2);
5871       BOOL ret=[wk openFile:fnstr withApplication:appstr andDeactivate:YES];
5872       [fnstr release];
5873       [appstr release];
5874       return ret;
5875   }
5876   else if ((content1&&*content1) || (content2&&*content2))
5877   {
5878       const char *fn = (content1 && *content1) ? content1 : content2;
5879       NSWorkspace *wk = [NSWorkspace sharedWorkspace];
5880       if (!wk) return FALSE;
5881       NSString *fnstr = nil;
5882       BOOL ret = FALSE;
5883     
5884       if (fn && !strnicmp(fn, "/select,\"", 9))
5885       {
5886         char* tmp = strdup(fn+9);
5887         if (*tmp && tmp[strlen(tmp)-1]=='\"') tmp[strlen(tmp)-1]='\0';
5888         if (*tmp)
5889         {
5890           if ([wk respondsToSelector:@selector(activateFileViewerSelectingURLs:)]) // 10.6+
5891           {
5892             fnstr=(NSString *)SWELL_CStringToCFString(tmp);
5893             NSURL *url = [NSURL fileURLWithPath:fnstr isDirectory:false];
5894             if (url)
5895             {
5896               [wk activateFileViewerSelectingURLs:[NSArray arrayWithObjects:url, nil]]; // NSArray (and NSURL) autoreleased
5897               ret=TRUE;
5898             }
5899           }
5900           else
5901           {
5902             if (WDL_remove_filepart(tmp))
5903             {
5904               fnstr=(NSString *)SWELL_CStringToCFString(tmp);
5905               ret=[wk openFile:fnstr];
5906             }
5907           }
5908         }
5909         free(tmp);
5910       }
5911       else if (strlen(fn)>4 && !stricmp(fn+strlen(fn)-4,".app"))
5912       {
5913         fnstr=(NSString *)SWELL_CStringToCFString(fn);
5914         ret=[wk launchApplication:fnstr];
5915       }
5916       else
5917       {
5918         fnstr=(NSString *)SWELL_CStringToCFString(fn);
5919         ret=[wk openFile:fnstr];
5920       }
5921       [fnstr release];
5922       return ret;
5923   }
5924   return FALSE;
5930 @implementation SWELL_FocusRectWnd
5932 -(BOOL)isOpaque { return YES; }
5933 -(void) drawRect:(NSRect)rect
5935   NSColor *col=[NSColor colorWithCalibratedRed:0.5 green:0.5 blue:0.5 alpha:1.0];
5936   [col set];
5937   
5938   CGRect r = CGRectMake(rect.origin.x,rect.origin.y,rect.size.width,rect.size.height);
5939   
5940   CGContextRef ctx = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
5941   
5942   CGContextFillRect(ctx,r);              
5943   
5945 @end
5947 // r=NULL to "free" handle
5948 // otherwise r is in hwndPar coordinates
5949 void SWELL_DrawFocusRect(HWND hwndPar, RECT *rct, void **handle)
5951   if (!handle) return;
5952   NSWindow *wnd = (NSWindow *)*handle;
5953   
5954   if (!rct)
5955   {
5956     if (wnd)
5957     {
5958       NSWindow *ow=[wnd parentWindow];
5959       if (ow) [ow removeChildWindow:wnd];
5960 //      [wnd setParentWindow:nil];
5961       [wnd close];
5962       *handle=0;
5963     }
5964   }
5965   else 
5966   {
5967     RECT r=*rct;
5968     if (hwndPar)
5969     {
5970       ClientToScreen(hwndPar,((LPPOINT)&r));
5971       ClientToScreen(hwndPar,((LPPOINT)&r)+1);
5972     }
5973     else
5974     {
5975       // todo: flip?
5976     }
5977     if (r.top>r.bottom) { int a=r.top; r.top=r.bottom;r.bottom=a; }
5978     NSRect rr=NSMakeRect(r.left,r.top,r.right-r.left,r.bottom-r.top);
5979     
5980     NSWindow *par=nil;
5981     if (hwndPar)
5982     {
5983       if ([(id)hwndPar isKindOfClass:[NSWindow class]]) par=(NSWindow *)hwndPar;
5984       else if ([(id)hwndPar isKindOfClass:[NSView class]]) par=[(NSView *)hwndPar window];
5985       else return;
5986     }
5987     
5988     if (wnd && ([wnd parentWindow] != par))
5989     {
5990       NSWindow *ow=[wnd parentWindow];
5991       if (ow) [ow removeChildWindow:wnd];
5992       //      [wnd setParentWindow:nil];
5993       [wnd close];
5994       *handle=0;
5995       wnd=0;    
5996     }
5997     
5998     if (!wnd)
5999     {
6000       *handle  = wnd = [[NSWindow alloc] initWithContentRect:rr styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
6001       [wnd setOpaque:YES];
6002       [wnd setAlphaValue:0.5];
6003       [wnd setExcludedFromWindowsMenu:YES];
6004       [wnd setIgnoresMouseEvents:YES];
6005       [wnd setContentView:[[SWELL_FocusRectWnd alloc] init]];
6006       
6007       if (par) [par addChildWindow:wnd ordered:NSWindowAbove];
6008       else 
6009       {
6010         [wnd setLevel:NSPopUpMenuWindowLevel];
6011         [wnd orderFront:wnd];
6012       }
6013       //    [wnd setParentWindow:par];
6014 //      [wnd orderWindow:NSWindowAbove relativeTo:[par windowNumber]];
6015     }
6016     
6017     [wnd setFrame:rr display:YES];    
6018   }
6022 @implementation SWELL_PopUpButton
6023 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
6025 -(void)setSwellStyle:(LONG)style { m_style=style; }
6026 -(LONG)getSwellStyle { return m_style; }
6027 @end
6029 @implementation SWELL_ComboBox
6030 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
6032 -(void)setSwellStyle:(LONG)style { m_style=style; }
6033 -(LONG)getSwellStyle { return m_style; }
6034 -(id)init { self = [super init]; if (self) { m_ids=new WDL_PtrList<char>; }  return self; }
6035 -(void)dealloc { delete m_ids; [super dealloc];  }
6036 - (BOOL)becomeFirstResponder;
6038   BOOL didBecomeFirstResponder = [super becomeFirstResponder];
6039   if (didBecomeFirstResponder) SendMessage(GetParent((HWND)self),WM_COMMAND,[self tag]|(EN_SETFOCUS<<16),(LPARAM)self);
6040   return didBecomeFirstResponder;
6042 @end
6047 bool SWELL_HandleMouseEvent(NSEvent *evt)
6049   NSEventType etype = [evt type];
6050   if (GetCapture()) return false;
6051   if (etype >= NSLeftMouseDown && etype <= NSRightMouseDragged)
6052   {
6053   }
6054   else return false;
6055   
6056   NSWindow *w = [evt window];
6057   if (w)
6058   {
6059     NSView *cview = [w contentView];
6060     NSView *besthit=NULL;
6061     if (cview)
6062     {
6063       NSPoint lpt = [evt locationInWindow];    
6064       NSView *hitv=[cview hitTest:lpt];
6065       lpt = [w convertBaseToScreen:lpt];
6066       
6067       int xpos=(int)floor(lpt.x);
6068       int ypos=(int)floor(lpt.y);
6069       
6070       while (hitv)
6071       {
6072         int ht=(int)sendSwellMessage(hitv,WM_NCHITTEST,0,MAKELPARAM(xpos,ypos));
6073         if (ht && ht != HTCLIENT) besthit=hitv;
6075         if (hitv==cview) break;
6076         hitv = [hitv superview];
6077       }
6078     }
6079     if (besthit)
6080     {
6081       if (etype == NSLeftMouseDown) [besthit mouseDown:evt];
6082       else if (etype == NSLeftMouseUp) [besthit mouseUp:evt];
6083       else if (etype == NSLeftMouseDragged) [besthit mouseDragged:evt];
6084       else if (etype == NSRightMouseDown) [besthit rightMouseDown:evt];
6085       else if (etype == NSRightMouseUp) [besthit rightMouseUp:evt];
6086       else if (etype == NSRightMouseDragged) [besthit rightMouseDragged:evt];
6087       else if (etype == NSMouseMoved) [besthit mouseMoved:evt];
6088       else return false;
6089       
6090       return true;
6091     }
6092   }
6093   return false;
6096 int SWELL_GetWindowWantRaiseAmt(HWND h)
6098   SWELL_ModelessWindow* mw=0;
6099   if ([(id)h isKindOfClass:[SWELL_ModelessWindow class]])
6100   {
6101     mw=(SWELL_ModelessWindow*)h;
6102   }
6103   else if ([(id)h isKindOfClass:[NSView class]])
6104   {
6105     NSWindow* wnd=[(NSView*)h window];
6106     if (wnd && [wnd isKindOfClass:[SWELL_ModelessWindow class]])
6107     {
6108       mw=(SWELL_ModelessWindow*)wnd;
6109     }
6110   }
6111   if (mw) return mw->m_wantraiseamt;  
6112   return 0; 
6115 void SWELL_SetWindowWantRaiseAmt(HWND h, int  amt)
6117   SWELL_ModelessWindow *mw=NULL;
6118   if ([(id)h isKindOfClass:[SWELL_ModelessWindow class]]) mw=(SWELL_ModelessWindow *)h;
6119   else if ([(id)h isKindOfClass:[NSView class]])
6120   {
6121     NSWindow *w = [(NSView *)h window];
6122     if (w && [w isKindOfClass:[SWELL_ModelessWindow class]]) mw = (SWELL_ModelessWindow*)w;
6123   }
6124   if (mw) 
6125   {
6126     int diff = amt - mw->m_wantraiseamt;
6127     mw->m_wantraiseamt = amt;
6128     if (diff && [NSApp isActive]) [mw setLevel:[mw level]+diff];
6129   }
6133 int SWELL_SetWindowLevel(HWND hwnd, int newlevel)
6135   NSWindow *w = (NSWindow *)hwnd;
6136   if (w && [w isKindOfClass:[NSView class]]) w= [(NSView *)w window];
6137   
6138   if (w && [w isKindOfClass:[NSWindow class]])
6139   {
6140     int ol = (int)[w level];
6141     [w setLevel:newlevel];
6142     return ol;
6143   }
6144   return 0;
6147 void SetAllowNoMiddleManRendering(HWND h, bool allow)
6149   if (!h || ![(id)h isKindOfClass:[SWELL_hwndChild class]]) return;
6150   SWELL_hwndChild* v = (SWELL_hwndChild*)h;
6151   v->m_allow_nomiddleman = allow;
6154 void SetOpaque(HWND h, bool opaque)
6156   if (!h || ![(id)h isKindOfClass:[SWELL_hwndChild class]]) return;
6157   SWELL_hwndChild* v = (SWELL_hwndChild*)h;
6158   [v setOpaque:opaque];
6161 void SetTransparent(HWND h)
6163   if (!h) return;
6164   NSWindow* wnd=0;
6165   if ([(id)h isKindOfClass:[NSWindow class]]) wnd=(NSWindow*)h;
6166   else if ([(id)h isKindOfClass:[NSView class]]) wnd=[(NSView*)h window];
6167   if (wnd) 
6168   {
6169     [wnd setBackgroundColor:[NSColor clearColor]];
6170     [wnd setOpaque:NO];
6171   }  
6174 int SWELL_GetDefaultButtonID(HWND hwndDlg, bool onlyIfEnabled)
6176   if (![(id)hwndDlg isKindOfClass:[NSView class]]) return 0;
6177   NSWindow *wnd = [(NSView *)hwndDlg window];
6178   NSButtonCell * cell = wnd ? [wnd defaultButtonCell] : nil;
6179   NSView *view;
6180   if (!cell || !(view=[cell controlView])) return 0;
6181   int cmdid = (int)[view tag];
6182   if (cmdid && onlyIfEnabled)
6183   {
6184     if (![cell isEnabled]) return 0;
6185   }
6186   return cmdid;
6190 void SWELL_SetWindowRepre(HWND hwnd, const char *fn, bool isDirty)
6192   if (!hwnd) return;
6193   NSWindow *w = NULL;
6194   if ([(id)hwnd isKindOfClass:[NSWindow class]]) w=(NSWindow *)hwnd;
6195   if ([(id)hwnd isKindOfClass:[NSView class]]) w=[(NSView *)hwnd window];
6196   
6197   if (w)
6198   {
6199     if (GetProp((HWND)[w contentView],"SWELL_DisableWindowRepre")) return;
6200     
6201     [w setDocumentEdited:isDirty];
6202     
6203     if (!fn || !*fn) [w setRepresentedFilename:@""];
6204     else
6205     {
6206       NSString *str = (NSString *)SWELL_CStringToCFString(fn);
6207       [w setRepresentedFilename:str];
6208       [str release];
6209     }
6210   }
6213 void SWELL_SetWindowShadow(HWND hwnd, bool shadow)
6215   if (!hwnd) return;
6216   NSWindow *w = (NSWindow *)hwnd;
6217   if ([w isKindOfClass:[NSView class]]) w = [(NSView *)w window];
6218   if (w && [w isKindOfClass:[NSWindow class]]) [w setHasShadow:shadow];
6221 #if 0 // not sure if this will interfere with coolSB
6222 BOOL ShowScrollBar(HWND hwnd, int nBar, BOOL vis)
6224   int v=0;
6225   if (nBar == SB_HORZ || nBar == SB_BOTH) v |= WS_HSCROLL;
6226   if (nBar == SB_VERT || nBar == SB_BOTH) v |= WS_VSCROLL;
6227   if (v)
6228   {
6229     int s=GetWindowLong(hwnd, GWL_STYLE);
6230     if (vis) s |= v;
6231     else s &= ~v;
6232     SetWindowLong(hwnd, GWL_STYLE, s);
6233     SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
6234     return TRUE;
6235   }
6236   return FALSE;
6238 #endif
6241 void SWELL_GenerateDialogFromList(const void *_list, int listsz)
6243 #define SIXFROMLIST list->p1,list->p2,list->p3, list->p4, list->p5, list->p6
6244   SWELL_DlgResourceEntry *list = (SWELL_DlgResourceEntry*)_list;
6245   while (listsz>0)
6246   {
6247     if (!strcmp(list->str1,"__SWELL_BUTTON"))
6248     {
6249       SWELL_MakeButton(list->flag1,list->str2, SIXFROMLIST);
6250     } 
6251     else if (!strcmp(list->str1,"__SWELL_EDIT"))
6252     {
6253       SWELL_MakeEditField(SIXFROMLIST);
6254     }
6255     else if (!strcmp(list->str1,"__SWELL_COMBO"))
6256     {
6257       SWELL_MakeCombo(SIXFROMLIST);
6258     }
6259     else if (!strcmp(list->str1,"__SWELL_LISTBOX"))
6260     {
6261       SWELL_MakeListBox(SIXFROMLIST);
6262     }
6263     else if (!strcmp(list->str1,"__SWELL_GROUP"))
6264     {
6265       SWELL_MakeGroupBox(list->str2,SIXFROMLIST);
6266     }
6267     else if (!strcmp(list->str1,"__SWELL_CHECKBOX"))
6268     {
6269       SWELL_MakeCheckBox(list->str2,SIXFROMLIST);
6270     }
6271     else if (!strcmp(list->str1,"__SWELL_LABEL"))
6272     {
6273       SWELL_MakeLabel(list->flag1, list->str2, SIXFROMLIST);
6274     }
6275     else if (*list->str2)
6276     {
6277       SWELL_MakeControl(list->str1, list->flag1, list->str2, SIXFROMLIST);
6278     }
6279     listsz--;
6280     list++;
6281   }
6284 BOOL EnumChildWindows(HWND hwnd, BOOL (*cwEnumFunc)(HWND,LPARAM),LPARAM lParam)
6286   if (!hwnd || ![(id)hwnd isKindOfClass:[NSView class]]) return TRUE;
6287   NSArray *ar = [(NSView *)hwnd subviews];
6288   if (ar)
6289   {
6290     [ar retain];
6291     NSInteger x,n=[ar count];
6292     for (x=0;x<n;x++)
6293     {
6294       NSView *v = [ar objectAtIndex:x];
6295       if (v)
6296       {
6297         if ([v isKindOfClass:[NSScrollView class]])
6298         {
6299           NSView *sv=[(NSScrollView *)v documentView];
6300           if (sv) v=sv;
6301         }
6302         if ([v isKindOfClass:[NSClipView class]]) 
6303         {
6304           NSView *sv = [(NSClipView *)v documentView];
6305           if (sv) v=sv;
6306         }
6308         if (!cwEnumFunc((HWND)v,lParam) || !EnumChildWindows((HWND)v,cwEnumFunc,lParam)) 
6309         {
6310           [ar release];
6311           return FALSE;
6312         }
6313       }
6314     }
6315     [ar release];
6316   }
6317   return TRUE;
6320 void SWELL_GetDesiredControlSize(HWND hwnd, RECT *r)
6322   if (hwnd && r && [(id)hwnd isKindOfClass:[NSControl class]])
6323   {
6324     NSControl *c = (NSControl *)hwnd;
6325     NSRect fr = [c frame];
6326     [c sizeToFit];
6327     NSRect frnew=[c frame];
6328     [c setFrame:fr];
6329     r->left=r->top=0;
6330     r->right = (int)frnew.size.width;
6331     r->bottom = (int)frnew.size.height;
6332   }
6335 BOOL SWELL_IsGroupBox(HWND hwnd)
6337   if (hwnd && [(id)hwnd isKindOfClass:[SWELL_BoxView class]]) return TRUE;
6338   return FALSE;
6340 BOOL SWELL_IsButton(HWND hwnd)
6342   if (hwnd && [(id)hwnd isKindOfClass:[SWELL_Button class]]) return TRUE;
6343   return FALSE;
6345 BOOL SWELL_IsStaticText(HWND hwnd)
6347   if (hwnd && [(id)hwnd isKindOfClass:[NSTextField class]]) return TRUE;
6348   //todo
6349   return FALSE;
6353 bool SWELL_SetAppAutoHideMenuAndDock(int ah) 
6355   static char _init;
6356   static NSUInteger _defpres;
6357   if (!_init)
6358   {
6359     if (SWELL_GetOSXVersion()>=0x1060)
6360     {
6361       _init=1;
6362       _defpres = [(SWELL_AppExtensions*)[NSApplication sharedApplication] presentationOptions];
6363     }
6364     else
6365     {
6366       _init=-1;
6367     }
6368   }
6369   if (_init > 0)
6370   {
6371     const int NSApplicationPresentationAutoHideDock               = (1 <<  0),
6372               NSApplicationPresentationHideDock = (1<<1),
6373               NSApplicationPresentationAutoHideMenuBar            = (1 <<  2);
6375     if (ah>0) [(SWELL_AppExtensions*)[NSApplication sharedApplication] setPresentationOptions:((ah>=2?NSApplicationPresentationHideDock:NSApplicationPresentationAutoHideDock)|NSApplicationPresentationAutoHideMenuBar)];
6376     else [(SWELL_AppExtensions*)[NSApplication sharedApplication] setPresentationOptions:_defpres];
6377     return true;
6378   }
6379   return false;
6382 #endif