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.
21 This file provides basic windows APIs for handling windows, as well as the stubs to enable swell-dlggen to work.
26 #ifndef SWELL_PROVIDED_BY_APP
28 #import <Cocoa/Cocoa.h>
29 #import <objc/objc-runtime.h>
32 #include "../ptrlist.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()
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;
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];
58 static void InvalidateSuperViews(NSView *view);
59 #define STANDARD_CONTROL_NEEDSDISPLAY_IMPL \
60 - (void)setNeedsDisplay:(BOOL)flag \
62 [super setNeedsDisplay:flag]; \
63 if (flag) InvalidateSuperViews(self); \
65 - (void)setNeedsDisplayInRect:(NSRect)rect \
67 [super setNeedsDisplayInRect:rect]; \
68 InvalidateSuperViews(self); \
72 int g_swell_want_nice_style = 1;
73 static void *SWELL_CStringToCFString_FilterPrefix(const char *str)
76 while (str[c] && str[c] != '&' && c++<1024);
77 if (!str[c] || c>=1024 || strlen(str)>=1024) return SWELL_CStringToCFString(str);
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;
109 if (!row || !(b=row->m_vals.Get(0))) 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;
117 if (!row || !(b=row->m_vals.Get(0))) b="";
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;
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
134 if (base >= nmemb || compar(key,[arr objectAtIndex:base])<=0) return base;
136 } /* else move left */
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();
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
154 if (base >= nmemb || compar(key,arr->Get(base),ctx)<=0) return base;
156 } /* else move left */
162 @implementation SWELL_TabView
163 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
165 -(void)setNotificationWindow:(id)dest
169 -(id)getNotificationWindow
177 -(void) setTag:(NSInteger)tag
181 - (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
185 NMHDR nm={(HWND)self,(UINT_PTR)[self tag],TCN_SELCHANGE};
186 SendMessage((HWND)m_dest,WM_NOTIFY,nm.idFrom,(LPARAM)&nm);
192 @implementation SWELL_ProgressView
193 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
199 -(void) setTag:(NSInteger)tag
203 -(LRESULT)onSwellMessage:(UINT)msg p1:(WPARAM)wParam p2:(LPARAM)lParam
205 if (msg == PBM_SETRANGE)
207 [self setMinValue:LOWORD(lParam)];
208 [self setMaxValue:HIWORD(lParam)];
210 else if (msg==PBM_SETPOS)
212 [self setDoubleValue:(double)wParam];
213 [self stopAnimation:self];
215 else if (msg==PBM_DELTAPOS)
217 [self incrementBy:(double)wParam];
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];
233 @implementation SWELL_StatusCell
236 if ((self=[super initTextCell:@""]))
242 -(void)setStatusImage:(NSImage *)img
246 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
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];
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];
268 @implementation SWELL_TreeView
269 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
273 if ((self = [super init]))
275 m_fakerightmouse=false;
276 m_items=new WDL_PtrList<HTREEITEM__>;
284 if (m_items) m_items->Empty(true);
288 [m_selColors release];
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);
302 for (x = 0; x < m_items->GetSize(); x++)
304 if (m_items->Get(x)->FindItem(item,par,idx)) return true;
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];
321 return it && it->m_haschildren;
324 - (id)outlineView:(NSOutlineView *)outlineView
325 child:(NSInteger)index
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
337 if (!item) return @"";
338 HTREEITEM__ *it=(HTREEITEM__ *)[item getValue];
340 if (!it || !it->m_value) return @"";
342 NSString *str=(NSString *)SWELL_CStringToCFString(it->m_value);
344 return [str autorelease];
349 -(void)mouseDown:(NSEvent *)theEvent
351 if (([theEvent modifierFlags] & NSControlKeyMask) && IsRightClickEmulateEnabled())
358 NMCLICK nmlv={{(HWND)self,(UINT_PTR)[self tag], NM_CLICK},};
359 SendMessage((HWND)[self target],WM_NOTIFY,nmlv.hdr.idFrom,(LPARAM)&nmlv);
362 [super mouseDown:theEvent];
366 -(void)mouseDragged:(NSEvent *)theEvent
370 -(void)mouseUp:(NSEvent *)theEvent
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;
386 SendMessage((HWND)[self target],WM_CONTEXTMENU,(WPARAM)self,(p.x&0xffff)|(p.y<<16));
392 - (void)highlightSelectionInClipRect:(NSRect)theClipRect
396 int a = GetFocus() == (HWND)self ? 0 : 2;
397 if ([m_selColors count] >= a)
399 NSColor *c=[m_selColors objectAtIndex:a];
402 // calculate rect of selected items, combine with theClipRect, and fill these areas with our background (phew!)
404 NSInteger x = [self selectedRow];
407 NSRect r = [self rectOfRow:x];
408 r = NSIntersectionRect(r,theClipRect);
409 if (r.size.height>0 && r.size.width>0)
419 return [super highlightSelectionInClipRect:theClipRect];
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));
440 if ((style&LVS_REPORT) && hdrchg)
442 // todo some crap with NSTableView::setHeaderView, but it's complicated
448 if ((self = [super init]))
453 m_status_imagelist_type=-1;
454 m_status_imagelist=0;
455 m_leftmousemovecnt=0;
456 m_fakerightmouse=false;
459 m_last_shift_clicked_item = m_last_plainly_clicked_item=-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>;
470 if (m_items) m_items->Empty(true);
476 [m_selColors release];
480 -(int)getColumnPos:(int)idx // get current position of column that was originally at idx
485 NSTableColumn* col=m_cols->Get(idx);
488 NSArray* arr=[self tableColumns];
491 pos=(int)[arr indexOfObject:col];
498 - (void)highlightSelectionInClipRect:(NSRect)theClipRect
502 int a = GetFocus() == (HWND)self ? 0 : 2;
503 if ([m_selColors count] >= a)
505 NSColor *c=[m_selColors objectAtIndex:a];
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)];
512 const NSInteger n = [self numberOfRows];
515 NSRect r = [self rectOfRow:x];
516 if (r.origin.y >= theClipRect.origin.y + theClipRect.size.height) break;
518 if ([self isRowSelected:x])
520 r = NSIntersectionRect(r,theClipRect);
521 if (r.size.height>0 && r.size.width>0)
523 if (needfillset) { needfillset=false; [c setFill]; }
532 return [super highlightSelectionInClipRect:theClipRect];
534 -(int)getColumnIdx:(int)pos // get original index of column that is currently at position
537 NSArray* arr=[self tableColumns];
538 if (arr && pos>=0 && pos < [arr count])
540 NSTableColumn* col=[arr objectAtIndex:pos];
543 idx=m_cols->Find(col);
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
566 if (!m_lbMode && (style & LVS_OWNERDATA))
568 HWND tgt=(HWND)[self target];
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;
576 nm.item.iItem=(int)rowIndex;
577 nm.item.iSubItem=m_cols->Find(aTableColumn);
579 nm.item.cchTextMax=sizeof(buf)-1;
581 SendMessage(tgt,WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
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);
590 SWELL_ListView_Row *r=0;
591 if (m_items && m_cols && (r=m_items->Get(rowIndex)))
593 p=r->m_vals.Get(m_cols->Find(aTableColumn));
594 if (m_status_imagelist_type == LVSIL_STATE || m_status_imagelist_type == LVSIL_SMALL)
596 image_idx=r->m_imageidx;
600 str=(NSString *)SWELL_CStringToCFString(p);
602 if (style & LBS_OWNERDRAWFIXED)
604 SWELL_ODListViewCell *cell=[aTableColumn dataCell];
605 if ([cell isKindOfClass:[SWELL_ODListViewCell class]]) [cell setItemIdx:(int)rowIndex];
609 if (!m_lbMode && m_status_imagelist)
611 SWELL_StatusCell *cell=(SWELL_StatusCell*)[aTableColumn dataCell];
612 if ([cell isKindOfClass:[SWELL_StatusCell class]])
614 HICON icon=m_status_imagelist->Get(image_idx-1);
616 if (icon) img=(NSImage *)GetNSImageFromHICON(icon);
617 [cell setStatusImage:img];
621 return [str autorelease];
626 -(void)mouseDown:(NSEvent *)theEvent
628 if (([theEvent modifierFlags] & NSControlKeyMask) && IsRightClickEmulateEnabled())
636 if ([theEvent clickCount]>1 && SWELL_NeedModernListViewHacks())
638 [super mouseDown:theEvent];
641 m_leftmousemovecnt=0;
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];
651 m_start_item_clickmode=0;
652 if (m_start_item >=0 && (m_fastClickMask&(1<<m_start_subitem)))
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);
657 nmlv.lParam = row->m_param;
658 SendMessage((HWND)[self target],WM_NOTIFY,nmlv.hdr.idFrom,(LPARAM)&nmlv);
659 m_start_item_clickmode=4;
663 if (m_start_item>=0 && m_status_imagelist && LVSIL_STATE == m_status_imagelist_type && pt.x <= [self rowHeight]) // in left area
665 m_start_item_clickmode=1;
671 -(void)mouseDragged:(NSEvent *)theEvent
673 if (++m_leftmousemovecnt==4)
675 if (m_start_item>=0 && !(m_start_item_clickmode&3))
679 // if m_start_item isnt selected, change selection to it now
680 if (!(m_start_item_clickmode&4) && ![self isRowSelected:m_start_item])
682 [self selectRowIndexes:[NSIndexSet indexSetWithIndex:m_start_item] byExtendingSelection:!!(GetAsyncKeyState(VK_CONTROL)&0x8000)];
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;
690 else if (m_leftmousemovecnt > 4 && !(m_start_item_clickmode&1))
692 HWND tgt=(HWND)[self target];
695 ScreenToClient(tgt,&p);
697 SendMessage(tgt,WM_MOUSEMOVE,0,(p.x&0xffff) + (((int)p.y)<<16));
701 -(void)mouseUp:(NSEvent *)theEvent
703 if ((m_fakerightmouse||([theEvent modifierFlags] & NSControlKeyMask)) && IsRightClickEmulateEnabled())
705 [self rightMouseUp:theEvent];
709 if ([theEvent clickCount]>1 && SWELL_NeedModernListViewHacks())
711 [super mouseUp:theEvent];
714 if (!(m_start_item_clickmode&1))
716 if (m_leftmousemovecnt>=0 && m_leftmousemovecnt<4 && !(m_start_item_clickmode&4))
718 const bool msel = [self allowsMultipleSelection];
719 if (m_lbMode && !msel) // listboxes --- allow clicking to reset the selection
721 [self deselectAll:self];
724 if (SWELL_NeedModernListViewHacks())
728 NSMutableIndexSet *m = [[NSMutableIndexSet alloc] init];
729 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
731 [m addIndexes:[self selectedRowIndexes]];
732 if ([m containsIndex:m_start_item]) [m removeIndex:m_start_item];
735 if (!msel) [m removeAllIndexes];
736 [m addIndex:m_start_item];
738 m_last_plainly_clicked_item = m_start_item;
740 else if (msel && (GetAsyncKeyState(VK_SHIFT)&0x8000))
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;
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)
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)];
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;
766 m_last_plainly_clicked_item = m_start_item;
767 [m addIndex:m_start_item];
770 [self selectRowIndexes:m byExtendingSelection:NO];
775 else [self deselectAll:self];
779 [super mouseDown:theEvent];
780 [super mouseUp:theEvent];
783 else if (m_leftmousemovecnt>=4)
785 HWND tgt=(HWND)[self target];
788 ScreenToClient(tgt,&p);
789 SendMessage(tgt,WM_LBUTTONUP,0,(p.x&0xffff) + (((int)p.y)<<16));
794 if (!m_lbMode && !(m_start_item_clickmode&(2|4)))
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);
806 - (void)rightMouseUp:(NSEvent *)theEvent
808 bool wantContext=true;
812 NSPoint pt=[theEvent locationInWindow];
813 pt=[self convertPoint:pt fromView:nil];
815 // note, windows selects on right mousedown
816 NSInteger row =[self rowAtPoint:pt];
817 if (row >= 0 && ![self isRowSelected:row])
819 NSIndexSet* rows=[NSIndexSet indexSetWithIndex:row];
820 [self deselectAll:self];
821 [self selectRowIndexes:rows byExtendingSelection:NO];
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;
831 SendMessage((HWND)[self target],WM_CONTEXTMENU,(WPARAM)self,(p.x&0xffff)|(p.y<<16));
836 -(LRESULT)onSwellMessage:(UINT)msg p1:(WPARAM)wParam p2:(LPARAM)lParam
838 HWND hwnd=(HWND)self;
841 case LB_RESETCONTENT:
845 m_items->Empty(true);
850 case LB_INSERTSTRING:
852 int cnt=ListView_GetItemCount(hwnd);
853 if (msg == LB_ADDSTRING && (style & LBS_SORT))
855 SWELL_ListView *tv=(SWELL_ListView*)hwnd;
856 if (tv->m_lbMode && tv->m_items)
858 cnt=ptrlist_bsearch_mod((char *)lParam,tv->m_items,_listviewrowSearchFunc,NULL);
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);
867 case LB_GETCOUNT: return ListView_GetItemCount(hwnd);
869 ListView_SetItemState(hwnd, (int)lParam,wParam ? LVIS_SELECTED : 0,LVIS_SELECTED);
874 SWELL_ListView_Row *row=self->m_items ? self->m_items->Get(wParam) : NULL;
876 if (row && row->m_vals.Get(0))
878 strcpy((char *)lParam, row->m_vals.Get(0));
879 return (LRESULT)strlen(row->m_vals.Get(0));
885 SWELL_ListView_Row *row=self->m_items ? self->m_items->Get(wParam) : NULL;
888 const char *p=row->m_vals.Get(0);
889 return p?strlen(p):0;
894 return !!(ListView_GetItemState(hwnd,(int)wParam,LVIS_SELECTED)&LVIS_SELECTED);
896 return [self selectedRow];
899 if (wParam<ListView_GetItemCount(hwnd))
901 [self selectRowIndexes:[NSIndexSet indexSetWithIndex:wParam] byExtendingSelection:NO];
902 [self scrollRowToVisible:wParam];
906 [self deselectAll:self];
914 SWELL_ListView_Row *row=m_items->Get(wParam);
915 if (row) return row->m_param;
923 SWELL_ListView_Row *row=m_items->Get(wParam);
924 if (row) row->m_param=lParam;
929 return [[self selectedRowIndexes] count];
930 case LB_DELETESTRING:
931 ListView_DeleteItem((HWND)self, (int)wParam);
937 -(int)getSwellNotificationMode
941 -(void)setSwellNotificationMode:(int)lbMode
946 -(void)onSwellCommand:(int)cmd
953 @implementation SWELL_ImageButtonCell
954 - (NSRect)drawTitle:(NSAttributedString *)title withFrame:(NSRect)frame inView:(NSView *)controlView
956 return NSMakeRect(0,0,0,0);
960 @implementation SWELL_ODButtonCell
961 - (BOOL)isTransparent
970 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
972 NSView *ctl=[self controlView];
973 if (!ctl) { [super drawWithFrame:cellFrame inView:controlView]; return; }
975 HDC hdc=GetDC((HWND)controlView);
978 HWND notWnd = GetParent((HWND)ctl);
979 RECT r={(int)(cellFrame.origin.x+0.5),(int)(cellFrame.origin.y+0.5)};
980 r.right=r.left+(int)(cellFrame.size.width+0.5);
981 r.bottom=r.top+(int)(cellFrame.size.height+0.5);
982 DRAWITEMSTRUCT dis={ODT_BUTTON,(UINT)[ctl tag],0,0,0,(HWND)ctl,hdc,{0,},0};
984 SendMessage(notWnd,WM_DRAWITEM,dis.CtlID,(LPARAM)&dis);
986 ReleaseDC((HWND)controlView,hdc);
992 @implementation SWELL_ODListViewCell
993 -(void)setOwnerControl:(SWELL_ListView *)t { m_ownctl=t; m_lastidx=0; }
994 -(void)setItemIdx:(int)idx
998 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
1000 if (!m_ownctl) { [super drawInteriorWithFrame:cellFrame inView:controlView]; return; }
1002 int itemidx=m_lastidx;
1004 SWELL_ListView_Row *row=m_ownctl->m_items->Get(itemidx);
1005 if (row) itemData=row->m_param;
1007 HDC hdc=GetDC((HWND)controlView);
1010 HWND notWnd = GetParent((HWND)m_ownctl);
1011 RECT r={(int)(cellFrame.origin.x+0.5),(int)(cellFrame.origin.y+0.5)};
1012 r.right=r.left+(int)(cellFrame.size.width+0.5);
1013 r.bottom=r.top+(int)(cellFrame.size.height+0.5);
1014 DRAWITEMSTRUCT dis={ODT_LISTBOX,(UINT)[m_ownctl tag],(UINT)itemidx,0,0,(HWND)m_ownctl,hdc,{0,},(DWORD_PTR)itemData};
1016 SendMessage(notWnd,WM_DRAWITEM,dis.CtlID,(LPARAM)&dis);
1018 ReleaseDC((HWND)controlView,hdc);
1029 HWND GetDlgItem(HWND hwnd, int idx)
1031 if (!hwnd) return 0;
1035 if ([pid isKindOfClass:[NSWindow class]]) v=[((NSWindow *)pid) contentView];
1036 else if ([pid isKindOfClass:[NSView class]]) v=(NSView *)pid;
1038 if (!idx || !v) return (HWND)v;
1042 NSArray *ar = [v subviews];
1043 const NSInteger n=[ar count];
1044 for (NSInteger x=0;x<n;x++)
1046 NSView *sv = [ar objectAtIndex:x];
1049 if ([sv respondsToSelector:@selector(tag)] && [sv tag] == idx) return (HWND)sv;
1051 if (sv && [sv isKindOfClass:[NSScrollView class]])
1053 sv=[(NSScrollView *)sv documentView];
1054 if (sv && [sv respondsToSelector:@selector(tag)] && [sv tag] == idx) return (HWND)sv;
1056 if (sv && [sv isKindOfClass:[NSClipView class]])
1058 sv = [(NSClipView *)sv documentView];
1059 if (sv && [sv respondsToSelector:@selector(tag)] && [sv tag] == idx) return (HWND)sv;
1063 // we might want to enable this for max compat with old code, but hopefully not: return [v viewWithTag:idx];
1069 LONG_PTR SetWindowLong(HWND hwnd, int idx, LONG_PTR val)
1071 if (!hwnd) return 0;
1075 if (idx==GWL_EXSTYLE && [pid respondsToSelector:@selector(swellSetExtendedStyle:)])
1077 LONG ret=(LONG) [(SWELL_hwndChild*)pid swellGetExtendedStyle];
1078 [(SWELL_hwndChild*)pid swellSetExtendedStyle:(LONG)val];
1081 if (idx==GWL_USERDATA && [pid respondsToSelector:@selector(setSwellUserData:)])
1083 LONG_PTR ret=(LONG_PTR)[(SWELL_hwndChild*)pid getSwellUserData];
1084 [(SWELL_hwndChild*)pid setSwellUserData:(LONG_PTR)val];
1088 if (idx==GWL_ID && [pid respondsToSelector:@selector(tag)] && [pid respondsToSelector:@selector(setTag:)])
1090 int ret= (int) [pid tag];
1091 [pid setTag:(int)val];
1092 return (LONG_PTR)ret;
1095 if (idx==GWL_WNDPROC && [pid respondsToSelector:@selector(setSwellWindowProc:)])
1097 WNDPROC ov=(WNDPROC)[pid getSwellWindowProc];
1098 [pid setSwellWindowProc:(WNDPROC)val];
1099 return (LONG_PTR)ov;
1101 if (idx==DWL_DLGPROC && [pid respondsToSelector:@selector(setSwellDialogProc:)])
1103 DLGPROC ov=(DLGPROC)[pid getSwellDialogProc];
1104 [pid setSwellDialogProc:(DLGPROC)val];
1105 return (LONG_PTR)ov;
1110 if ([pid respondsToSelector:@selector(setSwellStyle:)])
1112 LONG ov=[pid getSwellStyle];
1113 [pid setSwellStyle:(LONG)val];
1116 else if ([pid isKindOfClass:[NSButton class]])
1118 int ret=(int)GetWindowLong(hwnd,idx);
1120 if ((val&0xf) == BS_AUTO3STATE)
1122 [pid setButtonType:NSSwitchButton];
1123 [pid setAllowsMixedState:YES];
1124 if ([pid isKindOfClass:[SWELL_Button class]]) [pid swellSetRadioFlags:0];
1126 else if ((val & 0xf) == BS_AUTOCHECKBOX)
1128 [pid setButtonType:NSSwitchButton];
1129 [pid setAllowsMixedState:NO];
1130 if ([pid isKindOfClass:[SWELL_Button class]]) [pid swellSetRadioFlags:0];
1132 else if ((val & 0xf) == BS_AUTORADIOBUTTON)
1134 [pid setButtonType:NSRadioButton];
1135 if ([pid isKindOfClass:[SWELL_Button class]]) [pid swellSetRadioFlags:(val&WS_GROUP)?3:1];
1142 if ([[pid window] contentView] == pid)
1144 NSView *tv=(NSView *)pid;
1145 NSWindow *oldw = [tv window];
1146 NSUInteger smask = [oldw styleMask];
1148 if (smask & NSTitledWindowMask)
1151 if (smask & NSResizableWindowMask) mf|=WS_THICKFRAME;
1153 if (mf != (val&(WS_CAPTION|WS_THICKFRAME)))
1155 BOOL dovis = IsWindowVisible((HWND)oldw);
1156 NSWindow *oldpar = [oldw parentWindow];
1157 char oldtitle[2048];
1159 GetWindowText(hwnd,oldtitle,sizeof(oldtitle));
1160 NSRect fr=[oldw frame];
1162 if ([oldw respondsToSelector:@selector(swellGetOwner)]) oldOwner=(HWND)[(SWELL_ModelessWindow*)oldw swellGetOwner];
1163 NSInteger oldlevel = [oldw level];
1167 SWELL_hwndChild *tempview = [[SWELL_hwndChild alloc] initChild:nil Parent:(NSView *)oldw dlgProc:nil Param:0];
1170 unsigned int mask=0;
1172 if (val & WS_CAPTION)
1174 mask|=NSTitledWindowMask;
1175 if (val & WS_THICKFRAME)
1176 mask|=NSMiniaturizableWindowMask|NSClosableWindowMask|NSResizableWindowMask;
1179 HWND SWELL_CreateModelessFrameForWindow(HWND childW, HWND ownerW, unsigned int);
1180 HWND bla=SWELL_CreateModelessFrameForWindow((HWND)tv,(HWND)oldOwner,mask);
1185 // move owned windows over
1186 if ([oldw respondsToSelector:@selector(swellGetOwnerWindowHead)])
1188 void **p=(void **)[(SWELL_ModelessWindow*)oldw swellGetOwnerWindowHead];
1189 if (p && [(id)bla respondsToSelector:@selector(swellGetOwnerWindowHead)])
1191 void **p2=(void **)[(SWELL_ModelessWindow*)bla swellGetOwnerWindowHead];
1196 OwnedWindowListRec *rec = (OwnedWindowListRec *) *p2;
1199 if (rec->hwnd && [rec->hwnd respondsToSelector:@selector(swellSetOwner:)])
1200 [(SWELL_ModelessWindow *)rec->hwnd swellSetOwner:(id)bla];
1206 // move all child and owned windows over to new window
1207 NSArray *ar=[oldw childWindows];
1211 for (x = 0; x < [ar count]; x ++)
1213 NSWindow *cw=[ar objectAtIndex:x];
1217 [oldw removeChildWindow:cw];
1218 [(NSWindow *)bla addChildWindow:cw ordered:NSWindowAbove];
1226 if (oldpar) [oldpar addChildWindow:(NSWindow *)bla ordered:NSWindowAbove];
1227 if (oldtitle[0]) SetWindowText(hwnd,oldtitle);
1229 [(NSWindow *)bla setFrame:fr display:dovis];
1230 [(NSWindow *)bla setLevel:oldlevel];
1231 if (dovis) ShowWindow(bla,SW_SHOW);
1233 DestroyWindow((HWND)oldw);
1237 [oldw setContentView:tv];
1248 if ([pid respondsToSelector:@selector(setSwellExtraData:value:)])
1251 if ([pid respondsToSelector:@selector(getSwellExtraData:)]) ov=(LONG_PTR)[pid getSwellExtraData:idx];
1253 [pid setSwellExtraData:idx value:val];
1262 LONG_PTR GetWindowLong(HWND hwnd, int idx)
1264 if (!hwnd) return 0;
1269 if (idx==GWL_EXSTYLE && [pid respondsToSelector:@selector(swellGetExtendedStyle)])
1271 return (LONG_PTR)[pid swellGetExtendedStyle];
1274 if (idx==GWL_USERDATA && [pid respondsToSelector:@selector(getSwellUserData)])
1276 return (LONG_PTR)[pid getSwellUserData];
1278 if (idx==GWL_USERDATA && [pid isKindOfClass:[NSText class]])
1283 if (idx==GWL_ID && [pid respondsToSelector:@selector(tag)])
1287 if (idx==GWL_WNDPROC && [pid respondsToSelector:@selector(getSwellWindowProc)])
1289 return (LONG_PTR)[pid getSwellWindowProc];
1291 if (idx==DWL_DLGPROC && [pid respondsToSelector:@selector(getSwellDialogProc)])
1293 return (LONG_PTR)[pid getSwellDialogProc];
1298 if ([pid respondsToSelector:@selector(getSwellStyle)])
1300 return (LONG_PTR)[pid getSwellStyle];
1303 if ([pid isKindOfClass:[NSButton class]])
1306 if ([pid allowsMixedState]) ret |= BS_AUTO3STATE;
1307 else if ([pid isKindOfClass:[SWELL_Button class]] && (tmp = (int)[pid swellGetRadioFlags]))
1309 ret |= BS_AUTORADIOBUTTON;
1310 if (tmp&2) ret|=WS_GROUP;
1312 else ret |= BS_AUTOCHECKBOX;
1315 if ([pid isKindOfClass:[NSView class]])
1317 if ([[pid window] contentView] != pid) ret |= WS_CHILDWINDOW;
1320 NSUInteger smask =[[pid window] styleMask];
1321 if (smask & NSTitledWindowMask)
1324 if (smask & NSResizableWindowMask) ret|=WS_THICKFRAME;
1331 if ([pid respondsToSelector:@selector(getSwellExtraData:)])
1333 return (LONG_PTR)[pid getSwellExtraData:idx];
1340 static bool IsWindowImpl(NSView *ch, NSView *par)
1342 if (!par || ![par isKindOfClass:[NSView class]]) return false;
1344 NSArray *ar = [par subviews];
1345 if (!ar) return false;
1347 NSInteger x,n=[ar count];
1349 if ([ar objectAtIndex:x] == ch)
1356 if (IsWindowImpl(ch,[ar objectAtIndex:x]))
1365 bool IsWindow(HWND hwnd)
1367 if (!hwnd) return false;
1368 // this is very costly, but required
1371 NSArray *ch=[NSApp windows];
1373 NSInteger x,n=[ch count];
1377 NSWindow *w = [ch objectAtIndex:x];
1378 if (w == (NSWindow *)hwnd || [w contentView] == (NSView *)hwnd)
1384 @catch (NSException *ex) {
1392 NSWindow *w = [ch objectAtIndex:x];
1394 // only validate children of our windows (maybe an option for this?)
1395 ([w isKindOfClass:[SWELL_ModelessWindow class]] || [w isKindOfClass:[SWELL_ModalDialog class]]) &&
1396 IsWindowImpl((NSView*)hwnd,[w contentView]))
1402 @catch (NSException *ex) {
1413 bool IsWindowVisible(HWND hwnd)
1415 if (!hwnd) return false;
1419 if ([turd isKindOfClass:[NSView class]])
1421 NSWindow *w = [turd window];
1422 if (w && ![w isVisible]) return false;
1424 return ![turd isHiddenOrHasHiddenAncestor];
1426 if ([turd isKindOfClass:[NSWindow class]])
1428 return !![turd isVisible];
1434 static void *__GetNSImageFromHICON(HICON ico) // local copy to not be link dependent on swell-gdi.mm
1436 HGDIOBJ__ *i = (HGDIOBJ__ *)ico;
1437 if (!i || i->type != TYPE_BITMAP) return 0;
1438 return i->bitmapptr;
1442 @implementation SWELL_Button : NSButton
1444 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
1447 self = [super init];
1455 -(int)swellGetRadioFlags { return m_radioflags; }
1456 -(void)swellSetRadioFlags:(int)f { m_radioflags=f; }
1457 -(LONG_PTR)getSwellUserData { return m_userdata; }
1458 -(void)setSwellUserData:(LONG_PTR)val { m_userdata=val; }
1460 -(void)setSwellGDIImage:(void *)par
1462 m_swellGDIimage=par;
1464 -(void *)getSwellGDIImage
1466 return m_swellGDIimage;
1471 LRESULT SendMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1473 if (!hwnd) return 0;
1477 if ([obj respondsToSelector:@selector(onSwellMessage:p1:p2:)])
1479 return (LRESULT) [obj onSwellMessage:msg p1:wParam p2:lParam];
1483 if (msg == BM_GETCHECK && [obj isKindOfClass:[NSButton class]])
1485 NSInteger a=[(NSButton*)obj state];
1486 if (a==NSMixedState) return BST_INDETERMINATE;
1487 return a!=NSOffState;
1489 if (msg == BM_SETCHECK && [obj isKindOfClass:[NSButton class]])
1491 [(NSButton*)obj setState:(wParam&BST_INDETERMINATE)?NSMixedState:((wParam&BST_CHECKED)?NSOnState:NSOffState)];
1494 if ((msg==BM_GETIMAGE || msg == BM_SETIMAGE) && [obj isKindOfClass:[SWELL_Button class]])
1496 if (wParam != IMAGE_BITMAP && wParam != IMAGE_ICON) return 0; // ignore unknown types
1497 LONG_PTR ret=(LONG_PTR) (void *)[obj getSwellGDIImage];
1498 if (msg==BM_SETIMAGE)
1501 if (lParam) img=(NSImage *)__GetNSImageFromHICON((HICON)lParam);
1503 [obj setSwellGDIImage:(void *)(img?lParam:0)];
1507 else if (msg >= CB_ADDSTRING && msg <= CB_INITSTORAGE && ([obj isKindOfClass:[NSPopUpButton class]] || [obj isKindOfClass:[NSComboBox class]]))
1511 case CB_ADDSTRING: return SWELL_CB_AddString(hwnd,0,(char*)lParam);
1512 case CB_DELETESTRING: SWELL_CB_DeleteString(hwnd,0,(int)wParam); return 1;
1513 case CB_GETCOUNT: return SWELL_CB_GetNumItems(hwnd,0);
1514 case CB_GETCURSEL: return SWELL_CB_GetCurSel(hwnd,0);
1515 case CB_GETLBTEXT: return SWELL_CB_GetItemText(hwnd,0,(int)wParam,(char *)lParam, 1<<20);
1516 case CB_GETLBTEXTLEN: return SWELL_CB_GetItemText(hwnd,0,(int)wParam,NULL,0);
1517 case CB_INSERTSTRING: return SWELL_CB_InsertString(hwnd,0,(int)wParam,(char *)lParam);
1518 case CB_RESETCONTENT: SWELL_CB_Empty(hwnd,0); return 0;
1519 case CB_SETCURSEL: SWELL_CB_SetCurSel(hwnd,0,(int)wParam); return 0;
1520 case CB_GETITEMDATA: return SWELL_CB_GetItemData(hwnd,0,(int)wParam);
1521 case CB_SETITEMDATA: SWELL_CB_SetItemData(hwnd,0,(int)wParam,lParam); return 0;
1523 case CB_FINDSTRINGEXACT:
1524 if (lParam) return SWELL_CB_FindString(hwnd,0,(int)wParam,(const char *)lParam,msg==CB_FINDSTRINGEXACT);
1526 case CB_INITSTORAGE: return 0;
1530 else if (msg >= TBM_GETPOS && msg <= TBM_SETRANGE && ([obj isKindOfClass:[NSSlider class]]))
1534 case TBM_GETPOS: return SWELL_TB_GetPos(hwnd,0);
1535 case TBM_SETTIC: SWELL_TB_SetTic(hwnd,0,(int)lParam); return 1;
1536 case TBM_SETPOS: SWELL_TB_SetPos(hwnd,0,(int)lParam); return 1;
1537 case TBM_SETRANGE: SWELL_TB_SetRange(hwnd,0,LOWORD(lParam),HIWORD(lParam)); return 1;
1541 else if ((msg == EM_SETSEL || msg == EM_GETSEL || msg == EM_SETPASSWORDCHAR) && ([obj isKindOfClass:[NSTextField class]]))
1543 if (msg == EM_GETSEL)
1546 NSResponder *rs = [[obj window] firstResponder];
1547 if ([rs isKindOfClass:[NSView class]] && [(NSView *)rs isDescendantOf:obj])
1549 NSText* text=[[obj window] fieldEditor:YES forObject:(NSTextField*)obj];
1550 if (text) range=[text selectedRange];
1552 if (wParam) *(int*)wParam=(int)range.location;
1553 if (lParam) *(int*)lParam=(int)(range.location+range.length);
1555 else if (msg == EM_SETSEL)
1557 // [(NSTextField*)obj selectText:obj]; // Force the window's text field editor onto this control
1558 // don't force it, just ignore EM_GETSEL/EM_SETSEL if not in focus
1559 NSResponder *rs = [[obj window] firstResponder];
1560 if ([rs isKindOfClass:[NSView class]] && [(NSView *)rs isDescendantOf:obj])
1562 NSText* text = [[obj window] fieldEditor:YES forObject:(NSTextField*)obj]; // then get it from the window
1563 NSUInteger sl = [[text string] length];
1564 if (wParam == -1) lParam = wParam = 0;
1565 else if (lParam == -1) lParam = sl;
1566 if (wParam>sl) wParam=sl;
1567 if (lParam>sl) lParam=sl;
1568 if (text) [text setSelectedRange:NSMakeRange(wParam, wdl_max(lParam-wParam,0))]; // and set the range
1571 else if (msg == EM_SETPASSWORDCHAR)
1573 // not implemented, because it requires replacing obj within its parent window
1574 // instead caller explicitly destroy the edit control and create a new one with ES_PASSWORD
1582 // if content view gets unhandled message send to window
1583 if ([obj isKindOfClass:[NSView class]] && (w=[obj window]) && [w contentView] == obj && [w respondsToSelector:@selector(onSwellMessage:p1:p2:)])
1585 return (LRESULT) [(SWELL_hwndChild *)w onSwellMessage:msg p1:wParam p2:lParam];
1587 // if window gets unhandled message send to content view
1588 else if ([obj isKindOfClass:[NSWindow class]] && (v=[obj contentView]) && [v respondsToSelector:@selector(onSwellMessage:p1:p2:)])
1590 return (LRESULT) [(SWELL_hwndChild *)v onSwellMessage:msg p1:wParam p2:lParam];
1598 void DestroyWindow(HWND hwnd)
1603 if ([pid isKindOfClass:[NSView class]])
1605 KillTimer(hwnd,~(UINT_PTR)0);
1606 sendSwellMessage((id)pid,WM_DESTROY,0,0);
1608 NSWindow *pw = [(NSView *)pid window];
1609 if (pw && [pw contentView] == pid) // destroying contentview should destroy top level window
1611 DestroyWindow((HWND)pw);
1615 if (pw && [NSApp keyWindow] == pw)
1617 id foc=[pw firstResponder];
1618 if (foc && (foc == pid || IsChild((HWND)pid,(HWND)foc)))
1620 HWND h=GetParent((HWND)pid);
1624 [(NSView *)pid removeFromSuperview];
1627 else if ([pid isKindOfClass:[NSWindow class]])
1629 KillTimer(hwnd,~(UINT_PTR)0);
1630 sendSwellMessage([(id)pid contentView],WM_DESTROY,0,0);
1631 sendSwellMessage((id)pid,WM_DESTROY,0,0);
1633 if ([(id)pid respondsToSelector:@selector(swellDoDestroyStuff)])
1634 [(id)pid swellDoDestroyStuff];
1636 NSWindow *par=[(NSWindow*)pid parentWindow];
1639 [par removeChildWindow:(NSWindow*)pid];
1641 [(NSWindow *)pid close]; // this is probably bad, but close takes too long to close!
1646 void EnableWindow(HWND hwnd, int enable)
1651 if ([bla isKindOfClass:[NSWindow class]]) bla = [bla contentView];
1653 if (bla && [bla respondsToSelector:@selector(setEnabled:)])
1655 if (enable == -1000 && [bla respondsToSelector:@selector(setEnabledSwellNoFocus)])
1656 [bla setEnabledSwellNoFocus];
1658 [bla setEnabled:(enable?YES:NO)];
1659 if ([bla isKindOfClass:[SWELL_TextField class]])
1661 NSTextField* txt = (NSTextField*)bla;
1662 if (![txt isEditable] && ![txt isBordered] && ![txt drawsBackground]) // looks like a static text control
1664 NSColor* col = [txt textColor];
1665 float alpha = (enable ? 1.0f : 0.5f);
1666 [txt setTextColor:[col colorWithAlphaComponent:alpha]];
1673 void SetForegroundWindow(HWND hwnd)
1678 void SetFocus(HWND hwnd) // these take NSWindow/NSView, and return NSView *
1684 if ([r isKindOfClass:[NSWindow class]])
1686 [(NSWindow *)r makeFirstResponder:[(NSWindow *)r contentView]];
1687 if ([(NSWindow *)r isVisible]) [(NSWindow *)r makeKeyAndOrderFront:nil];
1689 else if ([r isKindOfClass:[NSView class]])
1691 NSWindow *wnd=[(NSView *)r window];
1694 [wnd makeFirstResponder:r];
1695 if ([wnd isVisible])
1697 [wnd makeKeyAndOrderFront:nil];
1704 void SWELL_GetViewPort(RECT *r, const RECT *sourcerect, bool wantWork)
1708 NSArray *ar=[NSScreen screens];
1710 const NSInteger cnt=[ar count];
1715 cx=(sourcerect->left+sourcerect->right)/2;
1716 cy=(sourcerect->top+sourcerect->bottom)/2;
1718 for (NSInteger x = 0; x < cnt; x ++)
1720 NSScreen *sc=[ar objectAtIndex:x];
1723 NSRect tr=wantWork ? [sc visibleFrame] : [sc frame];
1724 if (!x || (cx >= tr.origin.x && cx < tr.origin.x+tr.size.width &&
1725 cy >= tr.origin.y && cy < tr.origin.y+tr.size.height))
1727 r->left=(int)tr.origin.x;
1728 r->right=(int)(tr.origin.x+tr.size.width+0.5);
1729 r->top=(int)tr.origin.y;
1730 r->bottom=(int)(tr.origin.y+tr.size.height+0.5);
1743 void ScreenToClient(HWND hwnd, POINT *p)
1746 // no need to try/catch, this should never have an issue *wince*
1749 if ([ch isKindOfClass:[NSWindow class]]) ch=[((NSWindow *)ch) contentView];
1750 if (!ch || ![ch isKindOfClass:[NSView class]]) return;
1752 NSWindow *window=[ch window];
1754 NSPoint wndpt = [window convertScreenToBase:NSMakePoint(p->x,p->y)];
1756 // todo : WM_NCCALCSIZE
1757 NSPoint po = [ch convertPoint:wndpt fromView:nil];
1759 p->x=(int)(po.x+0.5);
1760 p->y=(int)(po.y+0.5);
1763 void ClientToScreen(HWND hwnd, POINT *p)
1768 if ([ch isKindOfClass:[NSWindow class]]) ch=[((NSWindow *)ch) contentView];
1769 if (!ch || ![ch isKindOfClass:[NSView class]]) return;
1771 NSWindow *window=[ch window];
1773 NSPoint wndpt = [ch convertPoint:NSMakePoint(p->x,p->y) toView:nil];
1775 NSPoint po = [window convertBaseToScreen:wndpt];
1776 // todo : WM_NCCALCSIZE
1778 p->x=(int)(po.x+0.5);
1779 p->y=(int)(po.y+0.5);
1782 static NSView *NavigateUpScrollClipViews(NSView *ch)
1784 NSView *par=[ch superview];
1785 if (par && [par isKindOfClass:[NSClipView class]])
1787 par=[par superview];
1788 if (par && [par isKindOfClass:[NSScrollView class]])
1796 HWND SWELL_NavigateUpScrollClipViews(HWND h)
1799 if (h && [(id)h isKindOfClass:[NSView class]]) v = (NSView *)h;
1800 else if (h && [(id)h isKindOfClass:[NSWindow class]]) v = [(NSWindow *)h contentView];
1802 return (HWND)NavigateUpScrollClipViews(v);
1806 bool GetWindowRect(HWND hwnd, RECT *r)
1808 r->left=r->top=r->right=r->bottom=0;
1809 if (!hwnd) return false;
1815 if ([ch isKindOfClass:[NSView class]] && (nswnd=[(NSView *)ch window]) && [nswnd contentView]==ch)
1818 if ([ch isKindOfClass:[NSWindow class]])
1820 NSRect b=[ch frame];
1821 r->left=(int)(b.origin.x);
1822 r->top=(int)(b.origin.y);
1823 r->right = (int)(b.origin.x+b.size.width+0.5);
1824 r->bottom= (int)(b.origin.y+b.size.height+0.5);
1827 if (![ch isKindOfClass:[NSView class]]) return false;
1828 ch=NavigateUpScrollClipViews(ch);
1829 NSRect b=[ch bounds];
1830 r->left=(int)(b.origin.x);
1831 r->top=(int)(b.origin.y);
1832 r->right = (int)(b.origin.x+b.size.width+0.5);
1833 r->bottom= (int)(b.origin.y+b.size.height+0.5);
1834 ClientToScreen((HWND)ch,(POINT *)r);
1835 ClientToScreen((HWND)ch,((POINT *)r)+1);
1836 SWELL_END_TRY(return false;)
1841 void GetWindowContentViewRect(HWND hwnd, RECT *r)
1845 if (hwnd && [(id)hwnd isKindOfClass:[NSView class]] && (nswnd=[(NSView *)hwnd window]) && [nswnd contentView]==(id)hwnd)
1848 if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]])
1850 NSView *ch=[(id)hwnd contentView];
1851 NSRect b=[ch bounds];
1852 r->left=(int)(b.origin.x);
1853 r->top=(int)(b.origin.y);
1854 r->right = (int)(b.origin.x+b.size.width+0.5);
1855 r->bottom= (int)(b.origin.y+b.size.height+0.5);
1856 ClientToScreen(hwnd,(POINT *)r);
1857 ClientToScreen(hwnd,((POINT *)r)+1);
1859 else GetWindowRect(hwnd,r);
1864 void GetClientRect(HWND hwnd, RECT *r)
1866 r->left=r->top=r->right=r->bottom=0;
1871 if ([ch isKindOfClass:[NSWindow class]]) ch=[((NSWindow *)ch) contentView];
1872 if (!ch || ![ch isKindOfClass:[NSView class]]) return;
1873 ch=NavigateUpScrollClipViews(ch);
1875 NSRect b=[ch bounds];
1876 r->left=(int)(b.origin.x);
1877 r->top=(int)(b.origin.y);
1878 r->right = (int)(b.origin.x+b.size.width+0.5);
1879 r->bottom= (int)(b.origin.y+b.size.height+0.5);
1881 // todo this may need more attention
1882 NCCALCSIZE_PARAMS tr={{*r,},};
1883 SendMessage(hwnd,WM_NCCALCSIZE,FALSE,(LPARAM)&tr);
1884 r->right = r->left + (tr.rgrc[0].right-tr.rgrc[0].left);
1885 r->bottom = r->top + (tr.rgrc[0].bottom-tr.rgrc[0].top);
1891 void SetWindowPos(HWND hwnd, HWND hwndAfter, int x, int y, int cx, int cy, int flags)
1896 NSWindow *nswnd; // content views = move window
1897 if (hwnd && [(id)hwnd isKindOfClass:[NSView class]] && (nswnd=[(NSView *)hwnd window]) && [nswnd contentView]==(id)hwnd)
1900 // todo: handle SWP_SHOWWINDOW
1903 if ([ch isKindOfClass:[NSWindow class]] || (isview=[ch isKindOfClass:[NSView class]]))
1907 ch=NavigateUpScrollClipViews(ch);
1908 if (isview && !(flags&SWP_NOZORDER))
1910 NSView *v = (NSView *)ch;
1911 NSView *par = [v superview];
1912 NSArray *subs = [par subviews];
1913 NSInteger idx = [subs indexOfObjectIdenticalTo:v], cnt=[subs count];
1915 NSView *viewafter = NULL;
1916 NSWindowOrderingMode omode = NSWindowAbove;
1918 if (cnt>1 && hwndAfter != (HWND)ch)
1920 if (hwndAfter==HWND_TOPMOST||hwndAfter==HWND_NOTOPMOST)
1923 else if (hwndAfter == HWND_TOP)
1925 if (idx<cnt-1) viewafter = [subs objectAtIndex:cnt-1];
1927 else if (hwndAfter == HWND_BOTTOM)
1929 if (idx>0) viewafter = [subs objectAtIndex:0];
1930 omode = NSWindowBelow;
1934 NSInteger a=[subs indexOfObjectIdenticalTo:(NSView *)hwndAfter];
1935 if (a != NSNotFound && a != (idx-1)) viewafter = (NSView *)hwndAfter;
1941 HWND h = GetCapture();
1942 if (!h || (h!=(HWND)v && !IsChild((HWND)v,h))) // if this window is captured don't reorder!
1944 NSView *oldfoc = (NSView*)[[v window] firstResponder];
1945 if (!oldfoc || ![oldfoc isKindOfClass:[NSView class]] ||
1946 (oldfoc != v && ![oldfoc isDescendantOf:v])) oldfoc=NULL;
1948 // better way to do this? maybe :/
1950 [v removeFromSuperviewWithoutNeedingDisplay];
1951 [par addSubview:v positioned:omode relativeTo:viewafter];
1954 if (oldfoc) [[v window] makeFirstResponder:oldfoc];
1959 NSRect f=[ch frame];
1961 if (!(flags&SWP_NOMOVE))
1963 f.origin.x=(float)x;
1964 f.origin.y=(float)y;
1967 if (!(flags&SWP_NOSIZE))
1969 f.size.width=(float)cx;
1970 f.size.height=(float)cy;
1971 if (f.size.height<0)f.size.height=-f.size.height;
1978 NSSize mins=[ch minSize];
1979 NSSize maxs=[ch maxSize];
1980 if (f.size.width < mins.width) f.size.width=mins.width;
1981 else if (f.size.width > maxs.width) f.size.width=maxs.width;
1982 if (f.size.height < mins.height) f.size.height=mins.height;
1983 else if (f.size.height> maxs.height) f.size.height=maxs.height;
1984 [ch setFrame:f display:NO];
1989 // this doesnt seem to actually be a good idea anymore
1990 // if ([[ch window] contentView] != ch && ![[ch superview] isFlipped])
1991 // f.origin.y -= f.size.height;
1993 if ([ch isKindOfClass:[NSScrollView class]])
1995 NSView *cv=[ch documentView];
1996 if (cv && [cv isKindOfClass:[NSTextView class]])
1998 NSRect fr=[cv frame];
1999 NSSize sz=[ch contentSize];
2001 if (![ch hasHorizontalScroller]) {a ++; fr.size.width=sz.width; }
2002 if (![ch hasVerticalScroller]) { a++; fr.size.height=sz.height; }
2003 if (a) [cv setFrame:fr];
2013 BOOL EnumWindows(BOOL (*proc)(HWND, LPARAM), LPARAM lp)
2015 NSArray *ch=[NSApp windows];
2017 const NSInteger n=[ch count];
2018 for(NSInteger x=0;x<n; x ++)
2020 NSWindow *w = [ch objectAtIndex:x];
2021 if (!proc((HWND)[w contentView],lp))
2032 HWND GetWindow(HWND hwnd, int what)
2034 if (!hwnd) return 0;
2037 if ([(id)hwnd isKindOfClass:[NSWindow class]]) hwnd=(HWND)[(id)hwnd contentView];
2038 if (!hwnd || ![(id)hwnd isKindOfClass:[NSView class]]) return 0;
2040 NSView *v=(NSView *)hwnd;
2041 if (what == GW_CHILD)
2043 NSArray *ar=[v subviews];
2044 if (ar && [ar count]>0)
2046 return (HWND)[ar objectAtIndex:0];
2050 if (what == GW_OWNER)
2052 v=NavigateUpScrollClipViews(v);
2053 if ([[v window] contentView] == v)
2055 if ([[v window] respondsToSelector:@selector(swellGetOwner)])
2057 return (HWND)[(SWELL_ModelessWindow*)[v window] swellGetOwner];
2061 return (HWND)[v superview];
2064 if (what >= GW_HWNDFIRST && what <= GW_HWNDPREV)
2066 v=NavigateUpScrollClipViews(v);
2067 if ([[v window] contentView] == v)
2069 if (what <= GW_HWNDLAST) return (HWND)hwnd; // content view is only window
2071 return 0; // we're the content view so cant do next/prev
2073 NSView *par=[v superview];
2076 NSArray *ar=[par subviews];
2078 if (ar && (cnt=[ar count]) > 0)
2080 if (what == GW_HWNDFIRST)
2081 return (HWND)[ar objectAtIndex:0];
2082 if (what == GW_HWNDLAST)
2083 return (HWND)[ar objectAtIndex:(cnt-1)];
2085 NSInteger idx=[ar indexOfObjectIdenticalTo:v];
2086 if (idx == NSNotFound) return 0;
2088 if (what==GW_HWNDNEXT) idx++;
2089 else if (what==GW_HWNDPREV) idx--;
2091 if (idx<0 || idx>=cnt) return 0;
2093 return (HWND)[ar objectAtIndex:idx];
2103 HWND GetParent(HWND hwnd)
2106 if (hwnd && [(id)hwnd isKindOfClass:[NSView class]])
2108 hwnd=(HWND)NavigateUpScrollClipViews((NSView *)hwnd);
2110 NSView *cv=[[(NSView *)hwnd window] contentView];
2111 if (cv == (NSView *)hwnd) hwnd=(HWND)[(NSView *)hwnd window]; // passthrough to get window parent
2114 HWND h=(HWND)[(NSView *)hwnd superview];
2119 if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]])
2121 HWND h= (HWND)[(NSWindow *)hwnd parentWindow];
2122 if (h) h=(HWND)[(NSWindow *)h contentView];
2126 if (hwnd && [(id)hwnd respondsToSelector:@selector(swellGetOwner)])
2128 HWND h= (HWND)[(SWELL_ModelessWindow *)hwnd swellGetOwner];
2129 if (h && [(id)h isKindOfClass:[NSWindow class]]) h=(HWND)[(NSWindow *)h contentView];
2137 HWND SetParent(HWND hwnd, HWND newPar)
2140 NSView *v=(NSView *)hwnd;
2141 if (!v || ![(id)v isKindOfClass:[NSView class]]) return 0;
2142 v=NavigateUpScrollClipViews(v);
2144 if ([(id)hwnd isKindOfClass:[NSView class]])
2146 NSView *tv=(NSView *)hwnd;
2147 if ([[tv window] contentView] == tv) // if we're reparenting a contentview (aka top level window)
2149 if (!newPar) return NULL;
2151 NSView *npv = (NSView *)newPar;
2152 if ([npv isKindOfClass:[NSWindow class]]) npv=[(NSWindow *)npv contentView];
2153 if (!npv || ![npv isKindOfClass:[NSView class]])
2156 char oldtitle[2048];
2158 GetWindowText(hwnd,oldtitle,sizeof(oldtitle));
2160 NSWindow *oldwnd = [tv window];
2162 if ([oldwnd respondsToSelector:@selector(swellGetOwner)]) oldown=[(SWELL_ModelessWindow*)oldwnd swellGetOwner];
2164 if ([tv isKindOfClass:[SWELL_hwndChild class]]) ((SWELL_hwndChild*)tv)->m_lastTopLevelOwner = oldown;
2167 SWELL_hwndChild *tmpview = [[SWELL_hwndChild alloc] initChild:nil Parent:(NSView *)oldwnd dlgProc:nil Param:0];
2170 [npv addSubview:tv];
2173 DestroyWindow((HWND)oldwnd); // close old window since its no longer used
2174 if (oldtitle[0]) SetWindowText(hwnd,oldtitle);
2177 else if (!newPar) // not content view, not parent (so making it a top level modeless dialog)
2179 char oldtitle[2048];
2181 GetWindowText(hwnd,oldtitle,sizeof(oldtitle));
2184 [tv removeFromSuperview];
2187 unsigned int wf=(NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask|NSResizableWindowMask);
2188 if ([tv respondsToSelector:@selector(swellCreateWindowFlags)])
2189 wf=(unsigned int)[(SWELL_hwndChild *)tv swellCreateWindowFlags];
2192 if ([tv isKindOfClass:[SWELL_hwndChild class]])
2194 id oldown = ((SWELL_hwndChild*)tv)->m_lastTopLevelOwner;
2197 NSArray *ch=[NSApp windows];
2198 const NSInteger n = [ch count];
2199 for(NSInteger x=0;x<n && !newOwner; x ++)
2201 NSWindow *w = [ch objectAtIndex:x];
2202 if (w == (NSWindow *)oldown || [w contentView] == (NSView *)oldown) newOwner = (HWND)w;
2207 HWND SWELL_CreateModelessFrameForWindow(HWND childW, HWND ownerW, unsigned int);
2208 HWND bla=SWELL_CreateModelessFrameForWindow((HWND)tv,(HWND)newOwner,wf);
2209 // create a new modeless frame
2213 [(NSWindow *)bla display];
2217 if (oldtitle[0]) SetWindowText(hwnd,oldtitle);
2223 HWND ret=(HWND) [v superview];
2227 [v removeFromSuperview];
2229 NSView *np=(NSView *)newPar;
2230 if (np && [np isKindOfClass:[NSWindow class]]) np=[(NSWindow *)np contentView];
2232 if (np && [np isKindOfClass:[NSView class]])
2243 int IsChild(HWND hwndParent, HWND hwndChild)
2245 if (!hwndParent || !hwndChild || hwndParent == hwndChild) return 0;
2247 id par=(id)hwndParent;
2248 id ch=(id)hwndChild;
2249 if (![ch isKindOfClass:[NSView class]]) return 0;
2250 if ([par isKindOfClass:[NSWindow class]])
2252 return [ch window] == par;
2254 else if ([par isKindOfClass:[NSView class]])
2256 return !![ch isDescendantOf:par];
2262 HWND GetForegroundWindow()
2265 NSWindow *window=[NSApp keyWindow];
2266 if (!window) return 0;
2267 id ret=[window firstResponder];
2268 if (ret && [ret isKindOfClass:[NSView class]])
2270 // if (ret == [window contentView]) return (HWND) window;
2273 return (HWND)window;
2281 NSWindow *window=[NSApp keyWindow];
2282 if (!window) return 0;
2283 id ret=[window firstResponder];
2284 if (ret && [ret isKindOfClass:[NSView class]])
2286 // if (ret == [window contentView]) return (HWND) window;
2288 if ([ret isKindOfClass:[NSTextView class]] && [ret superview] && [[ret superview] superview])
2290 NSView* v = [[ret superview] superview];
2291 if ([v isKindOfClass:[NSTextField class]]) return (HWND) v;
2300 bool IsEquivalentTextView(HWND h1, HWND h2)
2302 if (!h1 || !h2) return false;
2303 if (h1 == h2) return true;
2305 NSView* v1 = (NSView*)h1;
2306 NSView* v2 = (NSView*)h2;
2307 if ([v1 isKindOfClass:[NSTextField class]] && [v2 isKindOfClass:[NSTextView class]])
2313 if ([v1 isKindOfClass: [NSTextView class]] && [v2 isKindOfClass:[NSTextField class]])
2315 if ([v1 superview] && [[v1 superview] superview] && [[[v1 superview] superview] superview] == v2) return true;
2323 BOOL SetDlgItemText(HWND hwnd, int idx, const char *text)
2325 NSView *obj=(NSView *)(idx ? GetDlgItem(hwnd,idx) : hwnd);
2326 if (!obj) return false;
2330 if ([(id)obj isKindOfClass:[NSView class]] && (nswnd=[(NSView *)obj window]) && [nswnd contentView]==(id)obj)
2332 SetDlgItemText((HWND)nswnd,0,text); // also set window if setting content view
2335 if ([obj respondsToSelector:@selector(onSwellSetText:)])
2337 [(SWELL_hwndChild*)obj onSwellSetText:text];
2342 NSString *lbl=(NSString *)SWELL_CStringToCFString(text);
2343 if ([obj isKindOfClass:[NSWindow class]] || [obj isKindOfClass:[NSButton class]]) [(NSButton*)obj setTitle:lbl];
2344 else if ([obj isKindOfClass:[NSControl class]])
2346 [(NSControl*)obj setStringValue:lbl];
2347 if ([obj isKindOfClass:[NSTextField class]] && [(NSTextField *)obj isEditable])
2349 SendMessage(GetParent((HWND)obj),WM_COMMAND,[(NSControl *)obj tag]|(EN_CHANGE<<16),(LPARAM)obj);
2352 else if ([obj isKindOfClass:[NSText class]])
2354 // todo if there is a way to find out that the window's NSTextField is already assigned
2355 // to another field, restore the assignment afterwards
2356 [(NSText*)obj setString:lbl];
2357 [obj setNeedsDisplay:YES]; // required on Sierra, it seems -- if the parent is hidden (e.g. DialogBox() + WM_INITDIALOG), the view is not drawn
2359 else if ([obj isKindOfClass:[NSBox class]])
2361 [(NSBox *)obj setTitle:lbl];
2374 BOOL GetDlgItemText(HWND hwnd, int idx, char *text, int textlen)
2377 NSView *pvw=(NSView *)(idx?GetDlgItem(hwnd,idx) : hwnd);
2378 if (!pvw) return false;
2382 if ([(id)pvw isKindOfClass:[NSView class]] && [[(id)pvw window] contentView] == pvw)
2384 pvw=(NSView *)[(id)pvw window];
2387 if ([(id)pvw respondsToSelector:@selector(onSwellGetText)])
2389 const char *p=(const char *)[(SWELL_hwndChild*)pvw onSwellGetText];
2390 lstrcpyn_safe(text,p?p:"",textlen);
2396 if ([pvw isKindOfClass:[NSButton class]]||[pvw isKindOfClass:[NSWindow class]]) s=[((NSButton *)pvw) title];
2397 else if ([pvw isKindOfClass:[NSControl class]]) s=[((NSControl *)pvw) stringValue];
2398 else if ([pvw isKindOfClass:[NSText class]]) s=[(NSText*)pvw string];
2399 else if ([pvw isKindOfClass:[NSBox class]]) s=[(NSBox *)pvw title];
2402 if (s) SWELL_CFStringToCString(s,text,textlen);
2403 // [s getCString:text maxLength:textlen];
2410 void CheckDlgButton(HWND hwnd, int idx, int check)
2412 NSView *pvw=(NSView *)GetDlgItem(hwnd,idx);
2414 if ([pvw isKindOfClass:[NSButton class]])
2415 [(NSButton*)pvw setState:(check&BST_INDETERMINATE)?NSMixedState:((check&BST_CHECKED)?NSOnState:NSOffState)];
2419 int IsDlgButtonChecked(HWND hwnd, int idx)
2421 NSView *pvw=(NSView *)GetDlgItem(hwnd,idx);
2422 if (pvw && [pvw isKindOfClass:[NSButton class]])
2424 NSInteger a=[(NSButton*)pvw state];
2425 if (a==NSMixedState) return BST_INDETERMINATE;
2426 return a!=NSOffState;
2431 void SWELL_TB_SetPos(HWND hwnd, int idx, int pos)
2433 NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2434 if (p && [p isKindOfClass:[NSSlider class]])
2436 [p setDoubleValue:(double)pos];
2440 sendSwellMessage(p,TBM_SETPOS,1,pos);
2444 void SWELL_TB_SetRange(HWND hwnd, int idx, int low, int hi)
2446 NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2447 if (p && [p isKindOfClass:[NSSlider class]])
2449 [p setMinValue:low];
2454 sendSwellMessage(p,TBM_SETRANGE,1,((low&0xffff)|(hi<<16)));
2459 int SWELL_TB_GetPos(HWND hwnd, int idx)
2461 NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2462 if (p && [p isKindOfClass:[NSSlider class]])
2464 return (int) ([p doubleValue]+0.5);
2468 return (int) sendSwellMessage(p,TBM_GETPOS,0,0);
2473 void SWELL_TB_SetTic(HWND hwnd, int idx, int pos)
2475 NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2476 sendSwellMessage(p,TBM_SETTIC,0,pos);
2479 void SWELL_CB_DeleteString(HWND hwnd, int idx, int wh)
2481 NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2483 if ([p isKindOfClass:[SWELL_ComboBox class]])
2485 if (wh>=0 && wh<[p numberOfItems])
2487 [p removeItemAtIndex:wh];
2488 if (((SWELL_ComboBox*)p)->m_ids) ((SWELL_ComboBox*)p)->m_ids->Delete(wh);
2491 else if ( [p isKindOfClass:[NSPopUpButton class]])
2493 NSMenu *menu = [p menu];
2496 if (wh >= 0 && wh < [menu numberOfItems])
2497 [menu removeItemAtIndex:wh];
2503 int SWELL_CB_FindString(HWND hwnd, int idx, int startAfter, const char *str, bool exact)
2505 NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2508 int pos = startAfter;
2512 const size_t l1len = strlen(str);
2513 const int ni=(int)[p numberOfItems];
2515 if ([p isKindOfClass:[NSComboBox class]])
2519 NSString *s=[p itemObjectValueAtIndex:pos];
2523 SWELL_CFStringToCString(s,buf,sizeof(buf));
2524 if (exact ? !stricmp(str,buf) : !strnicmp(str,buf,l1len))
2533 NSMenuItem *i=[(NSPopUpButton *)p itemAtIndex:pos];
2536 NSString *s=[i title];
2540 SWELL_CFStringToCString(s,buf,sizeof(buf));
2541 if (exact ? !stricmp(str,buf) : !strnicmp(str,buf,l1len))
2550 int SWELL_CB_GetItemText(HWND hwnd, int idx, int item, char *buf, int bufsz)
2552 NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2555 if (!p) return CB_ERR;
2556 const int ni = (int)[p numberOfItems];
2557 if (item < 0 || item >= ni) return CB_ERR;
2559 if ([p isKindOfClass:[NSComboBox class]])
2561 NSString *s=[p itemObjectValueAtIndex:item];
2564 if (!buf) return (int) ([s lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 64);
2566 SWELL_CFStringToCString(s,buf,bufsz);
2572 NSMenuItem *i=[(NSPopUpButton *)p itemAtIndex:item];
2575 NSString *s=[i title];
2578 if (!buf) return (int) ([s lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 64);
2580 SWELL_CFStringToCString(s,buf,bufsz);
2589 int SWELL_CB_InsertString(HWND hwnd, int idx, int pos, const char *str)
2591 NSString *label=(NSString *)SWELL_CStringToCFString(str);
2592 NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2595 bool isAppend=false;
2596 const int ni = (int)[p numberOfItems];
2602 else if (pos < 0) pos=0;
2603 else if (pos > ni) pos=ni;
2606 if ([p isKindOfClass:[SWELL_ComboBox class]])
2608 if (isAppend && (((int)[(SWELL_ComboBox*)p getSwellStyle]) & CBS_SORT))
2610 pos=(int)arr_bsearch_mod(label,[p objectValues],_nsStringSearchProc);
2614 [p addItemWithObjectValue:label];
2616 [p insertItemWithObjectValue:label atIndex:pos];
2618 if (((SWELL_ComboBox*)p)->m_ids) ((SWELL_ComboBox*)p)->m_ids->Insert(pos,(char*)0);
2619 [p setNumberOfVisibleItems:(ni+1)];
2623 NSMenu *menu = [(NSPopUpButton *)p menu];
2626 const bool needclearsel = [p indexOfSelectedItem] < 0;
2627 if (isAppend && [p respondsToSelector:@selector(getSwellStyle)] && (((int)[(SWELL_PopUpButton*)p getSwellStyle]) & CBS_SORT))
2629 pos=(int)arr_bsearch_mod(label,[menu itemArray],_nsMenuSearchProc);
2631 NSMenuItem *item=[menu insertItemWithTitle:label action:NULL keyEquivalent:@"" atIndex:pos];
2632 [item setEnabled:YES];
2633 if (needclearsel) [(NSPopUpButton *)p selectItemAtIndex:-1];
2641 int SWELL_CB_AddString(HWND hwnd, int idx, const char *str)
2643 return SWELL_CB_InsertString(hwnd,idx,-1000,str);
2646 int SWELL_CB_GetCurSel(HWND hwnd, int idx)
2648 NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2650 return (int)[p indexOfSelectedItem];
2653 void SWELL_CB_SetCurSel(HWND hwnd, int idx, int item)
2655 NSComboBox *cb = (NSComboBox *)GetDlgItem(hwnd,idx);
2658 if (item < 0 || item >= [cb numberOfItems])
2660 // combo boxes can be NSComboBox or NSPopupButton, NSComboBox needs
2661 // a different deselect method (selectItemAtIndex:-1 throws an exception)
2662 if ([cb isKindOfClass:[NSComboBox class]])
2664 const NSInteger sel = [cb indexOfSelectedItem];
2665 if (sel>=0) [cb deselectItemAtIndex:sel];
2667 else if ([cb isKindOfClass:[NSPopUpButton class]])
2668 [(NSPopUpButton*)cb selectItemAtIndex:-1];
2671 [cb selectItemAtIndex:item];
2674 int SWELL_CB_GetNumItems(HWND hwnd, int idx)
2676 NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2678 return (int)[p numberOfItems];
2683 void SWELL_CB_SetItemData(HWND hwnd, int idx, int item, LONG_PTR data)
2685 id cb=(id)GetDlgItem(hwnd,idx);
2688 if ([cb isKindOfClass:[NSPopUpButton class]])
2690 if (item < 0 || item >= [cb numberOfItems]) return;
2691 NSMenuItem *it=[(NSPopUpButton*)cb itemAtIndex:item];
2694 SWELL_DataHold *p=[[SWELL_DataHold alloc] initWithVal:(void *)data];
2695 [it setRepresentedObject:p];
2698 else if ([cb isKindOfClass:[SWELL_ComboBox class]])
2700 if (item < 0 || item >= [cb numberOfItems]) return;
2701 if (((SWELL_ComboBox*)cb)->m_ids) ((SWELL_ComboBox*)cb)->m_ids->Set(item,(char*)data);
2705 LONG_PTR SWELL_CB_GetItemData(HWND hwnd, int idx, int item)
2707 id cb=(id)GetDlgItem(hwnd,idx);
2709 if ([cb isKindOfClass:[NSPopUpButton class]])
2711 if (item < 0 || item >= [cb numberOfItems]) return 0;
2712 NSMenuItem *it=[(NSPopUpButton*)cb itemAtIndex:item];
2714 id p= [it representedObject];
2715 if (!p || ![p isKindOfClass:[SWELL_DataHold class]]) return 0;
2716 return (LONG_PTR) (void *)[p getValue];
2718 else if ([cb isKindOfClass:[SWELL_ComboBox class]])
2720 if (item < 0 || item >= [cb numberOfItems]) return 0;
2721 if (((SWELL_ComboBox*)cb)->m_ids) return (LONG_PTR) ((SWELL_ComboBox*)cb)->m_ids->Get(item);
2726 void SWELL_CB_Empty(HWND hwnd, int idx)
2728 id cb=(id)GetDlgItem(hwnd,idx);
2730 if ([cb isKindOfClass:[NSPopUpButton class]] ||
2731 [cb isKindOfClass:[NSComboBox class]]) [cb removeAllItems];
2733 if ([cb isKindOfClass:[SWELL_ComboBox class]])
2735 if (((SWELL_ComboBox*)cb)->m_ids) ((SWELL_ComboBox*)cb)->m_ids->Empty();
2740 BOOL SetDlgItemInt(HWND hwnd, int idx, int val, int issigned)
2743 sprintf(buf,issigned?"%d":"%u",val);
2744 return SetDlgItemText(hwnd,idx,buf);
2747 int GetDlgItemInt(HWND hwnd, int idx, BOOL *translated, int issigned)
2750 if (!GetDlgItemText(hwnd,idx,buf,sizeof(buf)))
2752 if (translated) *translated=0;
2756 while (*p == ' ' || *p == '\t') p++;
2758 if ((a<0 && !issigned) || (!a && p[0] != '0')) { if (translated) *translated=0; return 0; }
2759 if (translated) *translated=1;
2763 void SWELL_HideApp()
2769 BOOL SWELL_GetGestureInfo(LPARAM lParam, GESTUREINFO* gi)
2771 if (!lParam || !gi) return FALSE;
2772 memcpy(gi, (GESTUREINFO*)lParam, sizeof(GESTUREINFO));
2777 void ShowWindow(HWND hwnd, int cmd)
2781 if (pid && [pid isKindOfClass:[NSWindow class]])
2783 if (cmd == SW_SHOWNA && [pid isKindOfClass:[SWELL_ModelessWindow class]])
2785 if (((SWELL_ModelessWindow *)pid)->m_wantInitialKeyWindowOnShow)
2787 ((SWELL_ModelessWindow *)pid)->m_wantInitialKeyWindowOnShow=false;
2793 [pid makeKeyAndOrderFront:pid];
2795 else if (cmd==SW_SHOWNA)
2797 [pid orderFront:pid];
2799 else if (cmd==SW_HIDE)
2803 else if (cmd == SW_SHOWMINIMIZED)
2805 // this ought to work
2806 //if ([NSApp mainWindow] == pid)
2808 // [NSApp hide:pid];
2812 [pid miniaturize:pid];
2817 if (!pid || ![pid isKindOfClass:[NSView class]]) return;
2819 pid=NavigateUpScrollClipViews(pid);
2825 [((NSView *)pid) setHidden:NO];
2829 NSWindow *pw=[pid window];
2830 if (pw && [NSApp keyWindow] == pw)
2832 id foc=[pw firstResponder];
2833 if (foc && (foc == pid || IsChild((HWND)pid,(HWND)foc)))
2835 HWND h=GetParent((HWND)pid);
2839 if (![((NSView *)pid) isHidden])
2841 if ((NSView *)pid != [pw contentView])
2843 HWND par = (HWND) [(NSView *)pid superview];
2847 GetWindowRect((HWND)pid,&r);
2848 ScreenToClient(par,(LPPOINT)&r);
2849 ScreenToClient(par,((LPPOINT)&r)+1);
2850 InvalidateRect(par,&r,FALSE);
2853 [((NSView *)pid) setHidden:YES];
2860 if ((nswnd=[(NSView *)pid window]) && [nswnd contentView]==(id)pid)
2862 ShowWindow((HWND)nswnd,cmd);
2866 void *SWELL_ModalWindowStart(HWND hwnd)
2868 if (hwnd && [(id)hwnd isKindOfClass:[NSView class]]) hwnd=(HWND)[(NSView *)hwnd window];
2869 if (!hwnd) return 0;
2870 return (void *)[NSApp beginModalSessionForWindow:(NSWindow *)hwnd];
2873 bool SWELL_ModalWindowRun(void *ctx, int *ret) // returns false and puts retval in *ret when done
2875 if (!ctx) return false;
2876 NSInteger r=[NSApp runModalSession:(NSModalSession)ctx];
2877 if (r==NSRunContinuesResponse) return true;
2878 if (ret) *ret=(int)r;
2882 void SWELL_ModalWindowEnd(void *ctx)
2886 if ([NSApp runModalSession:(NSModalSession)ctx] == NSRunContinuesResponse)
2889 while ([NSApp runModalSession:(NSModalSession)ctx]==NSRunContinuesResponse) Sleep(10);
2891 [NSApp endModalSession:(NSModalSession)ctx];
2895 void SWELL_CloseWindow(HWND hwnd)
2897 if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]])
2899 [((NSWindow*)hwnd) close];
2901 else if (hwnd && [(id)hwnd isKindOfClass:[NSView class]])
2903 [[(NSView*)hwnd window] close];
2908 #include "swell-dlggen.h"
2910 static id m_make_owner;
2911 static NSRect m_transform;
2912 static float m_parent_h;
2913 static bool m_doautoright;
2914 static NSRect m_lastdoauto;
2915 static bool m_sizetofits;
2916 static int m_make_radiogroupcnt;
2918 #define ACTIONTARGET (m_make_owner)
2920 void SWELL_MakeSetCurParms(float xscale, float yscale, float xtrans, float ytrans, HWND parent, bool doauto, bool dosizetofit)
2922 m_make_radiogroupcnt=0;
2923 m_sizetofits=dosizetofit;
2924 m_lastdoauto.origin.x = 0;
2925 m_lastdoauto.origin.y = -100;
2926 m_lastdoauto.size.width = 0;
2927 m_doautoright=doauto;
2928 m_transform.origin.x=xtrans;
2929 m_transform.origin.y=ytrans;
2930 m_transform.size.width=xscale;
2931 m_transform.size.height=yscale;
2932 m_make_owner=(id)parent;
2933 if ([m_make_owner isKindOfClass:[NSWindow class]]) m_make_owner=[(NSWindow *)m_make_owner contentView];
2935 if ([(id)m_make_owner isKindOfClass:[NSView class]])
2937 m_parent_h=[(NSView *)m_make_owner bounds].size.height;
2938 if (m_transform.size.height > 0 && [(id)parent isFlipped])
2939 m_transform.size.height*=-1;
2943 static void UpdateAutoCoords(NSRect r)
2945 m_lastdoauto.size.width=r.origin.x + r.size.width - m_lastdoauto.origin.x;
2948 static NSRect MakeCoords(int x, int y, int w, int h, bool wantauto, bool ignorevscaleheight=false)
2952 return NSMakeRect(-x,-y,-w,-h);
2954 float ysc=m_transform.size.height;
2955 float ysc2 = ignorevscaleheight ? 1.0 : ysc;
2956 int newx=(int)((x+m_transform.origin.x)*m_transform.size.width + 0.5);
2957 int newy=(int)((ysc >= 0.0 ? m_parent_h - ((y+m_transform.origin.y) )*ysc + h*ysc2 :
2958 ((y+m_transform.origin.y) )*-ysc) + 0.5);
2960 NSRect ret= NSMakeRect(newx,
2962 (int) (w*m_transform.size.width+0.5),
2963 (int) (h*fabs(ysc2)+0.5));
2966 if (wantauto && m_doautoright)
2968 float dx = ret.origin.x - m_lastdoauto.origin.x;
2969 if (fabs(dx)<32 && m_lastdoauto.origin.y >= ret.origin.y && m_lastdoauto.origin.y < ret.origin.y + ret.size.height)
2971 ret.origin.x += (int) m_lastdoauto.size.width;
2974 m_lastdoauto.origin.x = oret.origin.x + oret.size.width;
2975 m_lastdoauto.origin.y = ret.origin.y + ret.size.height*0.5;
2976 m_lastdoauto.size.width=0;
2981 static const double minwidfontadjust=1.81;
2982 #define TRANSFORMFONTSIZE (m_transform.size.width<1?8:m_transform.size.width<2?10:12)
2983 /// these are for swell-dlggen.h
2984 HWND SWELL_MakeButton(int def, const char *label, int idx, int x, int y, int w, int h, int flags)
2986 UINT_PTR a=(UINT_PTR)label;
2987 if (a < 65536) label = "ICONTEMP";
2988 SWELL_Button *button=[[SWELL_Button alloc] init];
2989 if (flags & BS_BITMAP)
2991 SWELL_ImageButtonCell * cell = [[SWELL_ImageButtonCell alloc] init];
2992 [button setCell:cell];
2996 if (m_transform.size.width < minwidfontadjust)
2998 [button setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3001 [button setTag:idx];
3002 if (g_swell_want_nice_style==1)
3003 [button setBezelStyle:NSShadowlessSquareBezelStyle ];
3005 [button setBezelStyle:NSRoundedBezelStyle ];
3006 NSRect tr=MakeCoords(x,y,w,h,true);
3009 if (g_swell_want_nice_style!=1 && tr.size.height >= 18 && tr.size.height<24)
3014 [button setFrame:tr];
3015 NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(label);
3016 [button setTitle:labelstr];
3017 [button setTarget:ACTIONTARGET];
3018 [button setAction:@selector(onSwellCommand:)];
3019 if (flags&SWELL_NOT_WS_VISIBLE) [button setHidden:YES];
3020 [m_make_owner addSubview:button];
3021 if (m_doautoright) UpdateAutoCoords([button frame]);
3022 if (def) [[m_make_owner window] setDefaultButtonCell:(NSButtonCell*)button];
3025 return (HWND) button;
3029 @implementation SWELL_TextView
3031 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
3038 -(void) setTag:(NSInteger)tag
3043 -(LRESULT)onSwellMessage:(UINT)msg p1:(WPARAM)wParam p2:(LPARAM)lParam
3048 if (wParam == SB_TOP)
3050 [self scrollRangeToVisible:NSMakeRange(0, 0)];
3052 else if (wParam == SB_BOTTOM)
3054 NSUInteger len = [[self string] length];
3055 [self scrollRangeToVisible:NSMakeRange(len, 0)];
3061 NSUInteger sl = [[self string] length];
3062 if (wParam == -1) lParam = wParam = 0;
3063 else if (lParam == -1) lParam = sl;
3065 if (wParam>sl)wParam=sl;
3066 if (lParam>sl)lParam=sl;
3067 [self setSelectedRange:NSMakeRange(wParam, lParam>wParam ? lParam-wParam : 0)];
3073 NSRange r = [self selectedRange];
3074 if (wParam) *(int*)wParam = (int)r.location;
3075 if (lParam) *(int*)lParam = (int)(r.location+r.length);
3081 HGDIOBJ__* obj = (HGDIOBJ__*)wParam;
3082 if (obj && obj->type == TYPE_FONT)
3084 if (obj->ct_FontRef)
3086 [self setFont:(NSFont *)obj->ct_FontRef];
3088 #ifdef SWELL_ATSUI_TEXT_SUPPORT
3089 else if (obj->atsui_font_style)
3091 ATSUFontID fontid = kATSUInvalidFontID;
3093 Boolean isbold = NO;
3094 Boolean isital = NO;
3095 Boolean isunder = NO;
3096 if (ATSUGetAttribute(obj->atsui_font_style, kATSUFontTag, sizeof(ATSUFontID), &fontid, 0) == noErr &&
3097 ATSUGetAttribute(obj->atsui_font_style, kATSUSizeTag, sizeof(Fixed), &fsize, 0) == noErr && fsize &&
3098 ATSUGetAttribute(obj->atsui_font_style, kATSUQDBoldfaceTag, sizeof(Boolean), &isbold, 0) == noErr &&
3099 ATSUGetAttribute(obj->atsui_font_style, kATSUQDItalicTag, sizeof(Boolean), &isital, 0) == noErr &&
3100 ATSUGetAttribute(obj->atsui_font_style, kATSUQDUnderlineTag, sizeof(Boolean), &isunder, 0) == noErr)
3104 ByteCount namelen=0;
3105 if (ATSUFindFontName(fontid, kFontFullName, (FontPlatformCode)kFontNoPlatform, kFontNoScriptCode, kFontNoLanguageCode, sizeof(name), name, &namelen, 0) == noErr && name[0] && namelen)
3109 for (i = 0; i < namelen; ++i) name[i] = name[2*i];
3112 // todo bold/ital/underline
3113 NSString* str = (NSString*)SWELL_CStringToCFString(name);
3114 CGFloat sz = Fix2Long(fsize);
3115 NSFont* font = [NSFont fontWithName:str size:sz];
3119 [self setFont:font];
3132 - (BOOL)becomeFirstResponder;
3134 BOOL didBecomeFirstResponder = [super becomeFirstResponder];
3135 if (didBecomeFirstResponder) SendMessage(GetParent((HWND)self),WM_COMMAND,[self tag]|(EN_SETFOCUS<<16),(LPARAM)self);
3136 return didBecomeFirstResponder;
3141 @implementation SWELL_TextField
3142 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
3144 - (BOOL)becomeFirstResponder;
3146 BOOL didBecomeFirstResponder = [super becomeFirstResponder];
3147 if (didBecomeFirstResponder) SendMessage(GetParent((HWND)self),WM_COMMAND,[self tag]|(EN_SETFOCUS<<16),(LPARAM)self);
3148 return didBecomeFirstResponder;
3154 HWND SWELL_MakeEditField(int idx, int x, int y, int w, int h, int flags)
3156 if ((flags&WS_VSCROLL) || (flags&WS_HSCROLL)) // || (flags & ES_READONLY))
3158 SWELL_TextView *obj=[[SWELL_TextView alloc] init];
3159 [obj setEditable:(flags & ES_READONLY)?NO:YES];
3160 if (m_transform.size.width < minwidfontadjust)
3161 [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3163 [obj setDelegate:ACTIONTARGET];
3165 [obj setHorizontallyResizable:NO];
3167 if (flags & WS_VSCROLL)
3169 NSRect fr=MakeCoords(x,y,w,h,true);
3171 [obj setVerticallyResizable:YES];
3172 NSScrollView *obj2=[[NSScrollView alloc] init];
3174 if (flags&WS_VSCROLL) [obj2 setHasVerticalScroller:YES];
3175 if (flags&WS_HSCROLL) [obj2 setHasHorizontalScroller:YES];
3176 [obj2 setAutohidesScrollers:YES];
3177 [obj2 setDrawsBackground:NO];
3178 [obj2 setDocumentView:obj];
3179 [m_make_owner addSubview:obj2];
3180 if (m_doautoright) UpdateAutoCoords([obj2 frame]);
3181 if (flags&SWELL_NOT_WS_VISIBLE) [obj2 setHidden:YES];
3185 memset(&tr,0,sizeof(tr));
3186 tr.size = [obj2 contentSize];
3194 [obj setFrame:MakeCoords(x,y,w,h,true)];
3195 [obj setVerticallyResizable:NO];
3196 if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3197 [m_make_owner addSubview:obj];
3198 if (m_doautoright) UpdateAutoCoords([obj frame]);
3206 if (flags & ES_PASSWORD) obj=[[NSSecureTextField alloc] init];
3207 else obj=[[SWELL_TextField alloc] init];
3208 [obj setEditable:(flags & ES_READONLY)?NO:YES];
3209 if (flags & ES_READONLY) [obj setSelectable:YES];
3210 if (m_transform.size.width < minwidfontadjust)
3211 [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3213 NSCell* cell = [obj cell];
3214 if (flags&ES_CENTER) [cell setAlignment:NSCenterTextAlignment];
3215 else if (flags&ES_RIGHT) [cell setAlignment:NSRightTextAlignment];
3219 [cell setScrollable:YES];
3222 [obj setTarget:ACTIONTARGET];
3223 [obj setAction:@selector(onSwellCommand:)];
3224 [obj setDelegate:ACTIONTARGET];
3226 [obj setFrame:MakeCoords(x,y,w,h,true)];
3227 if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3228 [m_make_owner addSubview:obj];
3229 if (m_doautoright) UpdateAutoCoords([obj frame]);
3235 HWND SWELL_MakeLabel( int align, const char *label, int idx, int x, int y, int w, int h, int flags)
3237 NSTextField *obj=[[SWELL_TextField alloc] init];
3238 [obj setEditable:NO];
3239 [obj setSelectable:NO];
3240 [obj setBordered:NO];
3241 [obj setBezeled:NO];
3242 [obj setDrawsBackground:NO];
3243 if (m_transform.size.width < minwidfontadjust)
3244 [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3246 if (flags & SS_NOTIFY)
3248 [obj setTarget:ACTIONTARGET];
3249 [obj setAction:@selector(onSwellCommand:)];
3252 NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(label);
3253 [obj setStringValue:labelstr];
3254 [obj setAlignment:(align<0?NSLeftTextAlignment:align>0?NSRightTextAlignment:NSCenterTextAlignment)];
3256 [[obj cell] setWraps:(h>12 ? YES : NO)];
3259 [obj setFrame:MakeCoords(x,y,w,h,true)];
3260 if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3261 [m_make_owner addSubview:obj];
3262 if (m_sizetofits && strlen(label)>1)[obj sizeToFit];
3263 if (m_doautoright) UpdateAutoCoords([obj frame]);
3270 HWND SWELL_MakeCheckBox(const char *name, int idx, int x, int y, int w, int h, int flags=0)
3272 return SWELL_MakeControl(name,idx,"Button",BS_AUTOCHECKBOX|flags,x,y,w,h,0);
3275 HWND SWELL_MakeListBox(int idx, int x, int y, int w, int h, int styles)
3277 HWND hw=SWELL_MakeControl("",idx,"SysListView32_LB",styles,x,y,w,h,0);
3282 GetClientRect(hw,&r);
3283 lvc.cx=300;//yer.right-r.left;
3285 ListView_InsertColumn(hw,0,&lvc);
3292 typedef struct ccprocrec
3294 SWELL_ControlCreatorProc proc;
3296 struct ccprocrec *next;
3299 static ccprocrec *m_ccprocs;
3301 void SWELL_RegisterCustomControlCreator(SWELL_ControlCreatorProc proc)
3305 ccprocrec *p=m_ccprocs;
3306 while (p && p->next)
3308 if (p->proc == proc)
3315 ccprocrec *ent = (ccprocrec*)malloc(sizeof(ccprocrec));
3324 void SWELL_UnregisterCustomControlCreator(SWELL_ControlCreatorProc proc)
3329 ccprocrec *p=m_ccprocs;
3332 if (p->proc == proc)
3336 if (lp) lp->next=p->next;
3337 else m_ccprocs=p->next;
3348 HWND SWELL_MakeControl(const char *cname, int idx, const char *classname, int style, int x, int y, int w, int h, int exstyle)
3352 NSRect wcr=MakeCoords(x,y,w,h,false);
3353 ccprocrec *p=m_ccprocs;
3356 HWND hwnd=p->proc((HWND)m_make_owner,cname,idx,classname,style,
3357 (int)(wcr.origin.x+0.5),(int)(wcr.origin.y+0.5),(int)(wcr.size.width+0.5),(int)(wcr.size.height+0.5));
3360 if (exstyle) SetWindowLong(hwnd,GWL_EXSTYLE,exstyle);
3366 if (!stricmp(classname,"SysTabControl32"))
3368 SWELL_TabView *obj=[[SWELL_TabView alloc] init];
3369 if (1) // todo: only if on 10.4 maybe?
3375 [obj setDelegate:(id)obj];
3376 [obj setAllowsTruncatedLabels:YES];
3377 [obj setNotificationWindow:ACTIONTARGET];
3379 [obj setFrame:MakeCoords(x,y,w,h,false)];
3380 if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3381 [m_make_owner addSubview:obj];
3382 SetAllowNoMiddleManRendering((HWND)m_make_owner,FALSE);
3386 else if (!stricmp(classname, "SysListView32")||!stricmp(classname, "SysListView32_LB"))
3388 SWELL_ListView *obj = [[SWELL_ListView alloc] init];
3389 [obj setColumnAutoresizingStyle:NSTableViewNoColumnAutoresizing];
3390 [obj setFocusRingType:NSFocusRingTypeNone];
3391 [obj setDataSource:(id)obj];
3394 BOOL isLB=!stricmp(classname, "SysListView32_LB");
3395 [obj setSwellNotificationMode:isLB];
3399 [obj setHeaderView:nil];
3400 [obj setAllowsMultipleSelection:!!(style & LBS_EXTENDEDSEL)];
3404 if ((style & LVS_NOCOLUMNHEADER) || !(style & LVS_REPORT)) [obj setHeaderView:nil];
3405 [obj setAllowsMultipleSelection:!(style & LVS_SINGLESEL)];
3407 [obj setAllowsColumnReordering:NO];
3408 [obj setAllowsEmptySelection:YES];
3411 id target=ACTIONTARGET;
3412 [obj setDelegate:target];
3413 [obj setTarget:target];
3414 [obj setAction:@selector(onSwellCommand:)];
3415 if ([target respondsToSelector:@selector(swellOnControlDoubleClick:)])
3417 [obj setDoubleAction:@selector(swellOnControlDoubleClick:)];
3421 [obj setDoubleAction:@selector(onSwellCommand:)];
3423 NSScrollView *obj2=[[NSScrollView alloc] init];
3424 NSRect tr=MakeCoords(x,y,w,h,false);
3426 [obj2 setDocumentView:obj];
3427 [obj2 setHasVerticalScroller:YES];
3428 if (!isLB) [obj2 setHasHorizontalScroller:YES];
3429 [obj2 setAutohidesScrollers:YES];
3430 [obj2 setDrawsBackground:NO];
3432 if (style&SWELL_NOT_WS_VISIBLE) [obj2 setHidden:YES];
3433 [m_make_owner addSubview:obj2];
3436 if (isLB || !(style & LVS_REPORT))
3439 lvc.mask=LVCF_TEXT|LVCF_WIDTH;
3440 lvc.cx=(int)ceil(wdl_max(tr.size.width,300.0));
3441 lvc.pszText=(char*)"";
3442 ListView_InsertColumn((HWND)obj,0,&lvc);
3443 if (isLB && (style & LBS_OWNERDRAWFIXED))
3445 NSArray *ar=[obj tableColumns];
3447 if (ar && [ar count] && (c=[ar objectAtIndex:0]))
3449 SWELL_ODListViewCell *t=[[SWELL_ODListViewCell alloc] init];
3451 [t setOwnerControl:obj];
3459 else if (!stricmp(classname, "SysTreeView32"))
3461 SWELL_TreeView *obj = [[SWELL_TreeView alloc] init];
3462 [obj setFocusRingType:NSFocusRingTypeNone];
3463 [obj setDataSource:(id)obj];
3465 id target=ACTIONTARGET;
3466 [obj setHeaderView:nil];
3467 [obj setDelegate:target];
3468 [obj setAllowsColumnReordering:NO];
3469 [obj setAllowsMultipleSelection:NO];
3470 [obj setAllowsEmptySelection:YES];
3473 [obj setTarget:target];
3474 [obj setAction:@selector(onSwellCommand:)];
3475 if ([target respondsToSelector:@selector(swellOnControlDoubleClick:)])
3476 [obj setDoubleAction:@selector(swellOnControlDoubleClick:)];
3478 [obj setDoubleAction:@selector(onSwellCommand:)];
3479 NSScrollView *obj2=[[NSScrollView alloc] init];
3480 NSRect tr=MakeCoords(x,y,w,h,false);
3482 [obj2 setDocumentView:obj];
3483 [obj2 setHasVerticalScroller:YES];
3484 [obj2 setAutohidesScrollers:YES];
3485 [obj2 setDrawsBackground:NO];
3487 if (style&SWELL_NOT_WS_VISIBLE) [obj2 setHidden:YES];
3488 [m_make_owner addSubview:obj2];
3492 NSTableColumn *col=[[NSTableColumn alloc] init];
3493 SWELL_ListViewCell *cell = [[SWELL_ListViewCell alloc] initTextCell:@""];
3494 [col setDataCell:cell];
3497 [col setWidth:(int)ceil(wdl_max(tr.size.width,300.0))];
3498 [col setEditable:NO];
3499 [[col dataCell] setWraps:NO];
3500 [obj addTableColumn:col];
3501 [obj setOutlineTableColumn:col];
3505 /// [obj setIndentationPerLevel:10.0];
3509 else if (!stricmp(classname, "msctls_progress32"))
3511 SWELL_ProgressView *obj=[[SWELL_ProgressView alloc] init];
3512 [obj setStyle:NSProgressIndicatorBarStyle];
3513 [obj setIndeterminate:NO];
3515 [obj setFrame:MakeCoords(x,y,w,h,false)];
3516 if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3517 [m_make_owner addSubview:obj];
3521 else if (!stricmp(classname,"Edit"))
3523 return SWELL_MakeEditField(idx,x,y,w,h,style);
3525 else if (!stricmp(classname, "static"))
3527 NSTextField *obj=[[SWELL_TextField alloc] init];
3528 [obj setEditable:NO];
3529 [obj setSelectable:NO];
3530 [obj setBordered:NO];
3531 [obj setBezeled:NO];
3532 [obj setDrawsBackground:NO];
3533 if (m_transform.size.width < minwidfontadjust)
3534 [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3536 if (cname && *cname)
3538 NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(cname);
3539 [obj setStringValue:labelstr];
3543 if ((style&SS_TYPEMASK) == SS_LEFTNOWORDWRAP) [[obj cell] setWraps:NO];
3544 else if ((style&SS_TYPEMASK) == SS_CENTER) [[obj cell] setAlignment:NSCenterTextAlignment];
3545 else if ((style&SS_TYPEMASK) == SS_RIGHT) [[obj cell] setAlignment:NSRightTextAlignment];
3548 [obj setFrame:MakeCoords(x,y,w,h,true)];
3549 if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3550 [m_make_owner addSubview:obj];
3551 if ((style & SS_TYPEMASK) == SS_BLACKRECT)
3553 [obj setHidden:YES];
3558 else if (!stricmp(classname,"Button"))
3560 if (style & BS_GROUPBOX)
3562 return SWELL_MakeGroupBox(cname, idx, x, y, w, h, style &~BS_GROUPBOX);
3564 if (style & BS_DEFPUSHBUTTON)
3566 return SWELL_MakeButton(1, cname, idx, x,y,w,h,style &~BS_DEFPUSHBUTTON);
3568 if (style & BS_PUSHBUTTON)
3570 return SWELL_MakeButton(0, cname, idx, x,y,w,h,style &~BS_PUSHBUTTON);
3572 SWELL_Button *button=[[SWELL_Button alloc] init];
3573 [button setTag:idx];
3574 NSRect fr=MakeCoords(x,y,w,h,true);
3575 SEL actionSel = @selector(onSwellCommand:);
3576 if ((style & 0xf) == BS_AUTO3STATE)
3578 [button setButtonType:NSSwitchButton];
3579 [button setAllowsMixedState:YES];
3581 else if ((style & 0xf) == BS_AUTOCHECKBOX)
3583 [button setButtonType:NSSwitchButton];
3584 [button setAllowsMixedState:NO];
3586 else if ((style & 0xf) == BS_AUTORADIOBUTTON)
3588 #ifdef MAC_OS_X_VERSION_10_8
3589 // Compiling with the OSX 10.8+ SDK and running on 10.8+ causes radio buttons with a common action selector to
3590 // be treated as a group. This works around that. if you need more than 8 groups (seriously?!), add the extra
3591 // functions in swell-dlg.mm and in the switch below
3595 if ((style & WS_GROUP) ||
3596 !(sv = [m_make_owner subviews]) ||
3598 !(v = [sv lastObject]) ||
3599 ![v isKindOfClass:[SWELL_Button class]] ||
3600 ([(SWELL_Button *)v swellGetRadioFlags]&2)) m_make_radiogroupcnt++;
3602 switch (m_make_radiogroupcnt & 7)
3604 case 0: actionSel = @selector(onSwellCommand0:); break;
3605 case 1: break; // default
3606 case 2: actionSel = @selector(onSwellCommand2:); break;
3607 case 3: actionSel = @selector(onSwellCommand3:); break;
3608 case 4: actionSel = @selector(onSwellCommand4:); break;
3609 case 5: actionSel = @selector(onSwellCommand5:); break;
3610 case 6: actionSel = @selector(onSwellCommand6:); break;
3611 case 7: actionSel = @selector(onSwellCommand7:); break;
3615 [button setButtonType:NSRadioButton];
3616 [button swellSetRadioFlags:(style & WS_GROUP)?3:1];
3618 else if ((style & 0xf) == BS_OWNERDRAW)
3620 SWELL_ODButtonCell *cell = [[SWELL_ODButtonCell alloc] init];
3621 [button setCell:cell];
3625 else // normal button
3627 if (style & BS_BITMAP)
3629 SWELL_ImageButtonCell * cell = [[SWELL_ImageButtonCell alloc] init];
3630 [button setCell:cell];
3633 // fr.size.width+=8;
3636 if (m_transform.size.width < minwidfontadjust)
3637 [button setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3638 [button setFrame:fr];
3639 NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(cname);
3640 [button setTitle:labelstr];
3641 [button setTarget:ACTIONTARGET];
3642 [button setAction:actionSel];
3643 if (style&BS_LEFTTEXT) [button setImagePosition:NSImageRight];
3644 if (style&SWELL_NOT_WS_VISIBLE) [button setHidden:YES];
3645 [m_make_owner addSubview:button];
3646 if (m_sizetofits && (style & 0xf) != BS_OWNERDRAW) [button sizeToFit];
3647 if (m_doautoright) UpdateAutoCoords([button frame]);
3650 return (HWND)button;
3652 else if (!stricmp(classname,"REAPERhfader")||!stricmp(classname,"msctls_trackbar32"))
3654 NSSlider *obj=[[NSSlider alloc] init];
3656 [obj setMinValue:0.0];
3657 [obj setMaxValue:1000.0];
3658 [obj setFrame:MakeCoords(x,y,w,h,false)];
3659 if (!stricmp(classname, "msctls_trackbar32"))
3661 [[obj cell] setControlSize:NSMiniControlSize];
3663 [obj setTarget:ACTIONTARGET];
3664 [obj setAction:@selector(onSwellCommand:)];
3665 if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3666 [m_make_owner addSubview:obj];
3673 HWND SWELL_MakeCombo(int idx, int x, int y, int w, int h, int flags)
3675 if ((flags & 0x3) == CBS_DROPDOWNLIST)
3677 SWELL_PopUpButton *obj=[[SWELL_PopUpButton alloc] init];
3679 [obj setFont:[NSFont systemFontOfSize:10.0f]];
3680 NSRect rc=MakeCoords(x,y,w,18,true,true);
3682 [obj setSwellStyle:flags];
3684 [obj setAutoenablesItems:NO];
3685 [obj setTarget:ACTIONTARGET];
3686 [obj setAction:@selector(onSwellCommand:)];
3688 if (g_swell_want_nice_style==1)
3690 [obj setBezelStyle:NSShadowlessSquareBezelStyle ];
3691 [[obj cell] setArrowPosition:NSPopUpArrowAtBottom];
3693 if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3694 [m_make_owner addSubview:obj];
3695 if (m_doautoright) UpdateAutoCoords([obj frame]);
3701 SWELL_ComboBox *obj=[[SWELL_ComboBox alloc] init];
3702 [obj setFocusRingType:NSFocusRingTypeNone];
3703 [obj setFont:[NSFont systemFontOfSize:10.0f]];
3704 [obj setEditable:(flags & 0x3) == CBS_DROPDOWNLIST?NO:YES];
3705 [obj setSwellStyle:flags];
3707 [obj setFrame:MakeCoords(x,y-1,w,22,true,true)];
3708 [obj setTarget:ACTIONTARGET];
3709 [obj setAction:@selector(onSwellCommand:)];
3710 [obj setDelegate:ACTIONTARGET];
3711 if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3712 [m_make_owner addSubview:obj];
3713 if (m_doautoright) UpdateAutoCoords([obj frame]);
3719 @implementation SWELL_BoxView
3721 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
3727 -(void) setTag:(NSInteger)tag
3733 HWND SWELL_MakeGroupBox(const char *name, int idx, int x, int y, int w, int h, int style)
3735 SWELL_BoxView *obj=[[SWELL_BoxView alloc] init];
3737 // this just doesn't work, you can't color the border unless it's NSBoxCustom,
3738 // and I can't get it to show the title text if it's NSBoxCustom
3739 //[obj setBoxType:(NSBoxType)4]; // NSBoxCustom, so we can color the border
3740 //[obj setTitlePosition:(NSTitlePosition)2]; // NSAtTop, default but NSBoxCustom unsets it
3742 // [obj setTag:idx];
3743 if (1) // todo: only if on 10.4 maybe?
3748 NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(name);
3749 [obj setTitle:labelstr];
3752 if (style & BS_CENTER)
3754 [[obj titleCell] setAlignment:NSCenterTextAlignment];
3756 [obj setFrame:MakeCoords(x,y,w,h,false)];
3757 [m_make_owner addSubview:obj positioned:NSWindowBelow relativeTo:nil];
3763 int TabCtrl_GetItemCount(HWND hwnd)
3765 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return 0;
3766 SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3767 return (int)[tv numberOfTabViewItems];
3770 BOOL TabCtrl_AdjustRect(HWND hwnd, BOOL fLarger, RECT *r)
3772 if (!r || !hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return FALSE;
3774 int sign=fLarger?-1:1;
3775 r->left+=sign*7; // todo: correct this?
3783 BOOL TabCtrl_DeleteItem(HWND hwnd, int idx)
3785 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return 0;
3786 SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3787 if (idx<0 || idx>= [tv numberOfTabViewItems]) return 0;
3788 [tv removeTabViewItem:[tv tabViewItemAtIndex:idx]];
3792 int TabCtrl_InsertItem(HWND hwnd, int idx, TCITEM *item)
3794 if (!item || !hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return -1;
3795 if (!(item->mask & TCIF_TEXT) || !item->pszText) return -1;
3796 SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3798 const int ni = (int)[tv numberOfTabViewItems];
3800 else if (idx>ni) idx=ni;
3802 NSTabViewItem *tabitem=[[NSTabViewItem alloc] init];
3803 NSString *str=(NSString *)SWELL_CStringToCFString(item->pszText);
3804 [tabitem setLabel:str];
3806 id turd=[tv getNotificationWindow];
3807 [tv setNotificationWindow:nil];
3808 [tv insertTabViewItem:tabitem atIndex:idx];
3809 [tv setNotificationWindow:turd];
3814 int TabCtrl_SetCurSel(HWND hwnd, int idx)
3816 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return -1;
3817 SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3818 int ret=TabCtrl_GetCurSel(hwnd);
3819 if (idx>=0 && idx < [tv numberOfTabViewItems])
3821 [tv selectTabViewItemAtIndex:idx];
3826 int TabCtrl_GetCurSel(HWND hwnd)
3828 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]]) return 0;
3829 SWELL_TabView *tv=(SWELL_TabView*)hwnd;
3830 NSTabViewItem *item=[tv selectedTabViewItem];
3831 if (!item) return 0;
3832 return (int)[tv indexOfTabViewItem:item];
3835 void ListView_SetExtendedListViewStyleEx(HWND h, int mask, int style)
3838 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
3839 SWELL_ListView *tv=(SWELL_ListView*)h;
3841 if (mask&LVS_EX_GRIDLINES)
3844 if (style&LVS_EX_GRIDLINES)
3846 s=NSTableViewSolidVerticalGridLineMask|NSTableViewSolidHorizontalGridLineMask;
3848 [tv setGridStyleMask:s];
3851 if (mask&LVS_EX_HEADERDRAGDROP)
3853 [tv setAllowsColumnReordering:!!(style&LVS_EX_HEADERDRAGDROP)];
3857 // todo LVS_EX_FULLROWSELECT (enabled by default on OSX)
3860 void SWELL_SetListViewFastClickMask(HWND hList, int mask)
3862 if (!hList || ![(id)hList isKindOfClass:[SWELL_ListView class]]) return;
3863 SWELL_ListView *lv = (SWELL_ListView *)hList;
3864 lv->m_fastClickMask=mask;
3869 void ListView_SetImageList(HWND h, HIMAGELIST imagelist, int which)
3873 SWELL_ListView *v=(SWELL_ListView *)h;
3875 v->m_status_imagelist_type=which;
3876 v->m_status_imagelist=(WDL_PtrList<HGDIOBJ__> *)imagelist;
3877 if (v->m_cols && v->m_cols->GetSize()>0)
3879 NSTableColumn *col=(NSTableColumn*)v->m_cols->Get(0);
3880 if (![col isKindOfClass:[SWELL_StatusCell class]])
3882 SWELL_StatusCell *cell=[[SWELL_StatusCell alloc] initNewCell];
3884 [col setDataCell:cell];
3890 int ListView_GetColumnWidth(HWND h, int pos)
3892 if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
3893 SWELL_ListView *v=(SWELL_ListView *)h;
3894 if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return 0;
3896 NSTableColumn *col=v->m_cols->Get(pos);
3899 if ([col respondsToSelector:@selector(isHidden)] && [(SWELL_TableColumnExtensions*)col isHidden]) return 0;
3900 return (int) floor(0.5+[col width]);
3903 void ListView_InsertColumn(HWND h, int pos, const LVCOLUMN *lvc)
3905 if (!h || !lvc) return;
3906 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
3910 SWELL_ListView *v=(SWELL_ListView *)h;
3911 NSTableColumn *col=[[NSTableColumn alloc] init];
3912 // note, not looking at lvc->mask at all
3914 [col setEditable:NO];
3915 // [col setResizingMask:2]; // user resizable, this seems to be the default
3917 if (lvc->fmt == LVCFMT_CENTER) [[col headerCell] setAlignment:NSCenterTextAlignment];
3918 else if (lvc->fmt == LVCFMT_RIGHT) [[col headerCell] setAlignment:NSRightTextAlignment];
3920 if (!v->m_lbMode && !(v->style & LVS_NOCOLUMNHEADER))
3922 NSString *lbl=(NSString *)SWELL_CStringToCFString(lvc->pszText);
3923 [[col headerCell] setStringValue:lbl];
3927 if (!pos && v->m_status_imagelist)
3929 SWELL_StatusCell *cell=[[SWELL_StatusCell alloc] initNewCell];
3931 [col setDataCell:cell];
3936 SWELL_ListViewCell *cell = [[SWELL_ListViewCell alloc] initTextCell:@""];
3937 [col setDataCell:cell];
3940 if (lvc->fmt == LVCFMT_CENTER) [cell setAlignment:NSCenterTextAlignment];
3941 else if (lvc->fmt == LVCFMT_RIGHT) [cell setAlignment:NSRightTextAlignment];
3945 [v addTableColumn:col];
3946 v->m_cols->Add(col);
3949 if (lvc->mask&LVCF_WIDTH)
3951 ListView_SetColumnWidth(h,pos,lvc->cx);
3956 void ListView_SetColumn(HWND h, int pos, const LVCOLUMN *lvc)
3958 if (!h || !lvc || ![(id)h isKindOfClass:[SWELL_ListView class]]) return;
3959 SWELL_ListView *v=(SWELL_ListView *)h;
3960 if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return;
3962 NSTableColumn *col=v->m_cols->Get(pos);
3965 if (lvc->mask&LVCF_FMT)
3967 if (lvc->fmt == LVCFMT_LEFT) [[col headerCell] setAlignment:NSLeftTextAlignment];
3968 else if (lvc->fmt == LVCFMT_CENTER) [[col headerCell] setAlignment:NSCenterTextAlignment];
3969 else if (lvc->fmt == LVCFMT_RIGHT) [[col headerCell] setAlignment:NSRightTextAlignment];
3971 if (lvc->mask&LVCF_WIDTH)
3975 if ([col respondsToSelector:@selector(setHidden:)]) [(SWELL_TableColumnExtensions*)col setHidden:YES];
3979 if ([col respondsToSelector:@selector(setHidden:)]) [(SWELL_TableColumnExtensions*)col setHidden:NO];
3980 [col setWidth:lvc->cx];
3983 if (lvc->mask&LVCF_TEXT)
3985 if (!v->m_lbMode && !(v->style&LVS_NOCOLUMNHEADER))
3987 NSString *lbl=(NSString *)SWELL_CStringToCFString(lvc->pszText);
3988 [[col headerCell] setStringValue:lbl];
3994 bool ListView_DeleteColumn(HWND h, int pos)
3996 if (!h) return false;
3997 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
3998 SWELL_ListView *v=(SWELL_ListView *)h;
3999 if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return false;
4000 [v removeTableColumn:v->m_cols->Get(pos)];
4001 v->m_cols->Delete(pos);
4005 void ListView_GetItemText(HWND hwnd, int item, int subitem, char *text, int textmax)
4007 LVITEM it={LVIF_TEXT,item,subitem,0,0,text,textmax,};
4008 ListView_GetItem(hwnd,&it);
4011 int ListView_InsertItem(HWND h, const LVITEM *item)
4013 if (!h || !item || item->iSubItem) return 0;
4014 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4016 SWELL_ListView *tv=(SWELL_ListView*)h;
4017 if (!tv->m_lbMode && (tv->style & LVS_OWNERDATA)) return -1;
4018 if (!tv->m_items) return -1;
4022 else if (a > tv->m_items->GetSize()) a=tv->m_items->GetSize();
4024 if (!tv->m_lbMode && (item->mask & LVIF_TEXT))
4026 if (tv->style & LVS_SORTASCENDING)
4028 a=ptrlist_bsearch_mod((char *)item->pszText,tv->m_items,_listviewrowSearchFunc,NULL);
4030 else if (tv->style & LVS_SORTDESCENDING)
4032 a=ptrlist_bsearch_mod((char *)item->pszText,tv->m_items,_listviewrowSearchFunc2,NULL);
4036 SWELL_ListView_Row *nr=new SWELL_ListView_Row;
4037 nr->m_vals.Add(strdup((item->mask & LVIF_TEXT) ? item->pszText : ""));
4038 if (item->mask & LVIF_PARAM) nr->m_param = item->lParam;
4039 tv->m_items->Insert(a,nr);
4043 if ((item->mask&LVIF_STATE) && (item->stateMask & (0xff<<16)))
4045 nr->m_imageidx=(item->state>>16)&0xff;
4050 if (a < tv->m_items->GetSize()-1)
4052 NSIndexSet *sel=[tv selectedRowIndexes];
4053 if (sel && [sel count])
4055 NSMutableIndexSet *ms = [[NSMutableIndexSet alloc] initWithIndexSet:sel];
4056 [ms shiftIndexesStartingAtIndex:a by:1];
4057 [tv selectRowIndexes:ms byExtendingSelection:NO];
4062 if (item->mask & LVIF_STATE)
4064 if (item->stateMask & LVIS_SELECTED)
4066 if (item->state&LVIS_SELECTED)
4068 bool isSingle = tv->m_lbMode ? !(tv->style & LBS_EXTENDEDSEL) : !!(tv->style&LVS_SINGLESEL);
4069 [tv selectRowIndexes:[NSIndexSet indexSetWithIndex:a] byExtendingSelection:isSingle?NO:YES];
4077 void ListView_SetItemText(HWND h, int ipos, int cpos, const char *txt)
4079 if (!h || cpos < 0 || cpos >= 32) return;
4080 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4082 SWELL_ListView *tv=(SWELL_ListView*)h;
4083 if (!tv->m_lbMode && (tv->style & LVS_OWNERDATA)) return;
4084 if (!tv->m_items) return;
4086 SWELL_ListView_Row *p=tv->m_items->Get(ipos);
4089 for (x = p->m_vals.GetSize(); x < cpos; x ++)
4091 p->m_vals.Add(strdup(""));
4093 if (cpos < p->m_vals.GetSize())
4095 free(p->m_vals.Get(cpos));
4096 p->m_vals.Set(cpos,strdup(txt));
4098 else p->m_vals.Add(strdup(txt));
4103 int ListView_GetNextItem(HWND h, int istart, int flags)
4105 if (flags==LVNI_FOCUSED||flags==LVNI_SELECTED)
4108 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return -1;
4110 SWELL_ListView *tv=(SWELL_ListView*)h;
4112 if (flags==LVNI_SELECTED)
4114 //int orig_start=istart;
4115 if (istart++<0)istart=0;
4116 const int n = (int)[tv numberOfRows];
4119 if ([tv isRowSelected:istart]) return istart;
4125 return (int)[tv selectedRow];
4130 bool ListView_SetItem(HWND h, LVITEM *item)
4132 if (!item) return false;
4133 if (!h) return false;
4134 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
4136 SWELL_ListView *tv=(SWELL_ListView*)h;
4137 if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4139 if (!tv->m_items) return false;
4140 SWELL_ListView_Row *row=tv->m_items->Get(item->iItem);
4141 if (!row) return false;
4143 if (item->mask & LVIF_PARAM)
4145 row->m_param=item->lParam;
4147 if ((item->mask & LVIF_TEXT) && item->pszText)
4149 ListView_SetItemText(h,item->iItem,item->iSubItem,item->pszText);
4151 if ((item->mask&LVIF_IMAGE) && item->iImage >= 0)
4153 row->m_imageidx=item->iImage+1;
4154 ListView_RedrawItems(h, item->iItem, item->iItem);
4157 if ((item->mask & LVIF_STATE) && item->stateMask)
4159 ListView_SetItemState(h,item->iItem,item->state,item->stateMask);
4165 bool ListView_GetItem(HWND h, LVITEM *item)
4167 if (!item) return false;
4168 if ((item->mask&LVIF_TEXT)&&item->pszText && item->cchTextMax > 0) item->pszText[0]=0;
4170 if (!h) return false;
4171 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
4174 SWELL_ListView *tv=(SWELL_ListView*)h;
4175 if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4177 if (!tv->m_items) return false;
4179 SWELL_ListView_Row *row=tv->m_items->Get(item->iItem);
4180 if (!row) return false;
4182 if (item->mask & LVIF_PARAM) item->lParam=row->m_param;
4183 if (item->mask & LVIF_TEXT) if (item->pszText && item->cchTextMax>0)
4185 char *p=row->m_vals.Get(item->iSubItem);
4186 lstrcpyn_safe(item->pszText,p?p:"",item->cchTextMax);
4188 if (item->mask & LVIF_STATE)
4190 if (item->stateMask & (0xff<<16))
4192 item->state|=row->m_imageidx<<16;
4198 if (item->iItem <0 || item->iItem >= tv->ownermode_cnt) return false;
4200 if (item->mask & LVIF_STATE)
4202 if ((item->stateMask&LVIS_SELECTED) && [tv isRowSelected:item->iItem]) item->state|=LVIS_SELECTED;
4203 if ((item->stateMask&LVIS_FOCUSED) && [tv selectedRow] == item->iItem) item->state|=LVIS_FOCUSED;
4208 int ListView_GetItemState(HWND h, int ipos, UINT mask)
4210 if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4211 SWELL_ListView *tv=(SWELL_ListView*)h;
4213 if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4215 if (!tv->m_items) return 0;
4216 SWELL_ListView_Row *row=tv->m_items->Get(ipos);
4218 if (mask & (0xff<<16))
4220 flag|=row->m_imageidx<<16;
4225 if (ipos<0 || ipos >= tv->ownermode_cnt) return 0;
4228 if ((mask&LVIS_SELECTED) && [tv isRowSelected:ipos]) flag|=LVIS_SELECTED;
4229 if ((mask&LVIS_FOCUSED) && [tv selectedRow]==ipos) flag|=LVIS_FOCUSED;
4233 bool ListView_SetItemState(HWND h, int ipos, UINT state, UINT statemask)
4236 if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
4237 SWELL_ListView *tv=(SWELL_ListView*)h;
4238 static int _is_doing_all;
4243 int n=ListView_GetItemCount(h);
4245 for (x = 0; x < n; x ++)
4246 ListView_SetItemState(h,x,state,statemask);
4248 ListView_RedrawItems(h,0,n-1);
4252 if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4254 if (!tv->m_items) return false;
4255 SWELL_ListView_Row *row=tv->m_items->Get(ipos);
4256 if (!row) return false;
4257 if (statemask & (0xff<<16))
4259 if (row->m_imageidx!=((state>>16)&0xff))
4261 row->m_imageidx=(state>>16)&0xff;
4268 if (ipos<0 || ipos >= tv->ownermode_cnt) return 0;
4271 if (statemask & LVIS_SELECTED)
4273 if (state & LVIS_SELECTED)
4275 bool isSingle = tv->m_lbMode ? !(tv->style & LBS_EXTENDEDSEL) : !!(tv->style&LVS_SINGLESEL);
4276 if (![tv isRowSelected:ipos]) { didsel=true; [tv selectRowIndexes:[NSIndexSet indexSetWithIndex:ipos] byExtendingSelection:isSingle?NO:YES]; }
4280 if ([tv isRowSelected:ipos]) { didsel=true; [tv deselectRow:ipos]; }
4283 if (statemask & LVIS_FOCUSED)
4285 if (state&LVIS_FOCUSED)
4302 NMLISTVIEW nm={{(HWND)h,(UINT_PTR)[tv tag],LVN_ITEMCHANGED},ipos,0,state,};
4303 SendMessage(GetParent(h),WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
4308 ListView_RedrawItems(h,ipos,ipos);
4313 void ListView_RedrawItems(HWND h, int startitem, int enditem)
4315 if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4316 SWELL_ListView *tv=(SWELL_ListView*)h;
4317 if (!tv->m_items) return;
4321 void ListView_DeleteItem(HWND h, int ipos)
4324 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4326 SWELL_ListView *tv=(SWELL_ListView*)h;
4327 if (!tv->m_items) return;
4329 if (ipos >=0 && ipos < tv->m_items->GetSize())
4331 if (ipos != tv->m_items->GetSize()-1)
4333 NSIndexSet *sel=[tv selectedRowIndexes];
4334 if (sel && [sel count])
4336 NSMutableIndexSet *ms = [[NSMutableIndexSet alloc] initWithIndexSet:sel];
4337 [ms shiftIndexesStartingAtIndex:ipos+1 by:-1];
4338 [tv selectRowIndexes:ms byExtendingSelection:NO];
4342 tv->m_items->Delete(ipos,true);
4349 void ListView_DeleteAllItems(HWND h)
4352 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4354 SWELL_ListView *tv=(SWELL_ListView*)h;
4355 tv->ownermode_cnt=0;
4356 if (tv->m_items) tv->m_items->Empty(true);
4361 int ListView_GetSelectedCount(HWND h)
4364 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4366 SWELL_ListView *tv=(SWELL_ListView*)h;
4367 return (int)[tv numberOfSelectedRows];
4370 int ListView_GetItemCount(HWND h)
4373 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4375 SWELL_ListView *tv=(SWELL_ListView*)h;
4376 if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4378 if (!tv->m_items) return 0;
4380 return tv->m_items->GetSize();
4382 return tv->ownermode_cnt;
4385 int ListView_GetSelectionMark(HWND h)
4388 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4390 SWELL_ListView *tv=(SWELL_ListView*)h;
4391 return (int)[tv selectedRow];
4394 int SWELL_GetListViewHeaderHeight(HWND h)
4397 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4399 SWELL_ListView* tv=(SWELL_ListView*)h;
4400 NSTableHeaderView* hv=[tv headerView];
4401 NSRect r=[hv bounds];
4402 return (int)(r.size.height+0.5);
4405 void ListView_SetColumnWidth(HWND h, int pos, int wid)
4407 if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4408 SWELL_ListView *v=(SWELL_ListView *)h;
4409 if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return;
4411 NSTableColumn *col=v->m_cols->Get(pos);
4416 if ([col respondsToSelector:@selector(setHidden:)]) [(SWELL_TableColumnExtensions*)col setHidden:YES];
4420 if ([col respondsToSelector:@selector(setHidden:)]) [(SWELL_TableColumnExtensions*)col setHidden:NO];
4425 BOOL ListView_GetColumnOrderArray(HWND h, int cnt, int* arr)
4427 if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return FALSE;
4428 SWELL_ListView* lv=(SWELL_ListView*)h;
4429 if (!lv->m_cols || lv->m_cols->GetSize() != cnt) return FALSE;
4432 for (i=0; i < cnt; ++i)
4434 arr[i]=[lv getColumnPos:i];
4440 BOOL ListView_SetColumnOrderArray(HWND h, int cnt, int* arr)
4442 if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return FALSE;
4443 SWELL_ListView* lv=(SWELL_ListView*)h;
4444 if (!lv->m_cols || lv->m_cols->GetSize() != cnt) return FALSE;
4447 for (i=0; i < cnt; ++i)
4449 int pos=[lv getColumnPos:i];
4451 if (dest>=0 && dest<cnt) [lv moveColumn:pos toColumn:dest];
4457 HWND ListView_GetHeader(HWND h)
4459 if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4463 int Header_GetItemCount(HWND h)
4465 if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4466 SWELL_ListView* lv=(SWELL_ListView*)h;
4467 if (lv->m_cols) return lv->m_cols->GetSize();
4471 BOOL Header_GetItem(HWND h, int col, HDITEM* hi)
4473 if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]] || !hi) return FALSE;
4474 SWELL_ListView* lv=(SWELL_ListView*)h;
4475 if (!lv->m_cols || col < 0 || col >= lv->m_cols->GetSize()) return FALSE;
4476 NSTableColumn* hcol=lv->m_cols->Get(col);
4477 if (!hcol) return FALSE;
4479 if (hi->mask&HDI_FORMAT)
4482 NSImage* img=[lv indicatorImageInTableColumn:hcol];
4485 NSString* imgname=[img name];
4488 if ([imgname isEqualToString:@"NSAscendingSortIndicator"]) hi->fmt |= HDF_SORTUP;
4489 else if ([imgname isEqualToString:@"NSDescendingSortIndicator"]) hi->fmt |= HDF_SORTDOWN;
4498 BOOL Header_SetItem(HWND h, int col, HDITEM* hi)
4500 if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]] || !hi) return FALSE;
4501 SWELL_ListView* lv=(SWELL_ListView*)h;
4502 if (!lv->m_cols || col < 0 || col >= lv->m_cols->GetSize()) return FALSE;
4503 NSTableColumn* hcol=lv->m_cols->Get(col);
4504 if (!hcol) return FALSE;
4506 if (hi->mask&HDI_FORMAT)
4509 if (hi->fmt&HDF_SORTUP) img=[NSImage imageNamed:@"NSAscendingSortIndicator"];
4510 else if (hi->fmt&HDF_SORTDOWN) img=[NSImage imageNamed:@"NSDescendingSortIndicator"];
4511 [lv setIndicatorImage:img inTableColumn:hcol];
4518 int ListView_HitTest(HWND h, LVHITTESTINFO *pinf)
4520 if (!h || !pinf) return -1;
4521 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return -1;
4523 SWELL_ListView *tv=(SWELL_ListView*)h;
4528 // rowAtPoint will return a row even if it is scrolled out of the clip view
4529 NSScrollView* sv=(NSScrollView *)NavigateUpScrollClipViews(tv);
4530 if (![sv isKindOfClass:[NSScrollView class]] && ![sv isKindOfClass:[NSClipView class]]) sv=NULL;
4532 NSRect r=[sv documentVisibleRect];
4533 int x=pinf->pt.x-r.origin.x;
4534 int y=pinf->pt.y-r.origin.y;
4536 if (x < 0) pinf->flags |= LVHT_TOLEFT;
4537 if (x >= r.size.width) pinf->flags |= LVHT_TORIGHT;
4538 if (y < 0) pinf->flags |= LVHT_ABOVE;
4539 if (y >= r.size.height) pinf->flags |= LVHT_BELOW;
4543 NSPoint pt = NSMakePoint( pinf->pt.x, pinf->pt.y );
4544 pinf->iItem=(int)[(NSTableView *)h rowAtPoint:pt];
4545 if (pinf->iItem >= 0)
4547 if (tv->m_status_imagelist && pt.x <= [tv rowHeight])
4549 pinf->flags=LVHT_ONITEMSTATEICON;
4553 pinf->flags=LVHT_ONITEMLABEL;
4558 pinf->flags=LVHT_NOWHERE;
4565 int ListView_SubItemHitTest(HWND h, LVHITTESTINFO *pinf)
4567 int row = ListView_HitTest(h, pinf);
4569 NSPoint pt=NSMakePoint(pinf->pt.x,pinf->pt.y);
4570 if (row < 0 && pt.y < 0)
4571 { // Fake the point in the client area of the listview to get the column # (like win32)
4574 pinf->iSubItem=(int)[(NSTableView *)h columnAtPoint:pt];
4578 void ListView_SetItemCount(HWND h, int cnt)
4581 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4583 SWELL_ListView *tv=(SWELL_ListView*)h;
4584 if (!tv->m_lbMode && (tv->style & LVS_OWNERDATA))
4586 tv->ownermode_cnt=cnt;
4590 void ListView_EnsureVisible(HWND h, int i, BOOL pok)
4593 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return;
4595 SWELL_ListView *tv=(SWELL_ListView*)h;
4598 if (!tv->m_lbMode && (tv->style & LVS_OWNERDATA))
4600 if (i >=tv->ownermode_cnt-1) i=tv->ownermode_cnt-1;
4604 if (tv->m_items && i >= tv->m_items->GetSize()) i=tv->m_items->GetSize()-1;
4608 [tv scrollRowToVisible:i];
4612 static bool ListViewGetRectImpl(HWND h, int item, int subitem, RECT* r) // subitem<0 for full item rect
4614 if (!h) return false;
4615 if (![(id)h isKindOfClass:[SWELL_ListView class]]) return false;
4616 if (item < 0 || item > ListView_GetItemCount(h)) return false;
4617 SWELL_ListView *tv=(SWELL_ListView*)h;
4619 if (subitem >= 0 && (!tv->m_cols || subitem >= tv->m_cols->GetSize())) return false;
4620 subitem=[tv getColumnPos:subitem];
4623 if (subitem < 0) ar = [tv rectOfRow:item];
4624 else ar=[tv frameOfCellAtColumn:subitem row:item];
4625 NSSize sp=[tv intercellSpacing];
4627 r->left=(int)ar.origin.x;
4628 r->top=(int)ar.origin.y;
4629 r->right=(int)(ar.origin.x+ar.size.width+sp.width);
4630 r->bottom=(int)(ar.origin.y+ar.size.height+sp.height);
4635 bool ListView_GetSubItemRect(HWND h, int item, int subitem, int code, RECT *r)
4637 return ListViewGetRectImpl(h, item, subitem, r);
4640 bool ListView_GetItemRect(HWND h, int item, RECT *r, int code)
4642 return ListViewGetRectImpl(h, item, -1, r);
4645 int ListView_GetTopIndex(HWND h)
4647 NSTableView* tv = (NSTableView*)h;
4649 NSScrollView* sv = [tv enclosingScrollView];
4652 NSPoint pt = { 0, 0 };
4653 NSView *hdr = [tv headerView];
4654 if (hdr && ![hdr isHidden])
4656 NSRect fr=[hdr frame];
4657 if (fr.size.height > 0.0) pt.y = fr.origin.y + fr.size.height;
4659 pt.y += [sv documentVisibleRect].origin.y;
4660 return (int)[tv rowAtPoint:pt];
4663 int ListView_GetCountPerPage(HWND h)
4665 NSTableView* tv = (NSTableView*)h;
4667 NSScrollView* sv = [tv enclosingScrollView];
4670 NSRect tvr = [sv documentVisibleRect];
4671 int rowh = [tv rowHeight];
4672 return tvr.size.height/rowh;
4675 bool ListView_Scroll(HWND h, int xscroll, int yscroll)
4677 NSTableView* tv = (NSTableView*)h;
4678 NSScrollView* sv = [tv enclosingScrollView];
4679 if (!sv) return false;
4681 NSRect tvr = [sv documentVisibleRect];
4682 NSPoint pt = { tvr.origin.x, tvr.origin.y };
4683 if (xscroll > 0) pt.x += tvr.size.width-1;
4684 if (yscroll > 0) pt.y += tvr.size.height-1;
4686 const NSInteger nr = [tv numberOfRows];
4687 NSInteger rowidx = [tv rowAtPoint:pt];
4688 if (rowidx < 0) rowidx=0;
4689 else if (rowidx >= nr) rowidx=nr-1;
4691 const NSInteger nc = [tv numberOfColumns];
4692 NSInteger colidx = [tv columnAtPoint:pt];
4693 if (colidx < 0) colidx=0;
4694 else if (colidx >= nc) colidx = nc-1;
4696 // colidx is our column index, not the display order, convert
4697 if ([tv isKindOfClass:[SWELL_ListView class]]) colidx = [(SWELL_ListView*)tv getColumnPos:(int)colidx];
4699 NSRect ir = [tv frameOfCellAtColumn:colidx row:rowidx];
4703 if (ir.size.height) rowidx += yscroll / ir.size.height;
4705 if (rowidx < 0) rowidx=0;
4706 else if (rowidx >= nr) rowidx = nr-1;
4707 [tv scrollRowToVisible:rowidx];
4712 if (ir.size.width) colidx += xscroll / ir.size.width;
4714 if (colidx < 0) colidx=0;
4715 else if (colidx >= nc) colidx = nc-1;
4717 // scrollColumnToVisible takes display order, which we have here
4718 [tv scrollColumnToVisible:colidx];
4725 bool ListView_GetScroll(HWND h, POINT* p)
4727 NSTableView* tv = (NSTableView*)h;
4728 NSScrollView* sv = [tv enclosingScrollView];
4731 NSRect cr = [sv documentVisibleRect];
4740 void ListView_SortItems(HWND hwnd, PFNLVCOMPARE compf, LPARAM parm)
4743 if (![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
4744 SWELL_ListView *tv=(SWELL_ListView*)hwnd;
4745 if (tv->m_lbMode || (tv->style & LVS_OWNERDATA) || !tv->m_items) return;
4748 tmp.Resize(tv->m_items->GetSize()*sizeof(void *));
4751 for(x=0;x<tv->m_items->GetSize();x++)
4753 SWELL_ListView_Row *r = tv->m_items->Get(x);
4756 r->m_tmp = !![tv isRowSelected:x];
4760 __listview_mergesort_internal(tv->m_items->GetList(),tv->m_items->GetSize(),sizeof(void *),compf,parm,(char*)tmp.Get());
4763 NSMutableIndexSet *indexSet = [[NSMutableIndexSet alloc] init];
4765 for(x=0;x<tv->m_items->GetSize();x++)
4767 SWELL_ListView_Row *r = tv->m_items->Get(x);
4768 if (r && (r->m_tmp&1)) [indexSet addIndex:x];
4770 [tv selectRowIndexes:indexSet byExtendingSelection:NO];
4778 HWND WindowFromPoint(POINT p)
4780 NSArray *windows=[NSApp orderedWindows];
4781 const NSInteger cnt=windows ? [windows count] : 0;
4783 NSWindow *kw = [NSApp keyWindow];
4784 if (kw && windows && [windows containsObject:kw]) kw=NULL;
4786 NSWindow *bestwnd=0;
4787 for (NSInteger x = kw ? -1 : 0; x < cnt; x ++)
4790 if (x>=0) wnd=[windows objectAtIndex:x];
4791 if (wnd && [wnd isVisible])
4793 NSRect fr=[wnd frame];
4794 if (p.x >= fr.origin.x && p.x < fr.origin.x + fr.size.width &&
4795 p.y >= fr.origin.y && p.y < fr.origin.y + fr.size.height)
4803 if (!bestwnd) return 0;
4804 NSPoint pt=NSMakePoint(p.x,p.y);
4805 NSPoint lpt=[bestwnd convertScreenToBase:pt];
4806 NSView *v=[[bestwnd contentView] hitTest:lpt];
4807 if (v) return (HWND)v;
4808 return (HWND)[bestwnd contentView];
4811 void UpdateWindow(HWND hwnd)
4813 if (hwnd && [(id)hwnd isKindOfClass:[NSView class]] && [(NSView *)hwnd needsDisplay])
4815 NSWindow *wnd = [(NSView *)hwnd window];
4816 [wnd displayIfNeeded];
4820 void SWELL_FlushWindow(HWND h)
4825 if ([(id)h isKindOfClass:[NSView class]])
4827 if ([(NSView *)h needsDisplay]) return;
4829 w = [(NSView *)h window];
4831 else if ([(id)h isKindOfClass:[NSWindow class]]) w = (NSWindow *)h;
4833 if (w && ![w viewsNeedDisplay])
4840 static void InvalidateSuperViews(NSView *view)
4843 view = [view superview];
4846 if ([view isKindOfClass:[SWELL_hwndChild class]])
4848 if (((SWELL_hwndChild *)view)->m_isdirty&2) break;
4849 ((SWELL_hwndChild *)view)->m_isdirty|=2;
4851 view = [view superview];
4855 BOOL InvalidateRect(HWND hwnd, const RECT *r, int eraseBk)
4857 if (!hwnd) return FALSE;
4859 if ([view isKindOfClass:[NSWindow class]]) view=[view contentView];
4860 if ([view isKindOfClass:[NSView class]])
4865 bool skip_parent_invalidate=false;
4866 if ([view isKindOfClass:[SWELL_hwndChild class]])
4868 if (!(((SWELL_hwndChild *)view)->m_isdirty&1))
4870 ((SWELL_hwndChild *)view)->m_isdirty|=1;
4872 else skip_parent_invalidate=true; // if already dirty, then assume parents are already dirty too
4874 if (!skip_parent_invalidate)
4876 InvalidateSuperViews(view);
4881 if (tr.top>tr.bottom)
4883 int a = tr.top; tr.top=tr.bottom; tr.bottom=a;
4885 [sv setNeedsDisplayInRect:NSMakeRect(tr.left,tr.top,tr.right-tr.left,tr.bottom-tr.top)];
4887 else [sv setNeedsDisplay:YES];
4893 static HWND m_fakeCapture;
4894 static BOOL m_capChangeNotify;
4898 return m_fakeCapture;
4901 HWND SetCapture(HWND hwnd)
4903 HWND oc=m_fakeCapture;
4904 int ocn=m_capChangeNotify;
4906 m_capChangeNotify = hwnd && [(id)hwnd respondsToSelector:@selector(swellCapChangeNotify)] && [(SWELL_hwndChild*)hwnd swellCapChangeNotify];
4908 if (ocn && oc && oc != hwnd) SendMessage(oc,WM_CAPTURECHANGED,0,(LPARAM)hwnd);
4913 void ReleaseCapture()
4915 HWND h=m_fakeCapture;
4917 if (m_capChangeNotify && h)
4919 SendMessage(h,WM_CAPTURECHANGED,0,0);
4924 HDC BeginPaint(HWND hwnd, PAINTSTRUCT *ps)
4927 memset(ps,0,sizeof(PAINTSTRUCT));
4928 if (!hwnd) return 0;
4930 if (![turd respondsToSelector:@selector(getSwellPaintInfo:)]) return 0;
4932 [(SWELL_hwndChild*)turd getSwellPaintInfo:(PAINTSTRUCT *)ps];
4936 BOOL EndPaint(HWND hwnd, PAINTSTRUCT *ps)
4941 LRESULT DefWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4943 if (msg==WM_RBUTTONUP||msg==WM_NCRBUTTONUP)
4945 POINT p={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
4947 if (msg==WM_RBUTTONUP)
4949 ClientToScreen(hwnd,&p);
4950 HWND h=WindowFromPoint(p);
4951 if (h && IsChild(hwnd,h)) hwndDest=h;
4953 SendMessage(hwnd,WM_CONTEXTMENU,(WPARAM)hwndDest,(p.x&0xffff)|(p.y<<16));
4956 else if (msg==WM_CONTEXTMENU || msg == WM_MOUSEWHEEL || msg == WM_MOUSEHWHEEL || msg == WM_GESTURE)
4958 if ([(id)hwnd isKindOfClass:[NSView class]])
4960 NSView *h=(NSView *)hwnd;
4961 while (h && [[h window] contentView] != h)
4964 if (h && [h respondsToSelector:@selector(onSwellMessage:p1:p2:)])
4966 return SendMessage((HWND)h,msg,wParam,lParam);
4971 else if (msg==WM_NCHITTEST)
4976 GetWindowRect(hwnd,&r);
4977 POINT pt={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
4979 if (r.top > r.bottom)
4981 pt.y = r.bottom + (r.top - pt.y); // translate coordinate into flipped-window
4983 int a=r.top; r.top=r.bottom; r.bottom=a;
4985 NCCALCSIZE_PARAMS p={{r,}};
4986 SendMessage(hwnd,WM_NCCALCSIZE,FALSE,(LPARAM)&p);
4987 if (!PtInRect(&p.rgrc[0],pt)) rv=HTNOWHERE;
4991 else if (msg==WM_KEYDOWN || msg==WM_KEYUP) return 69;
4992 else if (msg == WM_DISPLAYCHANGE)
4994 if ([(id)hwnd isKindOfClass:[NSView class]])
4996 NSArray *ch = [(NSView *)hwnd subviews];
5000 for(x=0;x<[ch count]; x ++)
5002 NSView *v = [ch objectAtIndex:x];
5003 sendSwellMessage(v,WM_DISPLAYCHANGE,wParam,lParam);
5007 void SWELL_DoDialogColorUpdates(HWND hwnd, DLGPROC d, bool isUpdate);
5008 DLGPROC d = (DLGPROC)GetWindowLong(hwnd,DWL_DLGPROC);
5009 if (d) SWELL_DoDialogColorUpdates(hwnd,d,true);
5017 void SWELL_BroadcastMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
5020 NSArray *ch=[NSApp orderedWindows];
5021 for(x=0;x<[ch count]; x ++)
5023 NSView *v = [[ch objectAtIndex:x] contentView];
5024 if (v && [v respondsToSelector:@selector(onSwellMessage:p1:p2:)])
5026 [(SWELL_hwndChild *)v onSwellMessage:uMsg p1:wParam p2:lParam];
5028 if (uMsg == WM_DISPLAYCHANGE)
5029 InvalidateRect((HWND)v,NULL,FALSE);
5047 ///////////////// clipboard compatability (NOT THREAD SAFE CURRENTLY)
5050 BOOL DragQueryPoint(HDROP hDrop,LPPOINT pt)
5052 if (!hDrop) return 0;
5053 DROPFILES *df=(DROPFILES*)GlobalLock(hDrop);
5056 GlobalUnlock(hDrop);
5060 void DragFinish(HDROP hDrop)
5062 //do nothing for now (caller will free hdrops)
5065 UINT DragQueryFile(HDROP hDrop, UINT wf, char *buf, UINT bufsz)
5067 if (!hDrop) return 0;
5068 DROPFILES *df=(DROPFILES*)GlobalLock(hDrop);
5071 char *p=(char*)df + df->pFiles;
5072 if (wf == 0xFFFFFFFF)
5088 lstrcpyn_safe(buf,p,bufsz);
5098 GlobalUnlock(hDrop);
5112 static WDL_PtrList<void> m_clip_recs;
5113 static WDL_PtrList<NSString> m_clip_fmts;
5114 static WDL_PtrList<char> m_clip_curfmts;
5115 struct swell_pendingClipboardStates
5119 swell_pendingClipboardStates(UINT _type, HANDLE _h)
5124 ~swell_pendingClipboardStates()
5130 static WDL_PtrList<swell_pendingClipboardStates> m_clipsPending;
5132 bool OpenClipboard(HWND hwndDlg)
5134 m_clipsPending.Empty(true);
5136 CF_TEXT; // ensure this type is registered
5138 NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:@"SWELL_APP"];
5139 m_clip_curfmts.Empty();
5140 NSArray *ar=[pasteboard types];
5143 if (ar && [ar count])
5147 for (x = 0; x < [ar count]; x ++)
5149 NSString *s=[ar objectAtIndex:x];
5152 for (y = 0; y < m_clip_fmts.GetSize(); y ++)
5154 if ([s compare:(NSString *)m_clip_fmts.Get(y)]==NSOrderedSame)
5156 if (m_clip_curfmts.Find((char*)(INT_PTR)(y+1))<0)
5157 m_clip_curfmts.Add((char*)(INT_PTR)(y+1));
5167 void CloseClipboard() // frees any remaining items in clipboard
5169 m_clip_recs.Empty(GlobalFree);
5171 if (m_clipsPending.GetSize())
5174 for (x=0;x<m_clipsPending.GetSize() && m_clipsPending.Get(x)->type != CF_TEXT;x++);
5175 NSPasteboard *pasteboard = x<m_clipsPending.GetSize() ? [NSPasteboard generalPasteboard] : [NSPasteboard pasteboardWithName:@"SWELL_APP"];
5177 NSMutableArray *ar = [[NSMutableArray alloc] initWithCapacity:m_clipsPending.GetSize()];
5179 for (x=0;x<m_clipsPending.GetSize();x++)
5181 swell_pendingClipboardStates *cs=m_clipsPending.Get(x);
5182 NSString *fmt=m_clip_fmts.Get(cs->type-1);
5183 if (fmt) [ar addObject:fmt];
5187 [pasteboard declareTypes:ar owner:nil];
5188 for (x=0;x<m_clipsPending.GetSize();x++)
5190 swell_pendingClipboardStates *cs=m_clipsPending.Get(x);
5191 NSString *fmt=m_clip_fmts.Get(cs->type-1);
5194 void *buf=GlobalLock(cs->h);
5197 int bufsz=GlobalSize(cs->h);
5198 if (cs->type == CF_TEXT)
5200 char *t = (char *)malloc(bufsz+1);
5203 memcpy(t,buf,bufsz);
5205 NSString *s = (NSString*)SWELL_CStringToCFString(t);
5206 [pasteboard setString:s forType:fmt];
5213 NSData *data=[NSData dataWithBytes:buf length:bufsz];
5214 [pasteboard setData:data forType:fmt];
5216 GlobalUnlock(cs->h);
5221 m_clipsPending.Empty(true);
5225 UINT EnumClipboardFormats(UINT lastfmt) // won't enumerate CF_TEXT (since thats a separate pasteboard)
5227 if (!m_clip_curfmts.GetSize()) return 0;
5228 if (lastfmt == 0) return (UINT)(INT_PTR)m_clip_curfmts.Get(0);
5230 for (x = m_clip_curfmts.GetSize()-2; x >= 0; x--) // scan backwards to avoid dupes causing infinite loops
5232 if ((UINT)(INT_PTR)m_clip_curfmts.Get(x) == lastfmt)
5233 return (UINT)(INT_PTR)m_clip_curfmts.Get(x+1);
5238 HANDLE GetClipboardData(UINT type)
5240 NSString *fmt=m_clip_fmts.Get(type-1);
5242 NSPasteboard *pasteboard = type == CF_TEXT ? [NSPasteboard generalPasteboard] : [NSPasteboard pasteboardWithName:@"SWELL_APP"];
5245 if (type == CF_TEXT)
5248 NSString *str = [pasteboard stringForType:fmt];
5251 int l = (int) ([str length]*4 + 32);
5252 char *buf = (char *)malloc(l);
5254 SWELL_CFStringToCString(str,buf,l);
5256 l = (int) (strlen(buf)+1);
5258 memcpy(GlobalLock(h),buf,l);
5266 NSData *data=[pasteboard dataForType:fmt];
5267 if (!data) return 0;
5268 int l = (int)[data length];
5270 if (h) memcpy(GlobalLock(h),[data bytes],l);
5274 if (h) m_clip_recs.Add(h);
5278 void EmptyClipboard()
5280 m_clipsPending.Empty(true);
5284 void SetClipboardData(UINT type, HANDLE h)
5286 m_clipsPending.Add(new swell_pendingClipboardStates(type,h));
5289 UINT RegisterClipboardFormat(const char *desc)
5292 if (!strcmp(desc,"SWELL__CF_TEXT"))
5294 s=NSStringPboardType;
5297 if (!s) s=(NSString*)SWELL_CStringToCFString(desc);
5299 for (x = 0; x < m_clip_fmts.GetSize(); x ++)
5301 NSString *ts=m_clip_fmts.Get(x);
5302 if ([ts compare:s]==NSOrderedSame)
5309 return m_clip_fmts.GetSize();
5312 int EnumPropsEx(HWND hwnd, PROPENUMPROCEX proc, LPARAM lParam)
5314 if (!hwnd || ![(id)hwnd respondsToSelector:@selector(swellEnumProps:lp:)]) return -1;
5315 return (int)[(SWELL_hwndChild *)hwnd swellEnumProps:proc lp:lParam];
5318 HANDLE GetProp(HWND hwnd, const char *name)
5320 if (!hwnd || ![(id)hwnd respondsToSelector:@selector(swellGetProp:wantRemove:)]) return NULL;
5321 return (HANDLE)[(SWELL_hwndChild *)hwnd swellGetProp:name wantRemove:NO];
5324 BOOL SetProp(HWND hwnd, const char *name, HANDLE val)
5326 if (!hwnd || ![(id)hwnd respondsToSelector:@selector(swellSetProp:value:)]) return FALSE;
5327 return (BOOL)!![(SWELL_hwndChild *)hwnd swellSetProp:name value:val];
5330 HANDLE RemoveProp(HWND hwnd, const char *name)
5332 if (!hwnd || ![(id)hwnd respondsToSelector:@selector(swellGetProp:wantRemove:)]) return NULL;
5333 return (HANDLE)[(SWELL_hwndChild *)hwnd swellGetProp:name wantRemove:YES];
5337 int GetSystemMetrics(int p)
5344 NSScreen *s=[NSScreen mainScreen];
5345 if (!s) return 1024;
5346 return p==SM_CXSCREEN ? [s frame].size.width : [s frame].size.height;
5348 case SM_CXHSCROLL: return 16;
5349 case SM_CYHSCROLL: return 16;
5350 case SM_CXVSCROLL: return 16;
5351 case SM_CYVSCROLL: return 16;
5356 BOOL ScrollWindow(HWND hwnd, int xamt, int yamt, const RECT *lpRect, const RECT *lpClipRect)
5358 if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]]) hwnd=(HWND)[(id)hwnd contentView];
5359 if (!hwnd || ![(id)hwnd isKindOfClass:[NSView class]]) return FALSE;
5361 if (!xamt && !yamt) return FALSE;
5363 // move child windows only
5368 NSArray *ar=[(NSView*)hwnd subviews];
5369 NSInteger i,c=[ar count];
5372 NSView *v=(NSView *)[ar objectAtIndex:i];
5379 [(id)hwnd setNeedsDisplay:YES];
5383 NSRect r=[(NSView*)hwnd bounds];
5386 [(id)hwnd setBoundsOrigin:r.origin];
5387 [(id)hwnd setNeedsDisplay:YES];
5392 HWND FindWindowEx(HWND par, HWND lastw, const char *classname, const char *title)
5394 // note: this currently is far far far from fully functional, bleh
5397 if (!title) return NULL;
5399 // get a list of top level windows, find any that match
5400 // (this does not scan child windows, which is a todo really)
5402 NSArray *ch=[NSApp windows];
5403 NSInteger x=0,n=[ch count];
5408 NSWindow *w = [ch objectAtIndex:x];
5409 if ((HWND)w == lastw || (HWND)[w contentView] == lastw) break;
5414 NSString *srch=(NSString*)SWELL_CStringToCFString(title);
5415 for(;x<n && !rv; x ++)
5417 NSWindow *w = [ch objectAtIndex:x];
5418 if ([[w title] isEqualToString:srch]) rv=(HWND)[w contentView];
5424 HWND h=lastw?GetWindow(lastw,GW_HWNDNEXT):GetWindow(par,GW_CHILD);
5432 GetWindowText(h,buf,sizeof(buf));
5433 if (strcmp(title,buf)) isOk=false;
5437 if (!stricmp(classname,"Static") && ![(id)h isKindOfClass:[NSTextField class]]) isOk=false;
5438 // todo: other classname translations
5442 h=GetWindow(h,GW_HWNDNEXT);
5447 BOOL TreeView_SetIndent(HWND hwnd, int indent)
5449 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return 0;
5450 SWELL_TreeView* tv = (SWELL_TreeView*)hwnd;
5451 [tv setIndentationPerLevel:(float)indent];
5455 HTREEITEM TreeView_InsertItem(HWND hwnd, TV_INSERTSTRUCT *ins)
5457 if (!hwnd || !ins) return 0;
5458 if (![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return 0;
5460 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5462 HTREEITEM__ *par=NULL;
5465 if (ins->hParent && ins->hParent != TVI_ROOT && ins->hParent != TVI_FIRST && ins->hParent != TVI_LAST && ins->hParent != TVI_SORT)
5467 if ([tv findItem:ins->hParent parOut:&par idxOut:&inspos])
5469 par = (HTREEITEM__ *)ins->hParent;
5474 if (ins->hInsertAfter == TVI_FIRST) inspos=0;
5475 else if (ins->hInsertAfter == TVI_LAST || ins->hInsertAfter == TVI_SORT || !ins->hInsertAfter) inspos=par ? par->m_children.GetSize() : tv->m_items ? tv->m_items->GetSize() : 0;
5476 else inspos = par ? par->m_children.Find((HTREEITEM__*)ins->hInsertAfter)+1 : tv->m_items ? tv->m_items->Find((HTREEITEM__*)ins->hInsertAfter)+1 : 0;
5478 HTREEITEM__ *item=new HTREEITEM__;
5479 if (ins->item.mask & TVIF_CHILDREN)
5480 item->m_haschildren = !!ins->item.cChildren;
5481 if (ins->item.mask & TVIF_PARAM) item->m_param = ins->item.lParam;
5482 if (ins->item.mask & TVIF_TEXT) item->m_value = strdup(ins->item.pszText);
5485 if (!tv->m_items) tv->m_items = new WDL_PtrList<HTREEITEM__>;
5486 tv->m_items->Insert(inspos,item);
5488 else par->m_children.Insert(inspos,item);
5491 return (HTREEITEM) item;
5494 BOOL TreeView_Expand(HWND hwnd, HTREEITEM item, UINT flag)
5496 if (!hwnd || !item) return false;
5498 if (![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return false;
5500 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5502 id itemid=((HTREEITEM__*)item)->m_dh;
5503 bool isExp=!![tv isItemExpanded:itemid];
5505 if (flag == TVE_EXPAND && !isExp) [tv expandItem:itemid];
5506 else if (flag == TVE_COLLAPSE && isExp) [tv collapseItem:itemid];
5507 else if (flag==TVE_TOGGLE)
5509 if (isExp) [tv collapseItem:itemid];
5510 else [tv expandItem:itemid];
5518 HTREEITEM TreeView_GetSelection(HWND hwnd)
5520 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return NULL;
5522 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5523 NSInteger idx=[tv selectedRow];
5524 if (idx<0) return NULL;
5526 SWELL_DataHold *t=[tv itemAtRow:idx];
5527 if (t) return (HTREEITEM)[t getValue];
5532 void TreeView_DeleteItem(HWND hwnd, HTREEITEM item)
5534 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5535 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5537 HTREEITEM__ *par=NULL;
5540 if ([tv findItem:item parOut:&par idxOut:&idx])
5544 par->m_children.Delete(idx,true);
5546 else if (tv->m_items)
5548 tv->m_items->Delete(idx,true);
5554 void TreeView_DeleteAllItems(HWND hwnd)
5556 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5557 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5559 if (tv->m_items) tv->m_items->Empty(true);
5563 void TreeView_SelectItem(HWND hwnd, HTREEITEM item)
5565 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5567 NSInteger row=[(SWELL_TreeView*)hwnd rowForItem:((HTREEITEM__*)item)->m_dh];
5569 [(SWELL_TreeView*)hwnd selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
5574 NMTREEVIEW nm={{(HWND)hwnd,(UINT_PTR)[(SWELL_TreeView*)hwnd tag],TVN_SELCHANGED},};
5575 SendMessage(GetParent(hwnd),WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
5580 BOOL TreeView_GetItem(HWND hwnd, LPTVITEM pitem)
5582 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]] || !pitem || !(pitem->mask & TVIF_HANDLE) || !(pitem->hItem)) return FALSE;
5584 HTREEITEM__ *ti = (HTREEITEM__*)pitem->hItem;
5585 pitem->cChildren = ti->m_haschildren ? 1:0;
5586 pitem->lParam = ti->m_param;
5587 if ((pitem->mask&TVIF_TEXT)&&pitem->pszText&&pitem->cchTextMax>0)
5589 lstrcpyn_safe(pitem->pszText,ti->m_value?ti->m_value:"",pitem->cchTextMax);
5594 NSInteger itemRow = [(SWELL_TreeView*)hwnd rowForItem:ti->m_dh];
5595 if (itemRow >= 0 && [(SWELL_TreeView*)hwnd isRowSelected:itemRow])
5596 pitem->state |= TVIS_SELECTED;
5597 if ([(SWELL_TreeView*)hwnd isItemExpanded:ti->m_dh])
5598 pitem->state |= TVIS_EXPANDED;
5603 BOOL TreeView_SetItem(HWND hwnd, LPTVITEM pitem)
5605 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]] || !pitem || !(pitem->mask & TVIF_HANDLE) || !(pitem->hItem)) return FALSE;
5607 HTREEITEM__ *par=NULL;
5610 if (![(SWELL_TreeView*)hwnd findItem:pitem->hItem parOut:&par idxOut:&idx]) return FALSE;
5612 HTREEITEM__ *ti = (HTREEITEM__*)pitem->hItem;
5614 if (pitem->mask & TVIF_CHILDREN) ti->m_haschildren = pitem->cChildren?1:0;
5615 if (pitem->mask & TVIF_PARAM) ti->m_param = pitem->lParam;
5617 if ((pitem->mask&TVIF_TEXT)&&pitem->pszText)
5620 ti->m_value=strdup(pitem->pszText);
5621 InvalidateRect(hwnd, 0, FALSE);
5624 if (pitem->stateMask & TVIS_SELECTED)
5626 NSInteger itemRow = [(SWELL_TreeView*)hwnd rowForItem:ti->m_dh];
5629 if (pitem->state&TVIS_SELECTED)
5631 [(SWELL_TreeView*)hwnd selectRowIndexes:[NSIndexSet indexSetWithIndex:itemRow] byExtendingSelection:NO];
5637 NMTREEVIEW nm={{(HWND)hwnd,(UINT_PTR)[(SWELL_TreeView*)hwnd tag],TVN_SELCHANGED},};
5638 SendMessage(GetParent(hwnd),WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
5645 // todo figure out unselect?!
5646 // [(SWELL_TreeView*)hwnd selectRowIndexes:[NSIndexSet indexSetWithIndex:itemRow] byExtendingSelection:NO];
5651 if (pitem->stateMask & TVIS_EXPANDED)
5652 TreeView_Expand(hwnd,pitem->hItem,(pitem->state&TVIS_EXPANDED)?TVE_EXPAND:TVE_COLLAPSE);
5658 HTREEITEM TreeView_HitTest(HWND hwnd, TVHITTESTINFO *hti)
5660 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]] || !hti) return NULL;
5661 SWELL_TreeView* tv = (SWELL_TreeView*)hwnd;
5666 for (i = 0; i < [tv numberOfRows]; ++i)
5668 NSRect r = [tv rectOfRow:i];
5669 if (x >= r.origin.x && x < r.origin.x+r.size.width && y >= r.origin.y && y < r.origin.y+r.size.height)
5671 SWELL_DataHold* t = [tv itemAtRow:i];
5672 if (t) return (HTREEITEM)[t getValue];
5677 return NULL; // not hit
5680 HTREEITEM TreeView_GetRoot(HWND hwnd)
5682 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return NULL;
5683 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5685 if (!tv->m_items) return 0;
5686 return (HTREEITEM) tv->m_items->Get(0);
5689 HTREEITEM TreeView_GetChild(HWND hwnd, HTREEITEM item)
5691 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return NULL;
5693 HTREEITEM__ *titem=(HTREEITEM__ *)item;
5694 if (!titem) return TreeView_GetRoot(hwnd);
5696 return (HTREEITEM) titem->m_children.Get(0);
5698 HTREEITEM TreeView_GetNextSibling(HWND hwnd, HTREEITEM item)
5700 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return NULL;
5701 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
5703 if (!item) return TreeView_GetRoot(hwnd);
5705 HTREEITEM__ *par=NULL;
5707 if ([tv findItem:item parOut:&par idxOut:&idx])
5711 return par->m_children.Get(idx+1);
5713 if (tv->m_items) return tv->m_items->Get(idx+1);
5718 void TreeView_SetBkColor(HWND hwnd, int color)
5720 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5721 [(NSOutlineView*)hwnd setBackgroundColor:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f
5722 green:GetGValue(color)/255.0f
5723 blue:GetBValue(color)/255.0f alpha:1.0f]];
5725 void TreeView_SetTextColor(HWND hwnd, int color)
5727 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]]) return;
5729 SWELL_TreeView *f = (SWELL_TreeView *)hwnd;
5730 [f->m_fgColor release];
5731 f->m_fgColor = [NSColor colorWithCalibratedRed:GetRValue(color)/255.0f
5732 green:GetGValue(color)/255.0f
5733 blue:GetBValue(color)/255.0f alpha:1.0f];
5734 [f->m_fgColor retain];
5736 void ListView_SetBkColor(HWND hwnd, int color)
5738 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
5739 [(NSTableView*)hwnd setBackgroundColor:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f
5740 green:GetGValue(color)/255.0f
5741 blue:GetBValue(color)/255.0f alpha:1.0f]];
5744 void ListView_SetSelColors(HWND hwnd, int *colors, int ncolors) // this works for SWELL_ListView as well as SWELL_TreeView
5747 NSMutableArray *ar=[[NSMutableArray alloc] initWithCapacity:ncolors];
5751 const int color = colors ? *colors++ : 0;
5752 [ar addObject:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f
5753 green:GetGValue(color)/255.0f
5754 blue:GetBValue(color)/255.0f alpha:1.0f]];
5757 if ([(id)hwnd isKindOfClass:[SWELL_ListView class]])
5759 SWELL_ListView *lv = (SWELL_ListView*)hwnd;
5760 [lv->m_selColors release];
5763 else if ([(id)hwnd isKindOfClass:[SWELL_TreeView class]])
5765 SWELL_TreeView *lv = (SWELL_TreeView*)hwnd;
5766 [lv->m_selColors release];
5774 void ListView_SetGridColor(HWND hwnd, int color)
5776 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
5777 [(NSTableView*)hwnd setGridColor:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f
5778 green:GetGValue(color)/255.0f
5779 blue:GetBValue(color)/255.0f alpha:1.0f]];
5781 void ListView_SetTextBkColor(HWND hwnd, int color)
5783 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
5784 // not implemented atm
5786 void ListView_SetTextColor(HWND hwnd, int color)
5788 if (!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]]) return;
5790 SWELL_ListView *f = (SWELL_ListView *)hwnd;
5791 [f->m_fgColor release];
5792 f->m_fgColor = [NSColor colorWithCalibratedRed:GetRValue(color)/255.0f
5793 green:GetGValue(color)/255.0f
5794 blue:GetBValue(color)/255.0f alpha:1.0f];
5795 [f->m_fgColor retain];
5799 BOOL ShellExecute(HWND hwndDlg, const char *action, const char *content1, const char *content2, const char *content3, int blah)
5801 if (content1 && !strnicmp(content1,"http://",7))
5803 NSWorkspace *wk = [NSWorkspace sharedWorkspace];
5804 if (!wk) return FALSE;
5805 NSString *fnstr=(NSString *)SWELL_CStringToCFString(content1);
5806 BOOL ret=[wk openURL:[NSURL URLWithString:fnstr]];
5811 if (content1 && !stricmp(content1,"explorer.exe")) content1="";
5812 else if (content1 && (!stricmp(content1,"notepad.exe")||!stricmp(content1,"notepad"))) content1="TextEdit.app";
5814 if (content2 && !stricmp(content2,"explorer.exe")) content2="";
5816 if (content1 && content2 && *content1 && *content2)
5818 NSWorkspace *wk = [NSWorkspace sharedWorkspace];
5819 if (!wk) return FALSE;
5820 NSString *appstr=(NSString *)SWELL_CStringToCFString(content1);
5821 NSString *fnstr=(NSString *)SWELL_CStringToCFString(content2);
5822 BOOL ret=[wk openFile:fnstr withApplication:appstr andDeactivate:YES];
5827 else if ((content1&&*content1) || (content2&&*content2))
5829 const char *fn = (content1 && *content1) ? content1 : content2;
5830 NSWorkspace *wk = [NSWorkspace sharedWorkspace];
5831 if (!wk) return FALSE;
5832 NSString *fnstr = nil;
5835 if (fn && !strnicmp(fn, "/select,\"", 9))
5837 char* tmp = strdup(fn+9);
5838 if (*tmp && tmp[strlen(tmp)-1]=='\"') tmp[strlen(tmp)-1]='\0';
5841 if ([wk respondsToSelector:@selector(activateFileViewerSelectingURLs:)]) // 10.6+
5843 fnstr=(NSString *)SWELL_CStringToCFString(tmp);
5844 NSURL *url = [NSURL fileURLWithPath:fnstr isDirectory:false];
5847 [wk activateFileViewerSelectingURLs:[NSArray arrayWithObjects:url, nil]]; // NSArray (and NSURL) autoreleased
5853 if (WDL_remove_filepart(tmp))
5855 fnstr=(NSString *)SWELL_CStringToCFString(tmp);
5856 ret=[wk openFile:fnstr];
5862 else if (strlen(fn)>4 && !stricmp(fn+strlen(fn)-4,".app"))
5864 fnstr=(NSString *)SWELL_CStringToCFString(fn);
5865 ret=[wk launchApplication:fnstr];
5869 fnstr=(NSString *)SWELL_CStringToCFString(fn);
5870 ret=[wk openFile:fnstr];
5881 @implementation SWELL_FocusRectWnd
5883 -(BOOL)isOpaque { return YES; }
5884 -(void) drawRect:(NSRect)rect
5886 NSColor *col=[NSColor colorWithCalibratedRed:0.5 green:0.5 blue:0.5 alpha:1.0];
5889 CGRect r = CGRectMake(rect.origin.x,rect.origin.y,rect.size.width,rect.size.height);
5891 CGContextRef ctx = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
5893 CGContextFillRect(ctx,r);
5898 // r=NULL to "free" handle
5899 // otherwise r is in hwndPar coordinates
5900 void SWELL_DrawFocusRect(HWND hwndPar, RECT *rct, void **handle)
5902 if (!handle) return;
5903 NSWindow *wnd = (NSWindow *)*handle;
5909 NSWindow *ow=[wnd parentWindow];
5910 if (ow) [ow removeChildWindow:wnd];
5911 // [wnd setParentWindow:nil];
5921 ClientToScreen(hwndPar,((LPPOINT)&r));
5922 ClientToScreen(hwndPar,((LPPOINT)&r)+1);
5928 if (r.top>r.bottom) { int a=r.top; r.top=r.bottom;r.bottom=a; }
5929 NSRect rr=NSMakeRect(r.left,r.top,r.right-r.left,r.bottom-r.top);
5934 if ([(id)hwndPar isKindOfClass:[NSWindow class]]) par=(NSWindow *)hwndPar;
5935 else if ([(id)hwndPar isKindOfClass:[NSView class]]) par=[(NSView *)hwndPar window];
5939 if (wnd && ([wnd parentWindow] != par))
5941 NSWindow *ow=[wnd parentWindow];
5942 if (ow) [ow removeChildWindow:wnd];
5943 // [wnd setParentWindow:nil];
5951 *handle = wnd = [[NSWindow alloc] initWithContentRect:rr styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
5952 [wnd setOpaque:YES];
5953 [wnd setAlphaValue:0.5];
5954 [wnd setExcludedFromWindowsMenu:YES];
5955 [wnd setIgnoresMouseEvents:YES];
5956 [wnd setContentView:[[SWELL_FocusRectWnd alloc] init]];
5958 if (par) [par addChildWindow:wnd ordered:NSWindowAbove];
5961 [wnd setLevel:NSPopUpMenuWindowLevel];
5962 [wnd orderFront:wnd];
5964 // [wnd setParentWindow:par];
5965 // [wnd orderWindow:NSWindowAbove relativeTo:[par windowNumber]];
5968 [wnd setFrame:rr display:YES];
5973 @implementation SWELL_PopUpButton
5974 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
5976 -(void)setSwellStyle:(LONG)style { m_style=style; }
5977 -(LONG)getSwellStyle { return m_style; }
5980 @implementation SWELL_ComboBox
5981 STANDARD_CONTROL_NEEDSDISPLAY_IMPL
5983 -(void)setSwellStyle:(LONG)style { m_style=style; }
5984 -(LONG)getSwellStyle { return m_style; }
5985 -(id)init { self = [super init]; if (self) { m_ids=new WDL_PtrList<char>; } return self; }
5986 -(void)dealloc { delete m_ids; [super dealloc]; }
5987 - (BOOL)becomeFirstResponder;
5989 BOOL didBecomeFirstResponder = [super becomeFirstResponder];
5990 if (didBecomeFirstResponder) SendMessage(GetParent((HWND)self),WM_COMMAND,[self tag]|(EN_SETFOCUS<<16),(LPARAM)self);
5991 return didBecomeFirstResponder;
5998 bool SWELL_HandleMouseEvent(NSEvent *evt)
6000 NSEventType etype = [evt type];
6001 if (GetCapture()) return false;
6002 if (etype >= NSLeftMouseDown && etype <= NSRightMouseDragged)
6007 NSWindow *w = [evt window];
6010 NSView *cview = [w contentView];
6011 NSView *besthit=NULL;
6014 NSPoint lpt = [evt locationInWindow];
6015 NSView *hitv=[cview hitTest:lpt];
6016 lpt = [w convertBaseToScreen:lpt];
6018 int xpos=(int)floor(lpt.x);
6019 int ypos=(int)floor(lpt.y);
6023 int ht=(int)sendSwellMessage(hitv,WM_NCHITTEST,0,MAKELPARAM(xpos,ypos));
6024 if (ht && ht != HTCLIENT) besthit=hitv;
6026 if (hitv==cview) break;
6027 hitv = [hitv superview];
6032 if (etype == NSLeftMouseDown) [besthit mouseDown:evt];
6033 else if (etype == NSLeftMouseUp) [besthit mouseUp:evt];
6034 else if (etype == NSLeftMouseDragged) [besthit mouseDragged:evt];
6035 else if (etype == NSRightMouseDown) [besthit rightMouseDown:evt];
6036 else if (etype == NSRightMouseUp) [besthit rightMouseUp:evt];
6037 else if (etype == NSRightMouseDragged) [besthit rightMouseDragged:evt];
6038 else if (etype == NSMouseMoved) [besthit mouseMoved:evt];
6047 int SWELL_GetWindowWantRaiseAmt(HWND h)
6049 SWELL_ModelessWindow* mw=0;
6050 if ([(id)h isKindOfClass:[SWELL_ModelessWindow class]])
6052 mw=(SWELL_ModelessWindow*)h;
6054 else if ([(id)h isKindOfClass:[NSView class]])
6056 NSWindow* wnd=[(NSView*)h window];
6057 if (wnd && [wnd isKindOfClass:[SWELL_ModelessWindow class]])
6059 mw=(SWELL_ModelessWindow*)wnd;
6062 if (mw) return mw->m_wantraiseamt;
6066 void SWELL_SetWindowWantRaiseAmt(HWND h, int amt)
6068 SWELL_ModelessWindow *mw=NULL;
6069 if ([(id)h isKindOfClass:[SWELL_ModelessWindow class]]) mw=(SWELL_ModelessWindow *)h;
6070 else if ([(id)h isKindOfClass:[NSView class]])
6072 NSWindow *w = [(NSView *)h window];
6073 if (w && [w isKindOfClass:[SWELL_ModelessWindow class]]) mw = (SWELL_ModelessWindow*)w;
6077 int diff = amt - mw->m_wantraiseamt;
6078 mw->m_wantraiseamt = amt;
6079 if (diff && [NSApp isActive]) [mw setLevel:[mw level]+diff];
6084 int SWELL_SetWindowLevel(HWND hwnd, int newlevel)
6086 NSWindow *w = (NSWindow *)hwnd;
6087 if (w && [w isKindOfClass:[NSView class]]) w= [(NSView *)w window];
6089 if (w && [w isKindOfClass:[NSWindow class]])
6091 int ol = (int)[w level];
6092 [w setLevel:newlevel];
6098 void SetAllowNoMiddleManRendering(HWND h, bool allow)
6100 if (!h || ![(id)h isKindOfClass:[SWELL_hwndChild class]]) return;
6101 SWELL_hwndChild* v = (SWELL_hwndChild*)h;
6102 v->m_allow_nomiddleman = allow;
6105 void SetOpaque(HWND h, bool opaque)
6107 if (!h || ![(id)h isKindOfClass:[SWELL_hwndChild class]]) return;
6108 SWELL_hwndChild* v = (SWELL_hwndChild*)h;
6109 [v setOpaque:opaque];
6112 void SetTransparent(HWND h)
6116 if ([(id)h isKindOfClass:[NSWindow class]]) wnd=(NSWindow*)h;
6117 else if ([(id)h isKindOfClass:[NSView class]]) wnd=[(NSView*)h window];
6120 [wnd setBackgroundColor:[NSColor clearColor]];
6125 int SWELL_GetDefaultButtonID(HWND hwndDlg, bool onlyIfEnabled)
6127 if (![(id)hwndDlg isKindOfClass:[NSView class]]) return 0;
6128 NSWindow *wnd = [(NSView *)hwndDlg window];
6129 NSButtonCell * cell = wnd ? [wnd defaultButtonCell] : nil;
6131 if (!cell || !(view=[cell controlView])) return 0;
6132 int cmdid = (int)[view tag];
6133 if (cmdid && onlyIfEnabled)
6135 if (![cell isEnabled]) return 0;
6141 void SWELL_SetWindowRepre(HWND hwnd, const char *fn, bool isDirty)
6145 if ([(id)hwnd isKindOfClass:[NSWindow class]]) w=(NSWindow *)hwnd;
6146 if ([(id)hwnd isKindOfClass:[NSView class]]) w=[(NSView *)hwnd window];
6150 if (GetProp((HWND)[w contentView],"SWELL_DisableWindowRepre")) return;
6152 [w setDocumentEdited:isDirty];
6154 if (!fn || !*fn) [w setRepresentedFilename:@""];
6157 NSString *str = (NSString *)SWELL_CStringToCFString(fn);
6158 [w setRepresentedFilename:str];
6164 void SWELL_SetWindowShadow(HWND hwnd, bool shadow)
6167 NSWindow *w = (NSWindow *)hwnd;
6168 if ([w isKindOfClass:[NSView class]]) w = [(NSView *)w window];
6169 if (w && [w isKindOfClass:[NSWindow class]]) [w setHasShadow:shadow];
6172 #if 0 // not sure if this will interfere with coolSB
6173 BOOL ShowScrollBar(HWND hwnd, int nBar, BOOL vis)
6176 if (nBar == SB_HORZ || nBar == SB_BOTH) v |= WS_HSCROLL;
6177 if (nBar == SB_VERT || nBar == SB_BOTH) v |= WS_VSCROLL;
6180 int s=GetWindowLong(hwnd, GWL_STYLE);
6183 SetWindowLong(hwnd, GWL_STYLE, s);
6184 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
6192 void SWELL_GenerateDialogFromList(const void *_list, int listsz)
6194 #define SIXFROMLIST list->p1,list->p2,list->p3, list->p4, list->p5, list->p6
6195 SWELL_DlgResourceEntry *list = (SWELL_DlgResourceEntry*)_list;
6198 if (!strcmp(list->str1,"__SWELL_BUTTON"))
6200 SWELL_MakeButton(list->flag1,list->str2, SIXFROMLIST);
6202 else if (!strcmp(list->str1,"__SWELL_EDIT"))
6204 SWELL_MakeEditField(SIXFROMLIST);
6206 else if (!strcmp(list->str1,"__SWELL_COMBO"))
6208 SWELL_MakeCombo(SIXFROMLIST);
6210 else if (!strcmp(list->str1,"__SWELL_LISTBOX"))
6212 SWELL_MakeListBox(SIXFROMLIST);
6214 else if (!strcmp(list->str1,"__SWELL_GROUP"))
6216 SWELL_MakeGroupBox(list->str2,SIXFROMLIST);
6218 else if (!strcmp(list->str1,"__SWELL_CHECKBOX"))
6220 SWELL_MakeCheckBox(list->str2,SIXFROMLIST);
6222 else if (!strcmp(list->str1,"__SWELL_LABEL"))
6224 SWELL_MakeLabel(list->flag1, list->str2, SIXFROMLIST);
6226 else if (*list->str2)
6228 SWELL_MakeControl(list->str1, list->flag1, list->str2, SIXFROMLIST);
6235 BOOL EnumChildWindows(HWND hwnd, BOOL (*cwEnumFunc)(HWND,LPARAM),LPARAM lParam)
6237 if (!hwnd || ![(id)hwnd isKindOfClass:[NSView class]]) return TRUE;
6238 NSArray *ar = [(NSView *)hwnd subviews];
6242 NSInteger x,n=[ar count];
6245 NSView *v = [ar objectAtIndex:x];
6248 if ([v isKindOfClass:[NSScrollView class]])
6250 NSView *sv=[(NSScrollView *)v documentView];
6253 if ([v isKindOfClass:[NSClipView class]])
6255 NSView *sv = [(NSClipView *)v documentView];
6259 if (!cwEnumFunc((HWND)v,lParam) || !EnumChildWindows((HWND)v,cwEnumFunc,lParam))
6271 void SWELL_GetDesiredControlSize(HWND hwnd, RECT *r)
6273 if (hwnd && r && [(id)hwnd isKindOfClass:[NSControl class]])
6275 NSControl *c = (NSControl *)hwnd;
6276 NSRect fr = [c frame];
6278 NSRect frnew=[c frame];
6281 r->right = (int)frnew.size.width;
6282 r->bottom = (int)frnew.size.height;
6286 BOOL SWELL_IsGroupBox(HWND hwnd)
6288 if (hwnd && [(id)hwnd isKindOfClass:[SWELL_BoxView class]]) return TRUE;
6291 BOOL SWELL_IsButton(HWND hwnd)
6293 if (hwnd && [(id)hwnd isKindOfClass:[SWELL_Button class]]) return TRUE;
6296 BOOL SWELL_IsStaticText(HWND hwnd)
6298 if (hwnd && [(id)hwnd isKindOfClass:[NSTextField class]]) return TRUE;
6304 bool SWELL_SetAppAutoHideMenuAndDock(int ah)
6307 static NSUInteger _defpres;
6310 if (SWELL_GetOSXVersion()>=0x1060)
6313 _defpres = [(SWELL_AppExtensions*)[NSApplication sharedApplication] presentationOptions];
6322 const int NSApplicationPresentationAutoHideDock = (1 << 0),
6323 NSApplicationPresentationHideDock = (1<<1),
6324 NSApplicationPresentationAutoHideMenuBar = (1 << 2);
6326 if (ah>0) [(SWELL_AppExtensions*)[NSApplication sharedApplication] setPresentationOptions:((ah>=2?NSApplicationPresentationHideDock:NSApplicationPresentationAutoHideDock)|NSApplicationPresentationAutoHideMenuBar)];
6327 else [(SWELL_AppExtensions*)[NSApplication sharedApplication] setPresentationOptions:_defpres];