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(classname) \
60 - (const char *)getSwellClass { return ( classname ); } \
61 - (void)setNeedsDisplay:(BOOL)flag \
63 [super setNeedsDisplay:flag]; \
64 if (flag) InvalidateSuperViews(self); \
66 - (void)setNeedsDisplayInRect:(NSRect)rect \
68 [super setNeedsDisplayInRect:rect]; \
69 InvalidateSuperViews(self); \
73 static WDL_PtrList<char> s_prefix_removals;
75 int g_swell_osx_readonlytext_wndbg = 0;
76 int g_swell_osx_style = 0; // &1 = rounded buttons, &2=big sur styled lists
77 static void *SWELL_CStringToCFString_FilterPrefix(const char *str)
80 while (str[c] && str[c] != '&' && c++<1024);
81 if (!str[c] || c>=1024 || strlen(str)>=1024) return SWELL_CStringToCFString(str);
95 // add to recent prefix removal cache for localization
96 if (WDL_NOT_NORMALLY(s_prefix_removals.GetSize() > 256))
97 s_prefix_removals.Delete(0,true,free);
100 const size_t sz1 = strlen(buf), sz2 = strlen(str);
101 char *p = (char *)malloc(sz1+sz2+2);
102 if (WDL_NORMALLY(p!=NULL))
105 memcpy(p+sz1+1,str,sz2+1);
106 s_prefix_removals.Add(p);
110 return SWELL_CStringToCFString(buf);
114 static int _nsStringSearchProc(const void *_a, const void *_b)
116 NSString *a=(NSString *)_a;
117 NSString *b = (NSString *)_b;
118 return (int)[a compare:b];
120 static int _nsMenuSearchProc(const void *_a, const void *_b)
122 NSString *a=(NSString *)_a;
123 NSMenuItem *b = (NSMenuItem *)_b;
124 return (int)[a compare:[b title]];
126 static int _listviewrowSearchFunc(const void *_a, const void *_b, const void *ctx)
128 const char *a = (const char *)_a;
129 SWELL_ListView_Row *row = (SWELL_ListView_Row *)_b;
131 if (!row || !(b=row->get_col_txt(0))) b="";
134 static int _listviewrowSearchFunc2(const void *_a, const void *_b, const void *ctx)
136 const char *a = (const char *)_a;
137 SWELL_ListView_Row *row = (SWELL_ListView_Row *)_b;
139 if (!row || !(b=row->get_col_txt(0))) b="";
143 // modified bsearch: returns place item SHOULD be in if it's not found
144 static NSInteger arr_bsearch_mod(void *key, NSArray *arr, int (*compar)(const void *, const void *))
146 const NSInteger nmemb = [arr count];
147 NSInteger p,lim,base=0;
149 for (lim = nmemb; lim != 0; lim >>= 1) {
150 p = base + (lim >> 1);
151 int cmp = compar(key, [arr objectAtIndex:p]);
152 if (cmp == 0) return (p);
153 if (cmp > 0) { /* key > p: move right */
154 // check to see if key is less than p+1, if it is, we're done
156 if (base >= nmemb || compar(key,[arr objectAtIndex:base])<=0) return base;
158 } /* else move left */
164 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)
166 const int nmemb = arr->GetSize();
169 for (lim = nmemb; lim != 0; lim >>= 1) {
170 p = base + (lim >> 1);
171 int cmp = compar(key, arr->Get(p),ctx);
172 if (cmp == 0) return (p);
173 if (cmp > 0) { /* key > p: move right */
174 // check to see if key is less than p+1, if it is, we're done
176 if (base >= nmemb || compar(key,arr->Get(base),ctx)<=0) return base;
178 } /* else move left */
184 @implementation SWELL_TabView
185 STANDARD_CONTROL_NEEDSDISPLAY_IMPL("SysTabControl32")
187 -(void)setNotificationWindow:(id)dest
191 -(id)getNotificationWindow
199 -(void) setTag:(NSInteger)tag
203 - (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
207 NMHDR nm={(HWND)self,(UINT_PTR)[self tag],TCN_SELCHANGE};
208 SendMessage((HWND)m_dest,WM_NOTIFY,nm.idFrom,(LPARAM)&nm);
214 @implementation SWELL_ProgressView
215 STANDARD_CONTROL_NEEDSDISPLAY_IMPL("msctls_progress32")
221 -(void) setTag:(NSInteger)tag
225 -(LRESULT)onSwellMessage:(UINT)msg p1:(WPARAM)wParam p2:(LPARAM)lParam
227 if (msg == PBM_SETRANGE)
229 [self setMinValue:LOWORD(lParam)];
230 [self setMaxValue:HIWORD(lParam)];
232 else if (msg==PBM_SETPOS)
234 [self setDoubleValue:(double)wParam];
235 [self stopAnimation:self];
237 else if (msg==PBM_DELTAPOS)
239 [self incrementBy:(double)wParam];
246 @implementation SWELL_ListViewCell
247 -(NSColor *)highlightColorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
249 if ([controlView isKindOfClass:[SWELL_ListView class]])
251 if (((SWELL_ListView *)controlView)->m_selColors) return nil;
253 else if ([controlView isKindOfClass:[SWELL_TreeView class]])
255 if (((SWELL_TreeView *)controlView)->m_selColors) return nil;
258 return [super highlightColorWithFrame:cellFrame inView:controlView];
260 - (NSRect)drawingRectForBounds:(NSRect)rect
262 const NSSize sz = [self cellSizeForBounds:rect];
263 rect = [super drawingRectForBounds:rect];
264 const int offs = (int) floor((rect.size.height - sz.height) * .5);
267 rect.origin.y += offs;
268 rect.size.height -= offs*2;
274 @implementation SWELL_StatusCell
275 -(id)initNewCell:(bool)always_indent
277 if ((self=[super initTextCell:@""]))
279 m_always_indent=always_indent;
284 -(void)setStatusImage:(NSImage *)img
288 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
292 const double fr_h = cellFrame.size.height;
293 const NSSize image_sz = [status size];
294 const double use_h = wdl_min(image_sz.height, fr_h);
295 const double yo = (fr_h-use_h)*.5;
297 if (use_h > cellFrame.size.width)
299 use_w = cellFrame.size.width;
308 [status drawInRect:NSMakeRect(cellFrame.origin.x + xo,cellFrame.origin.y + yo,use_w,use_h)
309 fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
311 if (m_always_indent || status)
313 cellFrame.origin.x += cellFrame.size.height + 2.0;
314 cellFrame.size.width -= cellFrame.size.height + 2.0;
316 [super drawWithFrame:cellFrame inView:controlView];
321 static HTREEITEM FindTreeItemByDataHold(const WDL_PtrList<HTREEITEM__> *list, SWELL_DataHold *srch)
323 for (int x = 0; x < list->GetSize(); x ++)
325 HTREEITEM item = list->Get(x);
326 if (item && item->m_dh == srch) return item;
328 for (int x = 0; x < list->GetSize(); x ++)
330 HTREEITEM item = list->Get(x);
331 if (item && item->m_children.GetSize())
333 item = FindTreeItemByDataHold(&item->m_children,srch);
334 if (item) return item;
340 @implementation SWELL_TreeView
341 STANDARD_CONTROL_NEEDSDISPLAY_IMPL("SysTreeView32")
345 if ((self = [super init]))
347 m_fakerightmouse=false;
348 m_items=new WDL_PtrList<HTREEITEM__>;
356 if (m_items) m_items->Empty(true);
360 [m_selColors release];
364 -(bool) findItem:(HTREEITEM)item parOut:(HTREEITEM__ **)par idxOut:(int *)idx
366 if (!m_items||!item) return false;
367 int x=m_items->Find((HTREEITEM__*)item);
374 for (x = 0; x < m_items->GetSize(); x++)
376 if (m_items->Get(x)->FindItem(item,par,idx)) return true;
382 -(NSInteger) outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
384 if (item == nil) return m_items ? m_items->GetSize() : 0;
385 return ((HTREEITEM__*)[item getValue])->m_children.GetSize();
388 - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
390 if (item==nil) return YES;
391 HTREEITEM__ *it=(HTREEITEM__ *)[item getValue];
393 return it && it->m_haschildren;
396 - (id)outlineView:(NSOutlineView *)outlineView
397 child:(NSInteger)index
400 HTREEITEM__ *row=item ? ((HTREEITEM__*)[item getValue])->m_children.Get(index) : m_items ? m_items->Get(index) : 0;
402 return (id)(row ? row->m_dh : NULL);
405 - (id)outlineView:(NSOutlineView *)outlineView
406 objectValueForTableColumn:(NSTableColumn *)tableColumn
409 if (!item) return @"";
410 HTREEITEM__ *it=(HTREEITEM__ *)[item getValue];
412 if (!it || !it->m_value) return @"";
414 NSString *str=(NSString *)SWELL_CStringToCFString(it->m_value);
416 return [str autorelease];
419 - (BOOL)outlineView:(NSOutlineView *)outlineView
420 writeItems:(NSArray *)items
421 toPasteboard:(NSPasteboard *)pasteboard
423 if (self->style & TVS_DISABLEDRAGDROP) return NO;
424 [pasteboard declareTypes:[NSArray arrayWithObject:@"swell_treeview"] owner:nil];
425 [pasteboard setString:@"" forType:@"swell_treeview"];
429 - (BOOL)outlineView:(NSOutlineView *)outlineView
430 acceptDrop:(id<NSDraggingInfo>)info
432 childIndex:(NSInteger)index
434 HWND par = GetParent((HWND)self);
435 if (par && GetCapture() == par)
439 ScreenToClient(par,&p);
440 SendMessage(par,WM_LBUTTONUP,0,MAKELPARAM(p.x,p.y));
446 - (BOOL)outlineView:(NSOutlineView *)outlineView
447 shouldExpandItem:(id)item
449 return NO; // optionally while dragging?
453 - (void)outlineView:(NSOutlineView *)outlineView
454 draggingSession:(NSDraggingSession *)session
455 endedAtPoint:(NSPoint)screenPoint
456 operation:(NSDragOperation)operation
458 [self unregisterDraggedTypes];
459 HWND par = GetParent((HWND)self);
460 if (par && GetCapture() == par)
462 // usually acceptDrop above will be the one that is called, but if the user ended up elsewhere
463 // this might, let the caller clean up capture
466 ScreenToClient(par,&p);
467 SendMessage(par,WM_LBUTTONUP,0,MAKELPARAM(p.x,p.y));
471 - (void)outlineView:(NSOutlineView *)outlineView
472 draggingSession:(NSDraggingSession *)session
473 willBeginAtPoint:(NSPoint)screenPoint
474 forItems:(NSArray *)draggedItems
476 if (self->style & TVS_DISABLEDRAGDROP) return;
477 HWND hwnd = (HWND)self, par = GetParent(hwnd);
480 HTREEITEM hit = NULL;
481 if (m_items && [draggedItems count] > 0)
483 id obj = [draggedItems objectAtIndex:0];
484 if ([obj isKindOfClass:[SWELL_DataHold class]])
485 hit = FindTreeItemByDataHold(m_items, (SWELL_DataHold *)obj);
490 memset(&tht,0,sizeof(tht));
491 GetCursorPos(&tht.pt);
492 ScreenToClient(hwnd, &tht.pt);
493 hit = TreeView_HitTest(hwnd, &tht);
496 HTREEITEM sel = TreeView_GetSelection(hwnd);
497 if (hit && hit != sel)
499 TreeView_SelectItem(hwnd,hit);
503 NMTREEVIEW nm={{hwnd,(UINT_PTR)[self tag],TVN_BEGINDRAG},};
504 nm.itemNew.hItem = sel;
505 nm.itemNew.lParam = sel ? sel->m_param : 0;
506 SendMessage(par,WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
507 if (GetCapture() == par)
508 [self registerForDraggedTypes:[NSArray arrayWithObject: @"swell_treeview"]];
512 - (NSDragOperation)outlineView:(NSOutlineView *)outlineView
513 validateDrop:(id<NSDraggingInfo>)info
514 proposedItem:(id)item
515 proposedChildIndex:(NSInteger)index
517 HWND hwnd=(HWND)self, par = GetParent(hwnd);
518 if (par && GetCapture()==par)
523 memset(&tht,0,sizeof(tht));
526 ScreenToClient(par,&p);
527 LRESULT move_res = SendMessage(par,WM_MOUSEMOVE,0,MAKELPARAM(p.x,p.y));
528 if (move_res == (LRESULT)-1) return NSDragOperationNone;
529 if (move_res == (LRESULT)-2) // move to end
531 HTREEITEM par_item = NULL;
532 HTREEITEM li = self->m_items ? self->m_items->Get(self->m_items->GetSize()-1) : NULL;
533 while (li && li->m_children.GetSize())
536 li = li->m_children.Get(li->m_children.GetSize()-1);
538 if (par_item && par_item->m_children.GetSize()) [self setDropItem:par_item->m_dh dropChildIndex:par_item->m_children.GetSize()];
540 else if (move_res >= 65536)
542 HTREEITEM paritem = NULL;
544 // it is safe (but time consuming!) to call findItem: on a possibly-junk pointer
545 if ([self findItem:(HTREEITEM)(INT_PTR)move_res parOut:&paritem idxOut:&idx] && paritem)
546 [self setDropItem:paritem->m_dh dropChildIndex:idx];
548 return NSDragOperationPrivate;
550 return NSDragOperationNone;
554 -(void)mouseDown:(NSEvent *)theEvent
556 if (([theEvent modifierFlags] & NSControlKeyMask) && IsRightClickEmulateEnabled())
563 NMCLICK nmlv={{(HWND)self,(UINT_PTR)[self tag], NM_CLICK},};
564 SendMessage((HWND)[self target],WM_NOTIFY,nmlv.hdr.idFrom,(LPARAM)&nmlv);
567 [super mouseDown:theEvent];
571 -(void)mouseDragged:(NSEvent *)theEvent
575 -(void)mouseUp:(NSEvent *)theEvent
577 if (m_fakerightmouse||([theEvent modifierFlags] & NSControlKeyMask)) [self rightMouseUp:theEvent];
578 else [super mouseUp:theEvent];
580 - (void)rightMouseUp:(NSEvent *)theEvent
582 bool wantContext=true;
584 NMCLICK nmlv={{(HWND)self,(UINT_PTR)[self tag], NM_RCLICK},};
585 if (SendMessage((HWND)[self target],WM_NOTIFY,nmlv.hdr.idFrom,(LPARAM)&nmlv)) wantContext=false;
591 SendMessage((HWND)[self target],WM_CONTEXTMENU,(WPARAM)self,MAKELONG(p.x&0xffff,p.y));
597 - (void)highlightSelectionInClipRect:(NSRect)theClipRect
601 int a = GetFocus() == (HWND)self ? 0 : 2;
602 if ([m_selColors count] >= a)
604 NSColor *c=[m_selColors objectAtIndex:a];
607 // calculate rect of selected items, combine with theClipRect, and fill these areas with our background (phew!)
609 NSInteger x = [self selectedRow];
612 NSRect r = [self rectOfRow:x];
613 r = NSIntersectionRect(r,theClipRect);
614 if (r.size.height>0 && r.size.width>0)
624 return [super highlightSelectionInClipRect:theClipRect];
636 @implementation SWELL_ListView
637 STANDARD_CONTROL_NEEDSDISPLAY_IMPL( m_lbMode ? "SysListView32_LB" : "SysListView32" )
639 -(BOOL)accessibilityPerformShowMenu
641 HWND par = (HWND)[self target];
644 int row = (int)ListView_GetNextItem((HWND)self,-1,LVNI_FOCUSED);
646 NMLISTVIEW nmlv={{(HWND)self,(UINT_PTR)[self tag], NM_RCLICK}, row, col, 0, 0, 0, };
647 SendMessage(par,WM_NOTIFY,nmlv.hdr.idFrom,(LPARAM)&nmlv);
653 -(LONG)getSwellStyle { return style; }
655 -(void)setSwellStyle:(LONG)st
657 bool hdrchg= ((style&LVS_NOCOLUMNHEADER) != (st&LVS_NOCOLUMNHEADER));
659 if ((style&LVS_REPORT) && hdrchg)
661 // todo some crap with NSTableView::setHeaderView, but it's complicated
667 if ((self = [super init]))
669 m_subitem_images = false;
673 m_status_imagelist_type=-1;
674 m_status_imagelist=0;
675 m_leftmousemovecnt=0;
676 m_fakerightmouse=false;
679 m_last_shift_clicked_item = m_last_plainly_clicked_item=-1;
682 m_start_item_clickmode=0; // 0=clicked item, 1=clicked image, &2=sent drag message, &4=quickclick mode
683 m_cols = new WDL_PtrList<NSTableColumn>;
684 m_items=new WDL_PtrList<SWELL_ListView_Row>;
690 if (m_items) m_items->Empty(true);
696 [m_selColors release];
700 -(int)getColumnPos:(int)idx // get current position of column that was originally at idx
705 NSTableColumn* col=m_cols->Get(idx);
708 NSArray* arr=[self tableColumns];
711 pos=(int)[arr indexOfObject:col];
718 - (void)highlightSelectionInClipRect:(NSRect)theClipRect
722 int a = GetFocus() == (HWND)self ? 0 : 2;
723 if ([m_selColors count] >= a)
725 NSColor *c=[m_selColors objectAtIndex:a];
728 // calculate rect of selected items, combine with theClipRect, and fill these areas with our background (phew!)
729 bool needfillset=true;
730 NSInteger x = [self rowAtPoint:NSMakePoint(0,theClipRect.origin.y)];
732 const NSInteger n = [self numberOfRows];
735 NSRect r = [self rectOfRow:x];
736 if (r.origin.y >= theClipRect.origin.y + theClipRect.size.height) break;
738 if ([self isRowSelected:x])
740 r = NSIntersectionRect(r,theClipRect);
741 if (r.size.height>0 && r.size.width>0)
743 if (needfillset) { needfillset=false; [c setFill]; }
752 return [super highlightSelectionInClipRect:theClipRect];
754 -(int)getColumnIdx:(int)pos // get original index of column that is currently at position
757 NSArray* arr=[self tableColumns];
758 if (arr && pos>=0 && pos < [arr count])
760 NSTableColumn* col=[arr objectAtIndex:pos];
763 idx=m_cols->Find(col);
769 -(NSInteger)columnAtPoint:(NSPoint)pt
771 int pos=(int)[super columnAtPoint:pt];
772 return (NSInteger) [self getColumnIdx:pos];
776 - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
778 return (!m_lbMode && (style & LVS_OWNERDATA)) ? ownermode_cnt : (m_items ? m_items->GetSize():0);
781 - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
786 if (!m_lbMode && (style & LVS_OWNERDATA))
788 HWND tgt=(HWND)[self target];
791 NMLVDISPINFO nm={{(HWND)self, (UINT_PTR)[self tag], LVN_GETDISPINFO}};
792 nm.item.mask=LVIF_TEXT;
793 if (m_status_imagelist_type==LVSIL_STATE) nm.item.mask |= LVIF_STATE;
794 else if (m_status_imagelist_type == LVSIL_SMALL) nm.item.mask |= LVIF_IMAGE;
796 nm.item.iItem=(int)rowIndex;
797 nm.item.iSubItem=m_cols->Find(aTableColumn);
799 nm.item.cchTextMax=sizeof(buf)-1;
801 SendMessage(tgt,WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
803 if (m_status_imagelist_type == LVSIL_STATE) image_idx=(nm.item.state>>16)&0xff;
804 else if (m_status_imagelist_type == LVSIL_SMALL) image_idx = nm.item.iImage + 1;
805 str=(NSString *)SWELL_CStringToCFString(nm.item.pszText);
810 SWELL_ListView_Row *r=0;
811 if (m_items && m_cols && (r=m_items->Get(rowIndex)))
813 int col_idx = m_cols->Find(aTableColumn);
814 p=r->get_col_txt(col_idx);
815 if (m_status_imagelist_type == LVSIL_STATE || m_status_imagelist_type == LVSIL_SMALL)
817 if (col_idx==0 || m_subitem_images)
818 image_idx=r->get_img_idx(col_idx);
822 str=(NSString *)SWELL_CStringToCFString(p);
824 if (style & LBS_OWNERDRAWFIXED)
826 SWELL_ODListViewCell *cell=[aTableColumn dataCell];
827 if ([cell isKindOfClass:[SWELL_ODListViewCell class]]) [cell setItemIdx:(int)rowIndex];
831 if (!m_lbMode && m_status_imagelist)
833 SWELL_StatusCell *cell=(SWELL_StatusCell*)[aTableColumn dataCell];
834 if ([cell isKindOfClass:[SWELL_StatusCell class]])
836 HICON icon=m_status_imagelist->Get(image_idx-1);
838 if (icon) img=(NSImage *)GetNSImageFromHICON(icon);
839 [cell setStatusImage:img];
843 return [str autorelease];
848 -(void)mouseDown:(NSEvent *)theEvent
850 if (([theEvent modifierFlags] & NSControlKeyMask) && IsRightClickEmulateEnabled())
858 if ([theEvent clickCount]>1 && SWELL_NeedModernListViewHacks())
860 [super mouseDown:theEvent];
863 m_leftmousemovecnt=0;
866 NSPoint pt=[theEvent locationInWindow];
867 pt=[self convertPoint:pt fromView:nil];
868 m_start_item=(int)[self rowAtPoint:pt];
869 m_start_subitem=(int)[self columnAtPoint:pt];
873 m_start_item_clickmode=0;
874 if (m_start_item >=0 && (m_fastClickMask&(1<<m_start_subitem)))
876 int msg = [theEvent clickCount] > 1 ? NM_DBLCLK : NM_CLICK;
877 NMLISTVIEW nmlv={{(HWND)self,(UINT_PTR)[self tag], msg}, m_start_item, m_start_subitem, 0, 0, 0, {NSPOINT_TO_INTS(pt)}, };
878 SWELL_ListView_Row *row=m_items->Get(nmlv.iItem);
880 nmlv.lParam = row->m_param;
881 SendMessage((HWND)[self target],WM_NOTIFY,nmlv.hdr.idFrom,(LPARAM)&nmlv);
882 m_start_item_clickmode=4;
886 if (m_start_item>=0 && m_status_imagelist && LVSIL_STATE == m_status_imagelist_type && pt.x <= [self rowHeight]) // in left area
888 m_start_item_clickmode=1;
894 -(void)mouseDragged:(NSEvent *)theEvent
896 if (++m_leftmousemovecnt==4)
898 if (m_start_item>=0 && !(m_start_item_clickmode&3))
902 // if m_start_item isnt selected, change selection to it now
903 if (!(m_start_item_clickmode&4) && ![self isRowSelected:m_start_item])
905 [self selectRowIndexes:[NSIndexSet indexSetWithIndex:m_start_item] byExtendingSelection:!!(GetAsyncKeyState(VK_CONTROL)&0x8000)];
907 NMLISTVIEW hdr={{(HWND)self,(UINT_PTR)[self tag],LVN_BEGINDRAG},m_start_item,m_start_subitem,0,};
908 SendMessage((HWND)[self target],WM_NOTIFY,hdr.hdr.idFrom, (LPARAM) &hdr);
909 m_start_item_clickmode |= 2;
913 else if (m_leftmousemovecnt > 4 && !(m_start_item_clickmode&1))
915 HWND tgt=(HWND)[self target];
918 ScreenToClient(tgt,&p);
920 SendMessage(tgt,WM_MOUSEMOVE,0,MAKELONG(p.x&0xffff,p.y));
924 -(void)mouseUp:(NSEvent *)theEvent
926 if ((m_fakerightmouse||([theEvent modifierFlags] & NSControlKeyMask)) && IsRightClickEmulateEnabled())
928 [self rightMouseUp:theEvent];
932 if ([theEvent clickCount]>1 && SWELL_NeedModernListViewHacks())
934 [super mouseUp:theEvent];
937 if (!(m_start_item_clickmode&1))
939 if (m_leftmousemovecnt>=0 && m_leftmousemovecnt<4 && !(m_start_item_clickmode&4))
941 const bool msel = [self allowsMultipleSelection];
942 if (m_lbMode && !msel) // listboxes --- allow clicking to reset the selection
944 [self deselectAll:self];
947 if (SWELL_NeedModernListViewHacks())
951 NSMutableIndexSet *m = [[NSMutableIndexSet alloc] init];
952 if (GetAsyncKeyState(VK_CONTROL)&0x8000)
954 [m addIndexes:[self selectedRowIndexes]];
955 if ([m containsIndex:m_start_item]) [m removeIndex:m_start_item];
958 if (!msel) [m removeAllIndexes];
959 [m addIndex:m_start_item];
961 m_last_plainly_clicked_item = m_start_item;
963 else if (msel && (GetAsyncKeyState(VK_SHIFT)&0x8000))
965 [m addIndexes:[self selectedRowIndexes]];
966 const int n = ListView_GetItemCount((HWND)self);
967 if (m_last_plainly_clicked_item<0 || m_last_plainly_clicked_item>=n)
968 m_last_plainly_clicked_item=m_start_item;
970 if (m_last_shift_clicked_item>=0 &&
971 m_last_shift_clicked_item<n &&
972 m_last_plainly_clicked_item != m_last_shift_clicked_item)
974 int a1 = m_last_shift_clicked_item;
975 int a2 = m_last_plainly_clicked_item;
976 if (a2<a1) { int tmp=a1; a1=a2; a2=tmp; }
977 [m removeIndexesInRange:NSMakeRange(a1,a2-a1 + 1)];
980 int a1 = m_start_item;
981 int a2 = m_last_plainly_clicked_item;
982 if (a2<a1) { int tmp=a1; a1=a2; a2=tmp; }
983 [m addIndexesInRange:NSMakeRange(a1,a2-a1 + 1)];
985 m_last_shift_clicked_item = m_start_item;
989 m_last_plainly_clicked_item = m_start_item;
990 [m addIndex:m_start_item];
993 [self selectRowIndexes:m byExtendingSelection:NO];
998 else [self deselectAll:self];
1002 [super mouseDown:theEvent];
1003 [super mouseUp:theEvent];
1006 else if (m_leftmousemovecnt>=4)
1008 HWND tgt=(HWND)[self target];
1011 ScreenToClient(tgt,&p);
1012 SendMessage(tgt,WM_LBUTTONUP,0,MAKELONG(p.x&0xffff,p.y));
1017 if (!m_lbMode && !(m_start_item_clickmode&(2|4)))
1019 NSPoint pt=[theEvent locationInWindow];
1020 pt=[self convertPoint:pt fromView:nil];
1021 int col = (int)[self columnAtPoint:pt];
1022 NMLISTVIEW nmlv={{(HWND)self,(UINT_PTR)[self tag], NM_CLICK}, (int)[self rowAtPoint:pt], col, 0, 0, 0, {NSPOINT_TO_INTS(pt)}, };
1023 SWELL_ListView_Row *row=m_items->Get(nmlv.iItem);
1024 if (row) nmlv.lParam = row->m_param;
1025 SendMessage((HWND)[self target],WM_NOTIFY,nmlv.hdr.idFrom,(LPARAM)&nmlv);
1029 - (void)rightMouseUp:(NSEvent *)theEvent
1031 bool wantContext=true;
1035 NSPoint pt=[theEvent locationInWindow];
1036 pt=[self convertPoint:pt fromView:nil];
1038 // note, windows selects on right mousedown
1039 NSInteger row =[self rowAtPoint:pt];
1040 if (row >= 0 && ![self isRowSelected:row])
1042 NSIndexSet* rows=[NSIndexSet indexSetWithIndex:row];
1043 [self deselectAll:self];
1044 [self selectRowIndexes:rows byExtendingSelection:NO];
1047 NMLISTVIEW nmlv={{(HWND)self,(UINT_PTR)[self tag], NM_RCLICK}, (int)row, (int)[self columnAtPoint:pt], 0, 0, 0, {NSPOINT_TO_INTS(pt)}, };
1048 if (SendMessage((HWND)[self target],WM_NOTIFY,nmlv.hdr.idFrom,(LPARAM)&nmlv)) wantContext=false;
1054 SendMessage((HWND)[self target],WM_CONTEXTMENU,(WPARAM)self,MAKELONG(p.x&0xffff,p.y));
1059 -(LRESULT)onSwellMessage:(UINT)msg p1:(WPARAM)wParam p2:(LPARAM)lParam
1061 HWND hwnd=(HWND)self;
1064 case LB_RESETCONTENT:
1068 m_items->Empty(true);
1073 case LB_INSERTSTRING:
1075 int cnt=ListView_GetItemCount(hwnd);
1076 if (msg == LB_ADDSTRING && (style & LBS_SORT))
1078 SWELL_ListView *tv=(SWELL_ListView*)hwnd;
1079 if (tv->m_lbMode && tv->m_items)
1081 cnt=ptrlist_bsearch_mod((char *)lParam,tv->m_items,_listviewrowSearchFunc,NULL);
1084 if (msg==LB_ADDSTRING) wParam=cnt;
1085 else if (wParam > cnt) wParam=cnt;
1086 LVITEM lvi={LVIF_TEXT,(int)wParam,0,0,0,(char *)lParam};
1087 ListView_InsertItem(hwnd,&lvi);
1090 case LB_GETCOUNT: return ListView_GetItemCount(hwnd);
1092 ListView_SetItemState(hwnd, (int)lParam,wParam ? LVIS_SELECTED : 0,LVIS_SELECTED);
1097 SWELL_ListView_Row *row=self->m_items ? self->m_items->Get(wParam) : NULL;
1098 *(char *)lParam = 0;
1100 if (row && (p=row->get_col_txt(0)))
1102 strcpy((char *)lParam, p);
1103 return (LRESULT)strlen(p);
1109 SWELL_ListView_Row *row=self->m_items ? self->m_items->Get(wParam) : NULL;
1112 const char *p=row->get_col_txt(0);
1113 return p?strlen(p):0;
1117 case LB_FINDSTRINGEXACT:
1120 int x = (int) wParam + 1;
1122 const int n = self->m_items ? self->m_items->GetSize() : 0;
1123 for (int i = 0; i < n; i ++)
1125 SWELL_ListView_Row *row=self->m_items->Get(x);
1128 const char *p = row->get_col_txt(0);
1129 if (p && !stricmp(p,(const char *)lParam)) return x;
1136 return !!(ListView_GetItemState(hwnd,(int)wParam,LVIS_SELECTED)&LVIS_SELECTED);
1138 return [self selectedRow];
1141 if (wParam<ListView_GetItemCount(hwnd))
1143 [self selectRowIndexes:[NSIndexSet indexSetWithIndex:wParam] byExtendingSelection:NO];
1144 [self scrollRowToVisible:wParam];
1148 [self deselectAll:self];
1152 case LB_GETITEMDATA:
1156 SWELL_ListView_Row *row=m_items->Get(wParam);
1157 if (row) return row->m_param;
1161 case LB_SETITEMDATA:
1165 SWELL_ListView_Row *row=m_items->Get(wParam);
1166 if (row) row->m_param=lParam;
1170 case LB_GETSELCOUNT:
1171 return [[self selectedRowIndexes] count];
1172 case LB_DELETESTRING:
1173 ListView_DeleteItem((HWND)self, (int)wParam);
1178 if (SWELL_GetOSXVersion() >= 0x1070 && [self respondsToSelector:@selector(endUpdates)])
1181 // workaround for a weird 10.14.6 bug
1182 // if the caller calls this, then invalidaterect()s the parent window right away,
1183 // appkit will (sometimes) throw an exception unlocking focus on the NSScrollView.
1184 // invalidating our window directly seems to prevent this.
1185 [self setNeedsDisplay:YES];
1190 if (SWELL_GetOSXVersion() >= 0x1070 && [self respondsToSelector:@selector(beginUpdates)])
1191 [self beginUpdates];
1199 -(int)getSwellNotificationMode
1203 -(void)setSwellNotificationMode:(int)lbMode
1208 -(void)onSwellCommand:(int)cmd
1215 @implementation SWELL_ImageButtonCell
1216 - (NSRect)drawTitle:(NSAttributedString *)title withFrame:(NSRect)frame inView:(NSView *)controlView
1218 return NSMakeRect(0,0,0,0);
1222 @implementation SWELL_ODButtonCell
1223 - (BOOL)isTransparent
1232 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
1234 NSView *ctl=[self controlView];
1235 if (!ctl) { [super drawWithFrame:cellFrame inView:controlView]; return; }
1237 HDC hdc=SWELL_CreateGfxContext([NSGraphicsContext currentContext]);
1240 HWND notWnd = GetParent((HWND)ctl);
1241 DRAWITEMSTRUCT dis={ODT_BUTTON,(UINT)[ctl tag],0,0,0,(HWND)ctl,hdc,{0,},0};
1242 NSRECT_TO_RECT(&dis.rcItem,cellFrame);
1243 SendMessage(notWnd,WM_DRAWITEM,dis.CtlID,(LPARAM)&dis);
1245 SWELL_DeleteGfxContext(hdc);
1251 @implementation SWELL_ODListViewCell
1252 -(void)setOwnerControl:(SWELL_ListView *)t { m_ownctl=t; m_lastidx=0; }
1253 -(void)setItemIdx:(int)idx
1257 - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
1259 if (!m_ownctl) { [super drawInteriorWithFrame:cellFrame inView:controlView]; return; }
1261 int itemidx=m_lastidx;
1263 SWELL_ListView_Row *row=m_ownctl->m_items->Get(itemidx);
1264 if (row) itemData=row->m_param;
1266 HDC hdc=SWELL_CreateGfxContext([NSGraphicsContext currentContext]);
1269 HWND notWnd = GetParent((HWND)m_ownctl);
1270 DRAWITEMSTRUCT dis={ODT_LISTBOX,(UINT)[m_ownctl tag],(UINT)itemidx,0,0,(HWND)m_ownctl,hdc,{0,},(DWORD_PTR)itemData};
1271 NSRECT_TO_RECT(&dis.rcItem,cellFrame);
1272 SendMessage(notWnd,WM_DRAWITEM,dis.CtlID,(LPARAM)&dis);
1274 SWELL_DeleteGfxContext(hdc);
1285 HWND GetDlgItem(HWND hwnd, int idx)
1287 if (WDL_NOT_NORMALLY(!hwnd)) return 0;
1291 if ([pid isKindOfClass:[NSWindow class]]) v=[((NSWindow *)pid) contentView];
1292 else if ([pid isKindOfClass:[NSView class]]) v=(NSView *)pid;
1294 if (!idx || !v) return (HWND)v;
1298 NSArray *ar = [v subviews];
1299 const NSInteger n=[ar count];
1300 for (NSInteger x=0;x<n;x++)
1302 NSView *sv = [ar objectAtIndex:x];
1305 if ([sv respondsToSelector:@selector(tag)] && [sv tag] == idx) return (HWND)sv;
1307 if (sv && [sv isKindOfClass:[NSScrollView class]])
1309 sv=[(NSScrollView *)sv documentView];
1310 if (sv && [sv respondsToSelector:@selector(tag)] && [sv tag] == idx) return (HWND)sv;
1312 if (sv && [sv isKindOfClass:[NSClipView class]])
1314 sv = [(NSClipView *)sv documentView];
1315 if (sv && [sv respondsToSelector:@selector(tag)] && [sv tag] == idx) return (HWND)sv;
1319 // we might want to enable this for max compat with old code, but hopefully not: return [v viewWithTag:idx];
1325 LONG_PTR SetWindowLong(HWND hwnd, int idx, LONG_PTR val)
1327 if (WDL_NOT_NORMALLY(!hwnd)) return 0;
1331 if (idx==GWL_EXSTYLE && [pid respondsToSelector:@selector(swellSetExtendedStyle:)])
1333 LONG ret=(LONG) [(SWELL_hwndChild*)pid swellGetExtendedStyle];
1334 [(SWELL_hwndChild*)pid swellSetExtendedStyle:(LONG)val];
1337 if (idx==GWL_USERDATA && [pid respondsToSelector:@selector(setSwellUserData:)])
1339 LONG_PTR ret=(LONG_PTR)[(SWELL_hwndChild*)pid getSwellUserData];
1340 [(SWELL_hwndChild*)pid setSwellUserData:(LONG_PTR)val];
1344 if (idx==GWL_ID && [pid respondsToSelector:@selector(tag)] && [pid respondsToSelector:@selector(setTag:)])
1346 int ret= (int) [pid tag];
1347 [pid setTag:(int)val];
1348 return (LONG_PTR)ret;
1351 if (idx==GWL_WNDPROC && [pid respondsToSelector:@selector(setSwellWindowProc:)])
1353 WNDPROC ov=(WNDPROC)[pid getSwellWindowProc];
1354 [pid setSwellWindowProc:(WNDPROC)val];
1355 return (LONG_PTR)ov;
1357 if (idx==DWL_DLGPROC && [pid respondsToSelector:@selector(setSwellDialogProc:)])
1359 DLGPROC ov=(DLGPROC)[pid getSwellDialogProc];
1360 [pid setSwellDialogProc:(DLGPROC)val];
1361 return (LONG_PTR)ov;
1366 if ([pid respondsToSelector:@selector(setSwellStyle:)])
1368 LONG ov=[pid getSwellStyle];
1369 [pid setSwellStyle:(LONG)(val & ~WS_VISIBLE)];
1372 else if ([pid isKindOfClass:[NSButton class]])
1374 int ret=(int)GetWindowLong(hwnd,idx);
1376 if ((val&0xf) == BS_AUTO3STATE)
1378 [pid setButtonType:NSSwitchButton];
1379 [pid setAllowsMixedState:YES];
1380 if ([pid isKindOfClass:[SWELL_Button class]]) [pid swellSetRadioFlags:0];
1382 else if ((val & 0xf) == BS_AUTOCHECKBOX)
1384 [pid setButtonType:NSSwitchButton];
1385 [pid setAllowsMixedState:NO];
1386 if ([pid isKindOfClass:[SWELL_Button class]]) [pid swellSetRadioFlags:0];
1388 else if ((val & 0xf) == BS_AUTORADIOBUTTON)
1390 [pid setButtonType:NSRadioButton];
1391 if ([pid isKindOfClass:[SWELL_Button class]]) [pid swellSetRadioFlags:(val&WS_GROUP)?3:1];
1398 if ([[pid window] contentView] == pid)
1400 NSView *tv=(NSView *)pid;
1401 NSWindow *oldw = [tv window];
1402 NSUInteger smask = [oldw styleMask];
1404 if (smask & NSTitledWindowMask)
1407 if (smask & NSResizableWindowMask) mf|=WS_THICKFRAME;
1409 if (mf != (val&(WS_CAPTION|WS_THICKFRAME)))
1411 BOOL dovis = IsWindowVisible((HWND)oldw);
1412 NSWindow *oldpar = [oldw parentWindow];
1413 char oldtitle[2048];
1415 GetWindowText(hwnd,oldtitle,sizeof(oldtitle));
1416 NSRect fr=[oldw frame];
1418 if ([oldw respondsToSelector:@selector(swellGetOwner)]) oldOwner=(HWND)[(SWELL_ModelessWindow*)oldw swellGetOwner];
1419 NSInteger oldlevel = [oldw level];
1423 SWELL_hwndChild *tempview = [[SWELL_hwndChild alloc] initChild:nil Parent:(NSView *)oldw dlgProc:nil Param:0];
1426 unsigned int mask=0;
1428 if (val & WS_CAPTION)
1430 mask|=NSTitledWindowMask;
1431 if (val & WS_THICKFRAME)
1432 mask|=NSMiniaturizableWindowMask|NSClosableWindowMask|NSResizableWindowMask;
1435 HWND SWELL_CreateModelessFrameForWindow(HWND childW, HWND ownerW, unsigned int);
1436 HWND bla=SWELL_CreateModelessFrameForWindow((HWND)tv,(HWND)oldOwner,mask);
1441 // move owned windows over
1442 if ([oldw respondsToSelector:@selector(swellGetOwnerWindowHead)])
1444 void **p=(void **)[(SWELL_ModelessWindow*)oldw swellGetOwnerWindowHead];
1445 if (p && [(id)bla respondsToSelector:@selector(swellGetOwnerWindowHead)])
1447 void **p2=(void **)[(SWELL_ModelessWindow*)bla swellGetOwnerWindowHead];
1452 OwnedWindowListRec *rec = (OwnedWindowListRec *) *p2;
1455 if (rec->hwnd && [rec->hwnd respondsToSelector:@selector(swellSetOwner:)])
1456 [(SWELL_ModelessWindow *)rec->hwnd swellSetOwner:(id)bla];
1462 // move all child and owned windows over to new window
1463 NSArray *ar=[oldw childWindows];
1467 for (x = 0; x < [ar count]; x ++)
1469 NSWindow *cw=[ar objectAtIndex:x];
1473 [oldw removeChildWindow:cw];
1474 [(NSWindow *)bla addChildWindow:cw ordered:NSWindowAbove];
1482 if (oldpar) [oldpar addChildWindow:(NSWindow *)bla ordered:NSWindowAbove];
1483 if (oldtitle[0]) SetWindowText(hwnd,oldtitle);
1485 [(NSWindow *)bla setFrame:fr display:dovis];
1486 [(NSWindow *)bla setLevel:oldlevel];
1487 if (dovis) ShowWindow(bla,SW_SHOW);
1489 DestroyWindow((HWND)oldw);
1493 [oldw setContentView:tv];
1503 if (idx == GWL_HWNDPARENT)
1505 NSWindow *window = [pid window];
1506 if (![window respondsToSelector:@selector(swellGetOwner)]) return 0;
1508 NSWindow *new_owner = val && [(id)(INT_PTR)val isKindOfClass:[NSView class]] ? [(NSView *)(INT_PTR)val window] : NULL;
1509 if (new_owner && ![new_owner respondsToSelector:@selector(swellAddOwnedWindow:)]) new_owner=NULL;
1511 NSWindow *old_owner = [(SWELL_ModelessWindow *)window swellGetOwner];
1512 if (old_owner != new_owner)
1514 if (old_owner) [(SWELL_ModelessWindow*)old_owner swellRemoveOwnedWindow:window];
1515 [(SWELL_ModelessWindow *)window swellSetOwner:nil];
1516 if (new_owner) [(SWELL_ModelessWindow *)new_owner swellAddOwnedWindow:window];
1518 return (old_owner ? (LONG_PTR)[old_owner contentView] : 0);
1521 if ([pid respondsToSelector:@selector(setSwellExtraData:value:)])
1524 if ([pid respondsToSelector:@selector(getSwellExtraData:)]) ov=(LONG_PTR)[pid getSwellExtraData:idx];
1526 [pid setSwellExtraData:idx value:val];
1535 LONG_PTR GetWindowLong(HWND hwnd, int idx)
1537 if (WDL_NOT_NORMALLY(!hwnd)) return 0;
1542 if (idx==GWL_EXSTYLE && [pid respondsToSelector:@selector(swellGetExtendedStyle)])
1544 return (LONG_PTR)[pid swellGetExtendedStyle];
1547 if (idx==GWL_USERDATA && [pid respondsToSelector:@selector(getSwellUserData)])
1549 return (LONG_PTR)[pid getSwellUserData];
1551 if (idx==GWL_USERDATA && [pid isKindOfClass:[NSText class]])
1553 NSView *par = [pid superview];
1556 if (![par isKindOfClass:[SWELL_TextField class]])
1557 par = [par superview];
1558 if ([par isKindOfClass:[SWELL_TextField class]])
1559 return [(SWELL_TextField*)par getSwellUserData];
1565 if (idx==GWL_ID && [pid respondsToSelector:@selector(tag)])
1569 if (idx==GWL_WNDPROC && [pid respondsToSelector:@selector(getSwellWindowProc)])
1571 return (LONG_PTR)[pid getSwellWindowProc];
1573 if (idx==DWL_DLGPROC && [pid respondsToSelector:@selector(getSwellDialogProc)])
1575 return (LONG_PTR)[pid getSwellDialogProc];
1580 if (![pid isHidden]) ret |= WS_VISIBLE;
1581 if ([pid respondsToSelector:@selector(getSwellStyle)])
1583 return (LONG_PTR)(([pid getSwellStyle]&~WS_VISIBLE) | ret);
1586 if ([pid isKindOfClass:[NSButton class]])
1589 if ([pid isKindOfClass:[NSPopUpButton class]]) ret |= CBS_DROPDOWNLIST;
1590 else if ([pid allowsMixedState]) ret |= BS_AUTO3STATE;
1591 else if ([pid isKindOfClass:[SWELL_Button class]] && (tmp = (int)[pid swellGetRadioFlags]))
1595 ret |= BS_AUTORADIOBUTTON;
1596 if (tmp&2) ret|=WS_GROUP;
1599 else ret |= BS_AUTOCHECKBOX;
1602 if ([pid isKindOfClass:[NSView class]])
1604 if ([[pid window] contentView] != pid) ret |= WS_CHILDWINDOW;
1607 NSUInteger smask =[[pid window] styleMask];
1608 if (smask & NSTitledWindowMask)
1611 if (smask & NSResizableWindowMask) ret|=WS_THICKFRAME;
1618 if (idx == GWL_HWNDPARENT)
1620 NSWindow *window = [pid window];
1621 if (![window respondsToSelector:@selector(swellGetOwner)]) return 0;
1622 NSWindow *old_owner = [(SWELL_ModelessWindow *)window swellGetOwner];
1623 return (old_owner ? (LONG_PTR)[old_owner contentView] : 0);
1626 if ([pid respondsToSelector:@selector(getSwellExtraData:)])
1628 return (LONG_PTR)[pid getSwellExtraData:idx];
1635 static bool IsWindowImpl(NSView *ch, NSView *par)
1637 if (!par || ![par isKindOfClass:[NSView class]]) return false;
1639 NSArray *ar = [par subviews];
1640 if (!ar) return false;
1642 NSInteger x,n=[ar count];
1644 if ([ar objectAtIndex:x] == ch)
1651 if (IsWindowImpl(ch,[ar objectAtIndex:x]))
1660 bool IsWindow(HWND hwnd)
1662 if (!hwnd) return false;
1663 // this is very costly, but required
1666 NSArray *ch=[NSApp windows];
1668 NSInteger x,n=[ch count];
1672 NSWindow *w = [ch objectAtIndex:x];
1673 if (w == (NSWindow *)hwnd || [w contentView] == (NSView *)hwnd)
1679 @catch (NSException *ex) {
1687 NSWindow *w = [ch objectAtIndex:x];
1689 // only validate children of our windows (maybe an option for this?)
1690 ([w isKindOfClass:[SWELL_ModelessWindow class]] || [w isKindOfClass:[SWELL_ModalDialog class]]) &&
1691 IsWindowImpl((NSView*)hwnd,[w contentView]))
1697 @catch (NSException *ex) {
1708 bool IsWindowVisible(HWND hwnd)
1710 if (!hwnd) return false;
1714 if ([turd isKindOfClass:[NSView class]])
1716 NSWindow *w = [turd window];
1717 if (w && ![w isVisible]) return false;
1719 return ![turd isHiddenOrHasHiddenAncestor];
1721 if ([turd isKindOfClass:[NSWindow class]])
1723 return !![turd isVisible];
1730 bool IsWindowEnabled(HWND hwnd)
1732 if (WDL_NOT_NORMALLY(!hwnd)) return false;
1739 if ([view isKindOfClass:[NSWindow class]]) view = [view contentView];
1741 rv = view && [view respondsToSelector:@selector(isEnabled)] && [view isEnabled];
1751 static void *__GetNSImageFromHICON(HICON ico) // local copy to not be link dependent on swell-gdi.mm
1753 HGDIOBJ__ *i = (HGDIOBJ__ *)ico;
1754 if (!i || i->type != TYPE_BITMAP) return 0;
1755 return i->bitmapptr;
1759 @implementation SWELL_Button : NSButton
1761 STANDARD_CONTROL_NEEDSDISPLAY_IMPL("Button")
1764 self = [super init];
1768 m_radioflags=0; // =4096 if not a checkbox at all
1772 -(int)swellGetRadioFlags { return m_radioflags; }
1773 -(void)swellSetRadioFlags:(int)f { m_radioflags=f; }
1774 -(LONG_PTR)getSwellUserData { return m_userdata; }
1775 -(void)setSwellUserData:(LONG_PTR)val { m_userdata=val; }
1777 -(void)setSwellGDIImage:(void *)par
1779 m_swellGDIimage=par;
1781 -(void *)getSwellGDIImage
1783 return m_swellGDIimage;
1789 NSFont *SWELL_GetNSFont(HGDIOBJ__ *obj);
1791 LRESULT SendMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1793 if (WDL_NOT_NORMALLY(!hwnd)) return 0;
1797 if ([obj respondsToSelector:@selector(onSwellMessage:p1:p2:)])
1799 return (LRESULT) [obj onSwellMessage:msg p1:wParam p2:lParam];
1803 if (msg == BM_GETCHECK && [obj isKindOfClass:[NSButton class]])
1805 NSInteger a=[(NSButton*)obj state];
1806 if (a==NSMixedState) return BST_INDETERMINATE;
1807 return a!=NSOffState;
1809 if (msg == BM_SETCHECK && [obj isKindOfClass:[NSButton class]])
1811 [(NSButton*)obj setState:(wParam&BST_INDETERMINATE)?NSMixedState:((wParam&BST_CHECKED)?NSOnState:NSOffState)];
1814 if ((msg==BM_GETIMAGE || msg == BM_SETIMAGE) && [obj isKindOfClass:[SWELL_Button class]])
1816 if (wParam != IMAGE_BITMAP && wParam != IMAGE_ICON) return 0; // ignore unknown types
1817 LONG_PTR ret=(LONG_PTR) (void *)[obj getSwellGDIImage];
1818 if (msg==BM_SETIMAGE)
1821 if (lParam) img=(NSImage *)__GetNSImageFromHICON((HICON)lParam);
1823 [obj setSwellGDIImage:(void *)(img?lParam:0)];
1827 else if (msg >= CB_ADDSTRING && msg <= CB_INITSTORAGE && ([obj isKindOfClass:[NSPopUpButton class]] || [obj isKindOfClass:[NSComboBox class]]))
1831 case CB_ADDSTRING: return SWELL_CB_AddString(hwnd,0,(char*)lParam);
1832 case CB_DELETESTRING: SWELL_CB_DeleteString(hwnd,0,(int)wParam); return 1;
1833 case CB_GETCOUNT: return SWELL_CB_GetNumItems(hwnd,0);
1834 case CB_GETCURSEL: return SWELL_CB_GetCurSel(hwnd,0);
1835 case CB_GETLBTEXT: return SWELL_CB_GetItemText(hwnd,0,(int)wParam,(char *)lParam, 1<<20);
1836 case CB_GETLBTEXTLEN: return SWELL_CB_GetItemText(hwnd,0,(int)wParam,NULL,0);
1837 case CB_INSERTSTRING: return SWELL_CB_InsertString(hwnd,0,(int)wParam,(char *)lParam);
1838 case CB_RESETCONTENT: SWELL_CB_Empty(hwnd,0); return 0;
1839 case CB_SETCURSEL: SWELL_CB_SetCurSel(hwnd,0,(int)wParam); return 0;
1840 case CB_GETITEMDATA: return SWELL_CB_GetItemData(hwnd,0,(int)wParam);
1841 case CB_SETITEMDATA: SWELL_CB_SetItemData(hwnd,0,(int)wParam,lParam); return 0;
1843 case CB_FINDSTRINGEXACT:
1844 if (lParam) return SWELL_CB_FindString(hwnd,0,(int)wParam,(const char *)lParam,msg==CB_FINDSTRINGEXACT);
1846 case CB_INITSTORAGE: return 0;
1850 else if (msg >= TBM_GETPOS && msg <= TBM_SETRANGE && ([obj isKindOfClass:[NSSlider class]]))
1854 case TBM_GETPOS: return SWELL_TB_GetPos(hwnd,0);
1855 case TBM_SETTIC: SWELL_TB_SetTic(hwnd,0,(int)lParam); return 1;
1856 case TBM_SETPOS: SWELL_TB_SetPos(hwnd,0,(int)lParam); return 1;
1857 case TBM_SETRANGE: SWELL_TB_SetRange(hwnd,0,LOWORD(lParam),HIWORD(lParam)); return 1;
1861 else if ((msg == EM_SETSEL || msg == EM_GETSEL || msg == EM_SETPASSWORDCHAR) && ([obj isKindOfClass:[NSTextField class]]))
1863 if (msg == EM_GETSEL)
1866 NSResponder *rs = [[obj window] firstResponder];
1867 if ([rs isKindOfClass:[NSView class]] && [(NSView *)rs isDescendantOf:obj])
1869 NSText* text=[[obj window] fieldEditor:YES forObject:(NSTextField*)obj];
1870 if (text) range=[text selectedRange];
1872 if (wParam) *(int*)wParam=(int)range.location;
1873 if (lParam) *(int*)lParam=(int)(range.location+range.length);
1875 else if (msg == EM_SETSEL)
1877 // [(NSTextField*)obj selectText:obj]; // Force the window's text field editor onto this control
1878 // don't force it, just ignore EM_GETSEL/EM_SETSEL if not in focus
1879 NSResponder *rs = [[obj window] firstResponder];
1880 if ([rs isKindOfClass:[NSView class]] && [(NSView *)rs isDescendantOf:obj])
1882 NSText* text = [[obj window] fieldEditor:YES forObject:(NSTextField*)obj]; // then get it from the window
1883 NSUInteger sl = [[text string] length];
1884 if (wParam == -1) lParam = wParam = 0;
1885 else if (lParam == -1) lParam = sl;
1886 if (wParam>sl) wParam=sl;
1887 if (lParam>sl) lParam=sl;
1888 if (text) [text setSelectedRange:NSMakeRange(wParam, wdl_max(lParam-wParam,0))]; // and set the range
1891 else if (msg == EM_SETPASSWORDCHAR)
1893 // not implemented, because it requires replacing obj within its parent window
1894 // instead caller explicitly destroy the edit control and create a new one with ES_PASSWORD
1898 else if (msg == WM_SETFONT && ([obj isKindOfClass:[NSTextField class]] ||
1899 [obj isKindOfClass:[NSTextView class]]))
1901 NSFont *font = SWELL_GetNSFont((HGDIOBJ__*)wParam);
1902 if (font) [obj setFont:font];
1905 else if (msg == WM_SETFONT && ([obj isKindOfClass:[NSScrollView class]]))
1907 NSView *cv=[(NSScrollView *)obj documentView];
1908 if (cv && [cv isKindOfClass:[NSTextView class]])
1910 NSFont *font = SWELL_GetNSFont((HGDIOBJ__*)wParam);
1911 if (font) [(NSTextView *)cv setFont:font];
1919 // if content view gets unhandled message send to window
1920 if ([obj isKindOfClass:[NSView class]] && (w=[obj window]) && [w contentView] == obj && [w respondsToSelector:@selector(onSwellMessage:p1:p2:)])
1922 return (LRESULT) [(SWELL_hwndChild *)w onSwellMessage:msg p1:wParam p2:lParam];
1924 // if window gets unhandled message send to content view
1925 else if ([obj isKindOfClass:[NSWindow class]] && (v=[obj contentView]) && [v respondsToSelector:@selector(onSwellMessage:p1:p2:)])
1927 return (LRESULT) [(SWELL_hwndChild *)v onSwellMessage:msg p1:wParam p2:lParam];
1935 void DestroyWindow(HWND hwnd)
1937 if (WDL_NOT_NORMALLY(!hwnd)) return;
1940 if ([pid isKindOfClass:[NSView class]])
1942 KillTimer(hwnd,~(UINT_PTR)0);
1943 sendSwellMessage((id)pid,WM_DESTROY,0,0);
1945 NSWindow *pw = [(NSView *)pid window];
1946 if (pw && [pw contentView] == pid) // destroying contentview should destroy top level window
1948 DestroyWindow((HWND)pw);
1954 id foc=[pw firstResponder];
1955 if (foc && (foc == pid || IsChild((HWND)pid,(HWND)foc)))
1957 [pw makeFirstResponder:nil];
1960 [(NSView *)pid removeFromSuperview];
1963 else if ([pid isKindOfClass:[NSWindow class]])
1965 KillTimer(hwnd,~(UINT_PTR)0);
1966 sendSwellMessage([(id)pid contentView],WM_DESTROY,0,0);
1967 sendSwellMessage((id)pid,WM_DESTROY,0,0);
1969 if ([(id)pid respondsToSelector:@selector(swellDoDestroyStuff)])
1970 [(id)pid swellDoDestroyStuff];
1972 NSWindow *par=[(NSWindow*)pid parentWindow];
1975 [par removeChildWindow:(NSWindow*)pid];
1977 [(NSWindow *)pid close]; // this is probably bad, but close takes too long to close!
1982 void EnableWindow(HWND hwnd, int enable)
1984 if (WDL_NOT_NORMALLY(!hwnd)) return;
1987 if ([bla isKindOfClass:[NSWindow class]]) bla = [bla contentView];
1989 if (bla && [bla respondsToSelector:@selector(setEnabled:)])
1993 HWND foc = GetFocus();
1994 if (foc && (foc==hwnd || IsChild(hwnd,foc)))
1996 HWND par = GetParent(hwnd);
1997 if (par) SetFocus(par);
2000 if (enable == -1000 && [bla respondsToSelector:@selector(setEnabledSwellNoFocus)])
2001 [(SWELL_hwndChild *)bla setEnabledSwellNoFocus];
2003 [bla setEnabled:(enable?YES:NO)];
2004 if ([bla isKindOfClass:[SWELL_TextField class]])
2005 [(SWELL_TextField*)bla initColors:-1];
2010 void SetForegroundWindow(HWND hwnd)
2012 WDL_ASSERT(hwnd != NULL);
2016 void SetFocus(HWND hwnd) // these take NSWindow/NSView, and return NSView *
2019 if (!r) return; // on win32 SetFocus(NULL) is allowed, removes focus (maybe we should implement)
2022 if ([r isKindOfClass:[NSWindow class]])
2024 [(NSWindow *)r makeFirstResponder:[(NSWindow *)r contentView]];
2025 if ([(NSWindow *)r isVisible]) [(NSWindow *)r makeKeyAndOrderFront:nil];
2027 else if (WDL_NORMALLY([r isKindOfClass:[NSView class]]))
2029 NSWindow *wnd=[(NSView *)r window];
2032 if ([wnd isVisible])
2033 [wnd makeKeyAndOrderFront:nil];
2034 if ([r acceptsFirstResponder])
2035 [wnd makeFirstResponder:r];
2041 void SWELL_GetViewPort(RECT *r, const RECT *sourcerect, bool wantWork)
2045 NSArray *ar=[NSScreen screens];
2047 const NSInteger cnt=[ar count];
2048 if (!sourcerect || cnt < 2)
2050 NSScreen *sc=[NSScreen mainScreen];
2053 NSRect tr=wantWork ? [sc visibleFrame] : [sc frame];
2054 NSRECT_TO_RECT(r,tr);
2065 double best_score = -1e20;
2066 // find screen of best intersection
2067 RECT sr = *sourcerect;
2068 if (sr.top > sr.bottom) { sr.top = sourcerect->bottom; sr.bottom = sourcerect->top; }
2069 if (sr.left > sr.right) { sr.left = sourcerect->right; sr.right = sourcerect->left; }
2070 for (NSInteger x = 0; x < cnt; x ++)
2072 NSScreen *sc=[ar objectAtIndex:x];
2075 NSRect tr=wantWork ? [sc visibleFrame] : [sc frame];
2077 NSRECT_TO_RECT(&tmp,tr);
2081 if (IntersectRect(&res, &tmp, &sr))
2083 score = wdl_abs((res.right-res.left) * (res.bottom-res.top));
2088 if (tmp.left > sr.right) dx = tmp.left - sr.right;
2089 else if (tmp.right < sr.left) dx = sr.left - tmp.right;
2090 if (tmp.bottom < sr.top) dy = tmp.bottom - sr.top;
2091 else if (tmp.top > sr.bottom) dy = tmp.top - sr.bottom;
2092 score = - (dx*dx + dy*dy);
2096 if (!x || score > best_score)
2107 void ScreenToClient(HWND hwnd, POINT *p)
2109 if (WDL_NOT_NORMALLY(!hwnd)) return;
2110 // no need to try/catch, this should never have an issue *wince*
2113 if ([ch isKindOfClass:[NSWindow class]]) ch=[((NSWindow *)ch) contentView];
2114 if (WDL_NOT_NORMALLY(!ch || ![ch isKindOfClass:[NSView class]])) return;
2116 NSWindow *window=[ch window];
2118 NSPoint wndpt = [window convertScreenToBase:NSMakePoint(p->x,p->y)];
2120 // todo : WM_NCCALCSIZE
2121 NSPOINT_TO_POINT(p, [ch convertPoint:wndpt fromView:nil]);
2124 void ClientToScreen(HWND hwnd, POINT *p)
2126 if (WDL_NOT_NORMALLY(!hwnd)) return;
2129 if ([ch isKindOfClass:[NSWindow class]]) ch=[((NSWindow *)ch) contentView];
2130 if (!ch || ![ch isKindOfClass:[NSView class]]) return;
2132 NSWindow *window=[ch window];
2134 NSPoint wndpt = [ch convertPoint:NSMakePoint(p->x,p->y) toView:nil];
2136 // todo : WM_NCCALCSIZE
2138 NSPOINT_TO_POINT(p,[window convertBaseToScreen:wndpt]);
2141 static NSView *NavigateUpScrollClipViews(NSView *ch)
2143 NSView *par=[ch superview];
2144 if (par && [par isKindOfClass:[NSClipView class]])
2146 par=[par superview];
2147 if (par && [par isKindOfClass:[NSScrollView class]])
2155 HWND SWELL_NavigateUpScrollClipViews(HWND h)
2158 if (h && [(id)h isKindOfClass:[NSView class]]) v = (NSView *)h;
2159 else if (h && [(id)h isKindOfClass:[NSWindow class]]) v = [(NSWindow *)h contentView];
2161 return (HWND)NavigateUpScrollClipViews(v);
2165 bool GetWindowRect(HWND hwnd, RECT *r)
2167 r->left=r->top=r->right=r->bottom=0;
2168 if (WDL_NOT_NORMALLY(!hwnd)) return false;
2174 if ([ch isKindOfClass:[NSView class]] && (nswnd=[(NSView *)ch window]) && [nswnd contentView]==ch)
2177 if ([ch isKindOfClass:[NSWindow class]])
2179 NSRECT_TO_RECT(r,[ch frame]);
2182 if (![ch isKindOfClass:[NSView class]]) return false;
2183 ch=NavigateUpScrollClipViews(ch);
2184 NSRECT_TO_RECT(r,[ch bounds]);
2185 ClientToScreen((HWND)ch,(POINT *)r);
2186 ClientToScreen((HWND)ch,((POINT *)r)+1);
2187 SWELL_END_TRY(return false;)
2192 void GetWindowContentViewRect(HWND hwnd, RECT *r)
2196 if (hwnd && [(id)hwnd isKindOfClass:[NSView class]] && (nswnd=[(NSView *)hwnd window]) && [nswnd contentView]==(id)hwnd)
2199 if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]])
2201 NSView *ch=[(id)hwnd contentView];
2202 NSRECT_TO_RECT(r,[ch bounds]);
2203 ClientToScreen(hwnd,(POINT *)r);
2204 ClientToScreen(hwnd,((POINT *)r)+1);
2206 else GetWindowRect(hwnd,r);
2211 void GetClientRect(HWND hwnd, RECT *r)
2213 r->left=r->top=r->right=r->bottom=0;
2214 if (WDL_NOT_NORMALLY(!hwnd)) return;
2218 if ([ch isKindOfClass:[NSWindow class]]) ch=[((NSWindow *)ch) contentView];
2219 if (!ch || ![ch isKindOfClass:[NSView class]]) return;
2220 ch=NavigateUpScrollClipViews(ch);
2222 NSRECT_TO_RECT(r,[ch bounds]);
2224 // todo this may need more attention
2225 NCCALCSIZE_PARAMS tr={{*r,},};
2226 SendMessage(hwnd,WM_NCCALCSIZE,FALSE,(LPARAM)&tr);
2227 r->right = r->left + (tr.rgrc[0].right-tr.rgrc[0].left);
2228 r->bottom = r->top + (tr.rgrc[0].bottom-tr.rgrc[0].top);
2234 void SetWindowPos(HWND hwnd, HWND hwndAfter, int x, int y, int cx, int cy, int flags)
2236 if (WDL_NOT_NORMALLY(!hwnd)) return;
2239 NSWindow *nswnd; // content views = move window
2240 if (hwnd && [(id)hwnd isKindOfClass:[NSView class]] && (nswnd=[(NSView *)hwnd window]) && [nswnd contentView]==(id)hwnd)
2243 // todo: handle SWP_SHOWWINDOW
2246 if ([ch isKindOfClass:[NSWindow class]] || (isview=[ch isKindOfClass:[NSView class]]))
2250 ch=NavigateUpScrollClipViews(ch);
2251 if (isview && !(flags&SWP_NOZORDER))
2253 NSView *v = (NSView *)ch;
2254 NSView *par = [v superview];
2255 NSArray *subs = [par subviews];
2256 NSInteger idx = [subs indexOfObjectIdenticalTo:v], cnt=[subs count];
2258 NSView *viewafter = NULL;
2259 NSWindowOrderingMode omode = NSWindowAbove;
2261 if (cnt>1 && hwndAfter != (HWND)ch)
2263 if (hwndAfter==HWND_TOPMOST||hwndAfter==HWND_NOTOPMOST)
2266 else if (hwndAfter == HWND_TOP)
2268 if (idx<cnt-1) viewafter = [subs objectAtIndex:cnt-1];
2270 else if (hwndAfter == HWND_BOTTOM)
2272 if (idx>0) viewafter = [subs objectAtIndex:0];
2273 omode = NSWindowBelow;
2277 NSInteger a=[subs indexOfObjectIdenticalTo:(NSView *)hwndAfter];
2278 if (a != NSNotFound && a != (idx-1)) viewafter = (NSView *)hwndAfter;
2284 HWND h = GetCapture();
2285 if (!h || (h!=(HWND)v && !IsChild((HWND)v,h))) // if this window is captured don't reorder!
2287 NSView *oldfoc = (NSView*)[[v window] firstResponder];
2288 if (!oldfoc || ![oldfoc isKindOfClass:[NSView class]] ||
2289 (oldfoc != v && ![oldfoc isDescendantOf:v])) oldfoc=NULL;
2291 // better way to do this? maybe :/
2293 [v removeFromSuperviewWithoutNeedingDisplay];
2294 [par addSubview:v positioned:omode relativeTo:viewafter];
2296 if (oldfoc && [oldfoc isKindOfClass:[NSView class]] && [oldfoc window] == [v window])
2297 [[v window] makeFirstResponder:oldfoc];
2304 NSRect f=[ch frame];
2306 if (!(flags&SWP_NOMOVE))
2308 f.origin.x=(float)x;
2309 f.origin.y=(float)y;
2312 if (!(flags&SWP_NOSIZE))
2314 f.size.width=(float)cx;
2315 f.size.height=(float)cy;
2316 if (f.size.height<0)f.size.height=-f.size.height;
2323 NSSize mins=[ch minSize];
2324 NSSize maxs=[ch maxSize];
2325 if (f.size.width < mins.width) f.size.width=mins.width;
2326 else if (f.size.width > maxs.width) f.size.width=maxs.width;
2327 if (f.size.height < mins.height) f.size.height=mins.height;
2328 else if (f.size.height> maxs.height) f.size.height=maxs.height;
2329 [ch setFrame:f display:NO];
2334 // this doesnt seem to actually be a good idea anymore
2335 // if ([[ch window] contentView] != ch && ![[ch superview] isFlipped])
2336 // f.origin.y -= f.size.height;
2338 if ([ch isKindOfClass:[NSScrollView class]])
2340 NSView *cv=[ch documentView];
2341 if (cv && [cv isKindOfClass:[NSTextView class]])
2343 NSRect fr=[cv frame];
2344 NSSize sz=[ch contentSize];
2346 if (![ch hasHorizontalScroller]) {a ++; fr.size.width=sz.width; }
2347 if (![ch hasVerticalScroller]) { a++; fr.size.height=sz.height; }
2348 if (a) [cv setFrame:fr];
2358 BOOL EnumWindows(BOOL (*proc)(HWND, LPARAM), LPARAM lp)
2360 NSArray *ch=[NSApp windows];
2362 const NSInteger n=[ch count];
2363 for(NSInteger x=0;x<n; x ++)
2365 NSWindow *w = [ch objectAtIndex:x];
2366 if (!proc((HWND)[w contentView],lp))
2377 HWND GetWindow(HWND hwnd, int what)
2379 if (WDL_NOT_NORMALLY(!hwnd)) return 0;
2382 if ([(id)hwnd isKindOfClass:[NSWindow class]]) hwnd=(HWND)[(id)hwnd contentView];
2383 if (!hwnd || ![(id)hwnd isKindOfClass:[NSView class]]) return 0;
2385 NSView *v=(NSView *)hwnd;
2386 if (what == GW_CHILD)
2388 NSArray *ar=[v subviews];
2389 if (ar && [ar count]>0)
2391 return (HWND)[ar objectAtIndex:0];
2395 if (what == GW_OWNER)
2397 v=NavigateUpScrollClipViews(v);
2398 if ([[v window] contentView] == v)
2400 if ([[v window] respondsToSelector:@selector(swellGetOwner)])
2402 return (HWND)[(SWELL_ModelessWindow*)[v window] swellGetOwner];
2406 return (HWND)[v superview];
2409 if (what >= GW_HWNDFIRST && what <= GW_HWNDPREV)
2411 v=NavigateUpScrollClipViews(v);
2412 if ([[v window] contentView] == v)
2414 if (what <= GW_HWNDLAST) return (HWND)hwnd; // content view is only window
2416 return 0; // we're the content view so cant do next/prev
2418 NSView *par=[v superview];
2421 NSArray *ar=[par subviews];
2423 if (ar && (cnt=[ar count]) > 0)
2425 if (what == GW_HWNDFIRST)
2426 return (HWND)[ar objectAtIndex:0];
2427 if (what == GW_HWNDLAST)
2428 return (HWND)[ar objectAtIndex:(cnt-1)];
2430 NSInteger idx=[ar indexOfObjectIdenticalTo:v];
2431 if (idx == NSNotFound) return 0;
2433 if (what==GW_HWNDNEXT) idx++;
2434 else if (what==GW_HWNDPREV) idx--;
2436 if (idx<0 || idx>=cnt) return 0;
2438 return (HWND)[ar objectAtIndex:idx];
2448 HWND GetParent(HWND hwnd)
2451 if (WDL_NORMALLY(hwnd) && [(id)hwnd isKindOfClass:[NSView class]])
2453 hwnd=(HWND)NavigateUpScrollClipViews((NSView *)hwnd);
2455 NSView *cv=[[(NSView *)hwnd window] contentView];
2456 if (cv == (NSView *)hwnd) hwnd=(HWND)[(NSView *)hwnd window]; // passthrough to get window parent
2459 HWND h=(HWND)[(NSView *)hwnd superview];
2464 if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]])
2466 HWND h= (HWND)[(NSWindow *)hwnd parentWindow];
2467 if (h) h=(HWND)[(NSWindow *)h contentView];
2471 if (hwnd && [(id)hwnd respondsToSelector:@selector(swellGetOwner)])
2473 HWND h= (HWND)[(SWELL_ModelessWindow *)hwnd swellGetOwner];
2474 if (h && [(id)h isKindOfClass:[NSWindow class]]) h=(HWND)[(NSWindow *)h contentView];
2482 HWND SetParent(HWND hwnd, HWND newPar)
2485 NSView *v=(NSView *)hwnd;
2486 WDL_ASSERT(hwnd != NULL);
2487 if (!v || ![(id)v isKindOfClass:[NSView class]]) return 0;
2488 v=NavigateUpScrollClipViews(v);
2490 if ([(id)hwnd isKindOfClass:[NSView class]])
2492 NSView *tv=(NSView *)hwnd;
2493 if ([[tv window] contentView] == tv) // if we're reparenting a contentview (aka top level window)
2495 if (!newPar) return NULL;
2497 NSView *npv = (NSView *)newPar;
2498 if ([npv isKindOfClass:[NSWindow class]]) npv=[(NSWindow *)npv contentView];
2499 if (!npv || ![npv isKindOfClass:[NSView class]])
2502 char oldtitle[2048];
2504 GetWindowText(hwnd,oldtitle,sizeof(oldtitle));
2506 NSWindow *oldwnd = [tv window];
2508 if ([oldwnd respondsToSelector:@selector(swellGetOwner)]) oldown=[(SWELL_ModelessWindow*)oldwnd swellGetOwner];
2510 if ([tv isKindOfClass:[SWELL_hwndChild class]]) ((SWELL_hwndChild*)tv)->m_lastTopLevelOwner = oldown;
2513 SWELL_hwndChild *tmpview = [[SWELL_hwndChild alloc] initChild:nil Parent:(NSView *)oldwnd dlgProc:nil Param:0];
2516 [npv addSubview:tv];
2519 DestroyWindow((HWND)oldwnd); // close old window since its no longer used
2520 if (oldtitle[0]) SetWindowText(hwnd,oldtitle);
2523 else if (!newPar) // not content view, not parent (so making it a top level modeless dialog)
2525 char oldtitle[2048];
2527 GetWindowText(hwnd,oldtitle,sizeof(oldtitle));
2530 [tv removeFromSuperview];
2533 unsigned int wf=(NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask|NSResizableWindowMask);
2534 if ([tv respondsToSelector:@selector(swellCreateWindowFlags)])
2535 wf=(unsigned int)[(SWELL_hwndChild *)tv swellCreateWindowFlags];
2538 if ([tv isKindOfClass:[SWELL_hwndChild class]])
2540 id oldown = ((SWELL_hwndChild*)tv)->m_lastTopLevelOwner;
2543 NSArray *ch=[NSApp windows];
2544 const NSInteger n = [ch count];
2545 for(NSInteger x=0;x<n && !newOwner; x ++)
2547 NSWindow *w = [ch objectAtIndex:x];
2548 if (w == (NSWindow *)oldown || [w contentView] == (NSView *)oldown) newOwner = (HWND)w;
2553 HWND SWELL_CreateModelessFrameForWindow(HWND childW, HWND ownerW, unsigned int);
2554 HWND bla=SWELL_CreateModelessFrameForWindow((HWND)tv,(HWND)newOwner,wf);
2555 // create a new modeless frame
2559 [(NSWindow *)bla display];
2563 if (oldtitle[0]) SetWindowText(hwnd,oldtitle);
2569 HWND ret=(HWND) [v superview];
2573 [v removeFromSuperview];
2575 NSView *np=(NSView *)newPar;
2576 if (np && [np isKindOfClass:[NSWindow class]]) np=[(NSWindow *)np contentView];
2578 if (np && [np isKindOfClass:[NSView class]])
2589 int IsChild(HWND hwndParent, HWND hwndChild)
2591 if (!hwndParent || !hwndChild || hwndParent == hwndChild) return 0;
2593 id par=(id)hwndParent;
2594 id ch=(id)hwndChild;
2595 if (![ch isKindOfClass:[NSView class]]) return 0;
2596 if ([par isKindOfClass:[NSWindow class]])
2598 return [ch window] == par;
2600 else if ([par isKindOfClass:[NSView class]])
2602 return !![ch isDescendantOf:par];
2608 HWND GetForegroundWindow()
2611 NSWindow *window=[NSApp keyWindow];
2612 if (!window) return 0;
2613 id ret=[window firstResponder];
2614 if (ret && [ret isKindOfClass:[NSView class]])
2616 // if (ret == [window contentView]) return (HWND) window;
2619 return (HWND)window;
2627 NSWindow *window=[NSApp keyWindow];
2628 if (!window) return 0;
2629 id ret=[window firstResponder];
2630 if (ret && [ret isKindOfClass:[NSView class]])
2632 // if (ret == [window contentView]) return (HWND) window;
2634 if ([ret isKindOfClass:[NSTextView class]] && [ret superview] && [[ret superview] superview])
2636 NSView* v = [[ret superview] superview];
2637 if ([v isKindOfClass:[NSTextField class]]) return (HWND) v;
2646 bool IsEquivalentTextView(HWND h1, HWND h2)
2648 if (!h1 || !h2) return false;
2649 if (h1 == h2) return true;
2651 NSView* v1 = (NSView*)h1;
2652 NSView* v2 = (NSView*)h2;
2653 if ([v1 isKindOfClass:[NSTextField class]] && [v2 isKindOfClass:[NSTextView class]])
2659 if ([v1 isKindOfClass: [NSTextView class]] && [v2 isKindOfClass:[NSTextField class]])
2661 if ([v1 superview] && [[v1 superview] superview] && [[[v1 superview] superview] superview] == v2) return true;
2669 BOOL SetDlgItemText(HWND hwnd, int idx, const char *text)
2671 NSView *obj=(NSView *)(idx ? GetDlgItem(hwnd,idx) : hwnd);
2672 if (WDL_NOT_NORMALLY(!obj)) return false;
2676 if ([(id)obj isKindOfClass:[NSView class]] && (nswnd=[(NSView *)obj window]) && [nswnd contentView]==(id)obj)
2678 SetDlgItemText((HWND)nswnd,0,text); // also set window if setting content view
2681 if ([obj respondsToSelector:@selector(onSwellSetText:)])
2683 [(SWELL_hwndChild*)obj onSwellSetText:text];
2688 NSString *lbl=(NSString *)SWELL_CStringToCFString(text);
2689 if ([obj isKindOfClass:[NSWindow class]] || [obj isKindOfClass:[NSButton class]]) [(NSButton*)obj setTitle:lbl];
2690 else if ([obj isKindOfClass:[NSControl class]])
2692 [(NSControl*)obj setStringValue:lbl];
2693 if ([obj isKindOfClass:[NSTextField class]] && [(NSTextField *)obj isEditable])
2695 if (![obj isKindOfClass:[NSComboBox class]])
2697 HWND par = GetParent((HWND)obj);
2699 SendMessage(par,WM_COMMAND,MAKELONG([(NSControl *)obj tag],EN_CHANGE),(LPARAM)obj);
2703 else if ([obj isKindOfClass:[NSText class]])
2705 // todo if there is a way to find out that the window's NSTextField is already assigned
2706 // to another field, restore the assignment afterwards
2707 [(NSText*)obj setString:lbl];
2708 [obj setNeedsDisplay:YES]; // required on Sierra, it seems -- if the parent is hidden (e.g. DialogBox() + WM_INITDIALOG), the view is not drawn
2710 else if ([obj isKindOfClass:[NSBox class]])
2712 [(NSBox *)obj setTitle:lbl];
2725 int GetWindowTextLength(HWND hwnd)
2727 if (WDL_NOT_NORMALLY(!hwnd)) return 0;
2731 NSView *pvw = (NSView *)hwnd;
2732 if ([(id)pvw isKindOfClass:[NSView class]] && [[(id)pvw window] contentView] == pvw)
2734 pvw=(NSView *)[(id)pvw window];
2737 if ([(id)pvw respondsToSelector:@selector(onSwellGetText)])
2739 const char *p=(const char *)[(SWELL_hwndChild*)pvw onSwellGetText];
2740 return p ? (int)strlen(p) : 0;
2745 if ([pvw isKindOfClass:[NSButton class]]||[pvw isKindOfClass:[NSWindow class]]) s=[((NSButton *)pvw) title];
2746 else if ([pvw isKindOfClass:[NSControl class]]) s=[((NSControl *)pvw) stringValue];
2747 else if ([pvw isKindOfClass:[NSText class]]) s=[(NSText*)pvw string];
2748 else if ([pvw isKindOfClass:[NSBox class]]) s=[(NSBox *)pvw title];
2751 const char *p = s ? [s UTF8String] : NULL;
2752 return p ? (int)strlen(p) : 0;
2758 BOOL GetDlgItemText(HWND hwnd, int idx, char *text, int textlen)
2761 NSView *pvw=(NSView *)(idx?GetDlgItem(hwnd,idx) : hwnd);
2762 if (WDL_NOT_NORMALLY(!pvw)) return false;
2766 if ([(id)pvw isKindOfClass:[NSView class]] && [[(id)pvw window] contentView] == pvw)
2768 pvw=(NSView *)[(id)pvw window];
2771 if ([(id)pvw respondsToSelector:@selector(onSwellGetText)])
2773 const char *p=(const char *)[(SWELL_hwndChild*)pvw onSwellGetText];
2774 lstrcpyn_safe(text,p?p:"",textlen);
2780 if ([pvw isKindOfClass:[NSButton class]]||[pvw isKindOfClass:[NSWindow class]]) s=[((NSButton *)pvw) title];
2781 else if ([pvw isKindOfClass:[NSControl class]]) s=[((NSControl *)pvw) stringValue];
2782 else if ([pvw isKindOfClass:[NSText class]]) s=[(NSText*)pvw string];
2783 else if ([pvw isKindOfClass:[NSBox class]]) s=[(NSBox *)pvw title];
2786 if (s) SWELL_CFStringToCString(s,text,textlen);
2787 // [s getCString:text maxLength:textlen];
2794 void CheckDlgButton(HWND hwnd, int idx, int check)
2796 NSView *pvw=(NSView *)GetDlgItem(hwnd,idx);
2797 if (WDL_NOT_NORMALLY(!pvw)) return;
2798 if ([pvw isKindOfClass:[NSButton class]])
2799 [(NSButton*)pvw setState:(check&BST_INDETERMINATE)?NSMixedState:((check&BST_CHECKED)?NSOnState:NSOffState)];
2803 int IsDlgButtonChecked(HWND hwnd, int idx)
2805 NSView *pvw=(NSView *)GetDlgItem(hwnd,idx);
2806 if (WDL_NORMALLY(pvw && [pvw isKindOfClass:[NSButton class]]))
2808 NSInteger a=[(NSButton*)pvw state];
2809 if (a==NSMixedState) return BST_INDETERMINATE;
2810 return a!=NSOffState;
2815 void SWELL_TB_SetPos(HWND hwnd, int idx, int pos)
2817 NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2818 if (WDL_NORMALLY(p) && [p isKindOfClass:[NSSlider class]])
2820 [p setDoubleValue:(double)pos];
2824 sendSwellMessage(p,TBM_SETPOS,1,pos);
2828 void SWELL_TB_SetRange(HWND hwnd, int idx, int low, int hi)
2830 NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2831 if (WDL_NORMALLY(p) && [p isKindOfClass:[NSSlider class]])
2833 [p setMinValue:low];
2838 sendSwellMessage(p,TBM_SETRANGE,1,MAKELONG(low&0xffff,hi));
2843 int SWELL_TB_GetPos(HWND hwnd, int idx)
2845 NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2846 if (WDL_NORMALLY(p) && [p isKindOfClass:[NSSlider class]])
2848 return (int) ([p doubleValue]+0.5);
2852 return (int) sendSwellMessage(p,TBM_GETPOS,0,0);
2857 void SWELL_TB_SetTic(HWND hwnd, int idx, int pos)
2859 NSSlider *p=(NSSlider *)GetDlgItem(hwnd,idx);
2860 WDL_ASSERT(p != NULL);
2861 sendSwellMessage(p,TBM_SETTIC,0,pos);
2864 void SWELL_CB_DeleteString(HWND hwnd, int idx, int wh)
2866 NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2867 if (WDL_NOT_NORMALLY(!p)) return;
2868 if ([p isKindOfClass:[SWELL_ComboBox class]])
2870 if (wh>=0 && wh<[p numberOfItems])
2872 SWELL_ComboBox *s = (SWELL_ComboBox *)p;
2873 if (s->m_ignore_selchg == wh) s->m_ignore_selchg=-1;
2874 else if (s->m_ignore_selchg >= wh) s->m_ignore_selchg--;
2875 [p removeItemAtIndex:wh];
2876 if (s->m_ids) ((SWELL_ComboBox*)p)->m_ids->Delete(wh);
2879 else if ( [p isKindOfClass:[NSPopUpButton class]])
2881 NSMenu *menu = [p menu];
2884 if (wh >= 0 && wh < [menu numberOfItems])
2885 [menu removeItemAtIndex:wh];
2891 int SWELL_CB_FindString(HWND hwnd, int idx, int startAfter, const char *str, bool exact)
2893 NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2894 if (WDL_NOT_NORMALLY(!p)) return 0;
2896 int pos = startAfter;
2900 const size_t l1len = strlen(str);
2901 const int ni=(int)[p numberOfItems];
2903 if ([p isKindOfClass:[NSComboBox class]])
2907 NSString *s=[p itemObjectValueAtIndex:pos];
2911 SWELL_CFStringToCString(s,buf,sizeof(buf));
2912 if (exact ? !stricmp(str,buf) : !strnicmp(str,buf,l1len))
2921 NSMenuItem *i=[(NSPopUpButton *)p itemAtIndex:pos];
2924 NSString *s=[i title];
2928 SWELL_CFStringToCString(s,buf,sizeof(buf));
2929 if (exact ? !stricmp(str,buf) : !strnicmp(str,buf,l1len))
2938 int SWELL_CB_GetItemText(HWND hwnd, int idx, int item, char *buf, int bufsz)
2940 NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2943 if (WDL_NOT_NORMALLY(!p)) return CB_ERR;
2944 const int ni = (int)[p numberOfItems];
2945 if (item < 0 || item >= ni) return CB_ERR;
2947 if ([p isKindOfClass:[NSComboBox class]])
2949 NSString *s=[p itemObjectValueAtIndex:item];
2952 if (!buf) return (int) ([s lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 64);
2954 SWELL_CFStringToCString(s,buf,bufsz);
2960 NSMenuItem *i=[(NSPopUpButton *)p itemAtIndex:item];
2963 NSString *s=[i title];
2966 if (!buf) return (int) ([s lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 64);
2968 SWELL_CFStringToCString(s,buf,bufsz);
2977 int SWELL_CB_InsertString(HWND hwnd, int idx, int pos, const char *str)
2979 NSString *label=(NSString *)SWELL_CStringToCFString(str);
2980 NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
2981 if (WDL_NOT_NORMALLY(!p)) return 0;
2983 bool isAppend=false;
2984 const int ni = (int)[p numberOfItems];
2990 else if (pos < 0) pos=0;
2991 else if (pos > ni) pos=ni;
2994 if ([p isKindOfClass:[SWELL_ComboBox class]])
2996 SWELL_ComboBox *s = (SWELL_ComboBox *)p;
2997 if (isAppend && (((int)[s getSwellStyle]) & CBS_SORT))
2999 pos=(int)arr_bsearch_mod(label,[p objectValues],_nsStringSearchProc);
3002 if (s->m_ignore_selchg >= pos) s->m_ignore_selchg++;
3004 [p addItemWithObjectValue:label];
3006 [p insertItemWithObjectValue:label atIndex:pos];
3008 if (s->m_ids) s->m_ids->Insert(pos,(char*)0);
3009 [p setNumberOfVisibleItems:(ni+1)];
3013 NSMenu *menu = [(NSPopUpButton *)p menu];
3016 const bool needclearsel = [p indexOfSelectedItem] < 0;
3017 if (isAppend && [p respondsToSelector:@selector(getSwellStyle)] && (((int)[(SWELL_PopUpButton*)p getSwellStyle]) & CBS_SORT))
3019 pos=(int)arr_bsearch_mod(label,[menu itemArray],_nsMenuSearchProc);
3021 NSMenuItem *item=[menu insertItemWithTitle:label action:NULL keyEquivalent:@"" atIndex:pos];
3022 [item setEnabled:YES];
3023 if (needclearsel) [(NSPopUpButton *)p selectItemAtIndex:-1];
3031 int SWELL_CB_AddString(HWND hwnd, int idx, const char *str)
3033 return SWELL_CB_InsertString(hwnd,idx,-1000,str);
3036 int SWELL_CB_GetCurSel(HWND hwnd, int idx)
3038 NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
3039 if (WDL_NOT_NORMALLY(!p)) return -1;
3040 return (int)[p indexOfSelectedItem];
3043 void SWELL_CB_SetCurSel(HWND hwnd, int idx, int item)
3045 NSComboBox *cb = (NSComboBox *)GetDlgItem(hwnd,idx);
3046 if (WDL_NOT_NORMALLY(!cb)) return;
3047 const bool is_swell_cb = [cb isKindOfClass:[SWELL_ComboBox class]];
3049 if (item < 0 || item >= [cb numberOfItems])
3051 // combo boxes can be NSComboBox or NSPopupButton, NSComboBox needs
3052 // a different deselect method (selectItemAtIndex:-1 throws an exception)
3053 if ([cb isKindOfClass:[NSComboBox class]])
3055 const NSInteger sel = [cb indexOfSelectedItem];
3056 if (sel>=0) [cb deselectItemAtIndex:sel];
3057 if (is_swell_cb) ((SWELL_ComboBox *)cb)->m_ignore_selchg = -1;
3059 else if ([cb isKindOfClass:[NSPopUpButton class]])
3060 [(NSPopUpButton*)cb selectItemAtIndex:-1];
3064 if (is_swell_cb) ((SWELL_ComboBox *)cb)->m_ignore_selchg = item;
3065 [cb selectItemAtIndex:item];
3069 int SWELL_CB_GetNumItems(HWND hwnd, int idx)
3071 NSComboBox *p=(NSComboBox *)GetDlgItem(hwnd,idx);
3072 if (WDL_NOT_NORMALLY(!p)) return 0;
3073 return (int)[p numberOfItems];
3078 void SWELL_CB_SetItemData(HWND hwnd, int idx, int item, LONG_PTR data)
3080 id cb=(id)GetDlgItem(hwnd,idx);
3081 if (WDL_NOT_NORMALLY(!cb)) return;
3083 if ([cb isKindOfClass:[NSPopUpButton class]])
3085 if (item < 0 || item >= [cb numberOfItems]) return;
3086 NSMenuItem *it=[(NSPopUpButton*)cb itemAtIndex:item];
3089 SWELL_DataHold *p=[[SWELL_DataHold alloc] initWithVal:(void *)data];
3090 [it setRepresentedObject:p];
3093 else if ([cb isKindOfClass:[SWELL_ComboBox class]])
3095 if (item < 0 || item >= [cb numberOfItems]) return;
3096 if (((SWELL_ComboBox*)cb)->m_ids) ((SWELL_ComboBox*)cb)->m_ids->Set(item,(char*)data);
3100 LONG_PTR SWELL_CB_GetItemData(HWND hwnd, int idx, int item)
3102 id cb=(id)GetDlgItem(hwnd,idx);
3103 if (WDL_NOT_NORMALLY(!cb)) return 0;
3104 if ([cb isKindOfClass:[NSPopUpButton class]])
3106 if (item < 0 || item >= [cb numberOfItems]) return 0;
3107 NSMenuItem *it=[(NSPopUpButton*)cb itemAtIndex:item];
3109 id p= [it representedObject];
3110 if (!p || ![p isKindOfClass:[SWELL_DataHold class]]) return 0;
3111 return (LONG_PTR) (void *)[p getValue];
3113 else if ([cb isKindOfClass:[SWELL_ComboBox class]])
3115 if (item < 0 || item >= [cb numberOfItems]) return 0;
3116 if (((SWELL_ComboBox*)cb)->m_ids) return (LONG_PTR) ((SWELL_ComboBox*)cb)->m_ids->Get(item);
3121 void SWELL_CB_Empty(HWND hwnd, int idx)
3123 id cb=(id)GetDlgItem(hwnd,idx);
3124 if (WDL_NOT_NORMALLY(!cb)) return;
3125 if ([cb isKindOfClass:[NSPopUpButton class]] ||
3126 [cb isKindOfClass:[NSComboBox class]]) [cb removeAllItems];
3128 if ([cb isKindOfClass:[SWELL_ComboBox class]])
3130 SWELL_ComboBox *p = (SWELL_ComboBox *)cb;
3131 p->m_ignore_selchg = -1;
3132 if (p->m_ids) p->m_ids->Empty();
3137 BOOL SetDlgItemInt(HWND hwnd, int idx, int val, int issigned)
3140 sprintf(buf,issigned?"%d":"%u",val);
3141 return SetDlgItemText(hwnd,idx,buf);
3144 int GetDlgItemInt(HWND hwnd, int idx, BOOL *translated, int issigned)
3147 if (!GetDlgItemText(hwnd,idx,buf,sizeof(buf)))
3149 if (translated) *translated=0;
3153 while (*p == ' ' || *p == '\t') p++;
3155 if ((a<0 && !issigned) || (!a && p[0] != '0')) { if (translated) *translated=0; return 0; }
3156 if (translated) *translated=1;
3160 void SWELL_HideApp()
3166 BOOL SWELL_GetGestureInfo(LPARAM lParam, GESTUREINFO* gi)
3168 if (!lParam || !gi) return FALSE;
3169 memcpy(gi, (GESTUREINFO*)lParam, sizeof(GESTUREINFO));
3174 void ShowWindow(HWND hwnd, int cmd)
3178 if (WDL_NORMALLY(pid) && [pid isKindOfClass:[NSWindow class]])
3180 if (cmd == SW_SHOWNA && [pid isKindOfClass:[SWELL_ModelessWindow class]])
3182 if (((SWELL_ModelessWindow *)pid)->m_wantInitialKeyWindowOnShow)
3184 ((SWELL_ModelessWindow *)pid)->m_wantInitialKeyWindowOnShow=false;
3190 [pid makeKeyAndOrderFront:pid];
3192 else if (cmd==SW_SHOWNA)
3194 [pid orderFront:pid];
3196 else if (cmd==SW_HIDE)
3200 else if (cmd==SW_SHOWMAXIMIZED)
3202 if (![pid isZoomed]) [pid zoom:nil];
3203 [pid orderFront:pid];
3205 else if (cmd == SW_RESTORE)
3207 if ([pid isZoomed]) [pid zoom:nil];
3208 [pid orderFront:pid];
3210 else if (cmd == SW_SHOWMINIMIZED)
3212 // this ought to work
3213 //if ([NSApp mainWindow] == pid)
3215 // [NSApp hide:pid];
3219 [pid miniaturize:pid];
3224 if (!pid || ![pid isKindOfClass:[NSView class]]) return;
3226 pid=NavigateUpScrollClipViews(pid);
3231 case SW_SHOWMAXIMIZED:
3234 [((NSView *)pid) setHidden:NO];
3238 NSWindow *pw=[pid window];
3241 id foc=[pw firstResponder];
3242 if (foc && (foc == pid || IsChild((HWND)pid,(HWND)foc)))
3244 [pw makeFirstResponder:nil];
3247 if (![((NSView *)pid) isHidden])
3249 if ((NSView *)pid != [pw contentView])
3251 HWND par = (HWND) [(NSView *)pid superview];
3255 GetWindowRect((HWND)pid,&r);
3256 ScreenToClient(par,(LPPOINT)&r);
3257 ScreenToClient(par,((LPPOINT)&r)+1);
3258 InvalidateRect(par,&r,FALSE);
3261 [((NSView *)pid) setHidden:YES];
3268 if ((nswnd=[(NSView *)pid window]) && [nswnd contentView]==(id)pid)
3270 ShowWindow((HWND)nswnd,cmd);
3274 void *SWELL_ModalWindowStart(HWND hwnd)
3276 if (hwnd && [(id)hwnd isKindOfClass:[NSView class]]) hwnd=(HWND)[(NSView *)hwnd window];
3277 if (WDL_NOT_NORMALLY(!hwnd)) return 0;
3278 return (void *)[NSApp beginModalSessionForWindow:(NSWindow *)hwnd];
3281 bool SWELL_ModalWindowRun(void *ctx, int *ret) // returns false and puts retval in *ret when done
3283 if (!ctx) return false;
3284 NSInteger r=[NSApp runModalSession:(NSModalSession)ctx];
3285 if (r==NSRunContinuesResponse) return true;
3286 if (ret) *ret=(int)r;
3290 void SWELL_ModalWindowEnd(void *ctx)
3294 if ([NSApp runModalSession:(NSModalSession)ctx] == NSRunContinuesResponse)
3297 while ([NSApp runModalSession:(NSModalSession)ctx]==NSRunContinuesResponse) Sleep(10);
3299 [NSApp endModalSession:(NSModalSession)ctx];
3303 void SWELL_CloseWindow(HWND hwnd)
3305 if (WDL_NORMALLY(hwnd) && [(id)hwnd isKindOfClass:[NSWindow class]])
3307 [((NSWindow*)hwnd) close];
3309 else if (hwnd && [(id)hwnd isKindOfClass:[NSView class]])
3311 [[(NSView*)hwnd window] close];
3316 #include "swell-dlggen.h"
3318 static id m_make_owner;
3319 static NSRect m_transform;
3320 static float m_parent_h;
3321 static bool m_doautoright;
3322 static NSRect m_lastdoauto;
3323 static bool m_sizetofits;
3324 static int m_make_radiogroupcnt;
3326 #define ACTIONTARGET (m_make_owner)
3328 void SWELL_MakeSetCurParms(float xscale, float yscale, float xtrans, float ytrans, HWND parent, bool doauto, bool dosizetofit)
3330 if (parent) s_prefix_removals.Empty(true,free);
3331 m_make_radiogroupcnt=0;
3332 m_sizetofits=dosizetofit;
3333 m_lastdoauto.origin.x = 0;
3334 m_lastdoauto.origin.y = -100;
3335 m_lastdoauto.size.width = 0;
3336 m_doautoright=doauto;
3337 m_transform.origin.x=xtrans;
3338 m_transform.origin.y=ytrans;
3339 m_transform.size.width=xscale;
3340 m_transform.size.height=yscale;
3341 m_make_owner=(id)parent;
3342 if ([m_make_owner isKindOfClass:[NSWindow class]]) m_make_owner=[(NSWindow *)m_make_owner contentView];
3344 if ([(id)m_make_owner isKindOfClass:[NSView class]])
3346 m_parent_h=[(NSView *)m_make_owner bounds].size.height;
3347 if (m_transform.size.height > 0 && [(id)parent isFlipped])
3348 m_transform.size.height*=-1;
3352 static void UpdateAutoCoords(NSRect r)
3354 m_lastdoauto.size.width=r.origin.x + r.size.width - m_lastdoauto.origin.x;
3357 static NSRect MakeCoords(int x, int y, int w, int h, bool wantauto, bool ignorevscaleheight=false)
3361 return NSMakeRect(-x,-y,-w,-h);
3363 float ysc=m_transform.size.height;
3364 float ysc2 = ignorevscaleheight ? 1.0 : ysc;
3365 int newx=(int)((x+m_transform.origin.x)*m_transform.size.width + 0.5);
3366 int newy=(int)((ysc >= 0.0 ? m_parent_h - ((y+m_transform.origin.y) )*ysc + h*ysc2 :
3367 ((y+m_transform.origin.y) )*-ysc) + 0.5);
3369 NSRect ret= NSMakeRect(newx,
3371 (int) (w*m_transform.size.width+0.5),
3372 (int) (h*fabs(ysc2)+0.5));
3375 if (wantauto && m_doautoright)
3377 float dx = ret.origin.x - m_lastdoauto.origin.x;
3378 if (fabs(dx)<32 && m_lastdoauto.origin.y >= ret.origin.y && m_lastdoauto.origin.y < ret.origin.y + ret.size.height)
3380 ret.origin.x += (int) m_lastdoauto.size.width;
3383 m_lastdoauto.origin.x = oret.origin.x + oret.size.width;
3384 m_lastdoauto.origin.y = ret.origin.y + ret.size.height*0.5;
3385 m_lastdoauto.size.width=0;
3390 static const double minwidfontadjust=1.81;
3391 #define TRANSFORMFONTSIZE (m_transform.size.width<1?8:m_transform.size.width<2?10:12)
3392 /// these are for swell-dlggen.h
3393 HWND SWELL_MakeButton(int def, const char *label, int idx, int x, int y, int w, int h, int flags)
3395 UINT_PTR a=(UINT_PTR)label;
3396 if (a < 65536) label = "ICONTEMP";
3397 SWELL_Button *button=[[SWELL_Button alloc] init];
3398 [button swellSetRadioFlags:4096];
3399 if (flags & BS_BITMAP)
3401 SWELL_ImageButtonCell * cell = [[SWELL_ImageButtonCell alloc] init];
3402 [button setCell:cell];
3406 if (m_transform.size.width < minwidfontadjust)
3408 [button setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3411 [button setTag:idx];
3413 NSRect tr=MakeCoords(x,y,w,h,true);
3414 if (g_swell_osx_style&1)
3416 [button setBezelStyle:NSRoundedBezelStyle];
3417 if (tr.size.height >= 18 && tr.size.height<24)
3419 tr.origin.y -= floor((24-tr.size.height)*0.5);
3422 tr.size.width += 14;
3427 [button setBezelStyle:NSShadowlessSquareBezelStyle];
3430 [button setFrame:tr];
3431 NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(label);
3432 [button setTitle:labelstr];
3433 [button setTarget:ACTIONTARGET];
3434 [button setAction:@selector(onSwellCommand:)];
3435 if ((flags & BS_XPOSITION_MASK) == BS_LEFT) [button setAlignment:NSLeftTextAlignment];
3436 if (flags&SWELL_NOT_WS_VISIBLE) [button setHidden:YES];
3437 [m_make_owner addSubview:button];
3438 if (m_doautoright) UpdateAutoCoords([button frame]);
3439 if (def) [[m_make_owner window] setDefaultButtonCell:(NSButtonCell*)button];
3442 return (HWND) button;
3446 @implementation SWELL_TextView
3448 STANDARD_CONTROL_NEEDSDISPLAY_IMPL("Edit")
3452 if (NULL != (self = [super init]))
3454 m_disable_menu = false;
3465 -(void) setTag:(NSInteger)tag
3470 -(LRESULT)onSwellMessage:(UINT)msg p1:(WPARAM)wParam p2:(LPARAM)lParam
3475 if (wParam == SB_TOP)
3477 [self scrollRangeToVisible:NSMakeRange(0, 0)];
3479 else if (wParam == SB_BOTTOM)
3481 NSUInteger len = [[self string] length];
3482 [self scrollRangeToVisible:NSMakeRange(len, 0)];
3488 NSUInteger sl = [[self string] length];
3489 if (wParam == -1) lParam = wParam = 0;
3490 else if (lParam == -1) lParam = sl;
3492 if (wParam>sl)wParam=sl;
3493 if (lParam>sl)lParam=sl;
3494 [self setSelectedRange:NSMakeRange(wParam, lParam>wParam ? lParam-wParam : 0)];
3500 NSRange r = [self selectedRange];
3501 if (wParam) *(int*)wParam = (int)r.location;
3502 if (lParam) *(int*)lParam = (int)(r.location+r.length);
3508 NSTextStorage *ts = [self textStorage];
3511 NSRange r = [self selectedRange];
3512 const char *s = (const char *)lParam;
3513 NSString *str = *s ? (NSString*)SWELL_CStringToCFString(s) : NULL;
3515 if (r.length > 0 && !str)
3516 [ts deleteCharactersInRange:r];
3517 else if (str && ![ts length])
3518 [self setString:str]; // dark-mode workaround, need default attributes
3520 [ts replaceCharactersInRange:r withString:str];
3522 if (str) [str release];
3529 NSFont *font = SWELL_GetNSFont((HGDIOBJ__*)wParam);
3530 if (font) [self setFont:font];
3537 - (BOOL)becomeFirstResponder;
3539 BOOL didBecomeFirstResponder = [super becomeFirstResponder];
3540 if (didBecomeFirstResponder) SendMessage(GetParent((HWND)self),WM_COMMAND,MAKELONG([self tag],EN_SETFOCUS),(LPARAM)self);
3541 return didBecomeFirstResponder;
3544 - (void)swellDisableContextMenu:(bool)dis
3546 m_disable_menu = dis;
3549 - (bool)swellWantsContextMenu
3551 return !m_disable_menu;
3555 @implementation SWELL_TextField
3556 STANDARD_CONTROL_NEEDSDISPLAY_IMPL([self isSelectable] ? "Edit" : "Static")
3560 if (NULL != (self = [super init]))
3562 m_disable_menu = false;
3563 m_ctlcolor_set = false;
3564 m_last_dark_mode = false;
3570 - (BOOL)becomeFirstResponder;
3572 BOOL didBecomeFirstResponder = [super becomeFirstResponder];
3573 if (didBecomeFirstResponder) SendMessage(GetParent((HWND)self),WM_COMMAND,MAKELONG([self tag],EN_SETFOCUS),(LPARAM)self);
3574 return didBecomeFirstResponder;
3576 - (void)initColors:(int)darkmode
3580 m_ctlcolor_set = false;
3581 m_last_dark_mode = darkmode ? 1 : 0;
3584 if ([self isEditable])
3586 if (SWELL_osx_is_dark_mode(1))
3588 if (m_last_dark_mode)
3589 [self setBackgroundColor:[NSColor windowBackgroundColor]];
3591 [self setBackgroundColor:[NSColor textBackgroundColor]];
3595 if (g_swell_osx_readonlytext_wndbg)
3596 [self setBackgroundColor:[NSColor textBackgroundColor]];
3599 else if (![self isBordered] && ![self drawsBackground]) // looks like a static text control
3601 const float alpha = ([self isEnabled] ? 1.0f : 0.5f);
3602 [self setTextColor:[[self textColor] colorWithAlphaComponent:alpha]];
3607 if (g_swell_osx_readonlytext_wndbg)
3608 [self setBackgroundColor:[NSColor windowBackgroundColor]];
3612 - (void) drawRect:(NSRect)r
3614 // we could move this to sendSwellMessage if (uMsg == WM_DISPLAYCHANGE), but meh
3615 if (!m_ctlcolor_set && SWELL_osx_is_dark_mode(1))
3617 const bool m = SWELL_osx_is_dark_mode(0);
3618 if (m != m_last_dark_mode) [self initColors:m];
3623 - (void)swellDisableContextMenu:(bool)dis
3625 m_disable_menu = dis;
3628 - (NSMenu *)textView:(NSTextView *)view
3630 forEvent:(NSEvent *)event
3631 atIndex:(NSUInteger)charIndex
3633 return m_disable_menu ? nil : menu;
3636 -(LONG_PTR)getSwellUserData
3640 -(void)setSwellUserData:(LONG_PTR)val
3649 HWND SWELL_MakeEditField(int idx, int x, int y, int w, int h, int flags)
3651 if ((flags&WS_VSCROLL) || (flags&WS_HSCROLL)) // || (flags & ES_READONLY))
3653 SWELL_TextView *obj=[[SWELL_TextView alloc] init];
3654 [obj setAutomaticQuoteSubstitutionEnabled:NO];
3655 [obj setEditable:(flags & ES_READONLY)?NO:YES];
3656 if (m_transform.size.width < minwidfontadjust)
3657 [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3659 [obj setDelegate:ACTIONTARGET];
3660 [obj setRichText:NO];
3662 [obj setHorizontallyResizable:NO];
3664 if (flags & WS_VSCROLL)
3666 NSRect fr=MakeCoords(x,y,w,h,true);
3668 [obj setVerticallyResizable:YES];
3669 NSScrollView *obj2=[[NSScrollView alloc] init];
3670 if (flags&WS_VSCROLL) [obj2 setHasVerticalScroller:YES];
3671 if (flags&WS_HSCROLL)
3673 [obj2 setHasHorizontalScroller:YES];
3674 [obj setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
3675 [obj setHorizontallyResizable:YES];
3676 [[obj textContainer] setWidthTracksTextView:NO];
3677 [[obj textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];
3679 [obj2 setAutohidesScrollers:YES];
3680 [obj2 setDrawsBackground:NO];
3681 [obj2 setDocumentView:obj];
3683 [m_make_owner addSubview:obj2];
3684 if (m_doautoright) UpdateAutoCoords([obj2 frame]);
3685 if (flags&SWELL_NOT_WS_VISIBLE) [obj2 setHidden:YES];
3689 memset(&tr,0,sizeof(tr));
3690 tr.size = [obj2 contentSize];
3698 [obj setFrame:MakeCoords(x,y,w,h,true)];
3699 [obj setVerticallyResizable:NO];
3700 if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3701 [m_make_owner addSubview:obj];
3702 if (m_doautoright) UpdateAutoCoords([obj frame]);
3710 if (flags & ES_PASSWORD) obj=[[NSSecureTextField alloc] init];
3711 else obj=[[SWELL_TextField alloc] init];
3712 [obj setEditable:(flags & ES_READONLY)?NO:YES];
3713 if (flags & ES_READONLY) [obj setSelectable:YES];
3714 if (m_transform.size.width < minwidfontadjust)
3715 [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3717 if ([obj isKindOfClass:[SWELL_TextField class]])
3718 [(SWELL_TextField *)obj initColors:SWELL_osx_is_dark_mode(0)];
3720 NSCell* cell = [obj cell];
3721 if (flags&ES_CENTER) [cell setAlignment:NSCenterTextAlignment];
3722 else if (flags&ES_RIGHT) [cell setAlignment:NSRightTextAlignment];
3726 [cell setScrollable:YES];
3729 [obj setTarget:ACTIONTARGET];
3730 [obj setAction:@selector(onSwellCommand:)];
3731 [obj setDelegate:ACTIONTARGET];
3733 [obj setFrame:MakeCoords(x,y,w,h,true)];
3734 if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3735 [m_make_owner addSubview:obj];
3736 if (m_doautoright) UpdateAutoCoords([obj frame]);
3742 HWND SWELL_MakeLabel( int align, const char *label, int idx, int x, int y, int w, int h, int flags)
3744 NSTextField *obj=[[SWELL_TextField alloc] init];
3745 [obj setEditable:NO];
3746 [obj setSelectable:NO];
3747 [obj setBordered:NO];
3748 [obj setBezeled:NO];
3749 [obj setDrawsBackground:NO];
3750 if (m_transform.size.width < minwidfontadjust)
3751 [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
3753 if (flags & SS_NOTIFY)
3755 [obj setTarget:ACTIONTARGET];
3756 [obj setAction:@selector(onSwellCommand:)];
3759 NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(label);
3760 [obj setStringValue:labelstr];
3761 [obj setAlignment:(align<0?NSLeftTextAlignment:align>0?NSRightTextAlignment:NSCenterTextAlignment)];
3763 [[obj cell] setWraps:(h>12 ? YES : NO)];
3766 [obj setFrame:MakeCoords(x,y,w,h,true)];
3767 if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3768 [m_make_owner addSubview:obj];
3769 if (m_sizetofits && strlen(label)>1)[obj sizeToFit];
3770 if (m_doautoright) UpdateAutoCoords([obj frame]);
3777 HWND SWELL_MakeCheckBox(const char *name, int idx, int x, int y, int w, int h, int flags=0)
3779 return SWELL_MakeControl(name,idx,"Button",BS_AUTOCHECKBOX|flags,x,y,w,h,0);
3782 HWND SWELL_MakeListBox(int idx, int x, int y, int w, int h, int styles)
3784 HWND hw=SWELL_MakeControl("",idx,"SysListView32_LB",styles,x,y,w,h,0);
3789 GetClientRect(hw,&r);
3790 lvc.cx=300;//yer.right-r.left;
3792 ListView_InsertColumn(hw,0,&lvc);
3799 typedef struct ccprocrec
3801 SWELL_ControlCreatorProc proc;
3803 struct ccprocrec *next;
3806 static ccprocrec *m_ccprocs;
3808 void SWELL_RegisterCustomControlCreator(SWELL_ControlCreatorProc proc)
3812 ccprocrec *p=m_ccprocs;
3813 while (p && p->next)
3815 if (p->proc == proc)
3822 ccprocrec *ent = (ccprocrec*)malloc(sizeof(ccprocrec));
3831 void SWELL_UnregisterCustomControlCreator(SWELL_ControlCreatorProc proc)
3836 ccprocrec *p=m_ccprocs;
3839 if (p->proc == proc)
3843 if (lp) lp->next=p->next;
3844 else m_ccprocs=p->next;
3854 static void set_listview_bigsur_style(NSTableView *obj)
3856 if (SWELL_GetOSXVersion() < 0x1100) return;
3857 #if defined(MAC_OS_VERSION_11_0) && (!defined(SWELL_COCOA_WILL_HAVE_PREBIGSUR_SDK) || defined(__aarch64__))
3858 // newer SDKs default to NSTableViewStyleAutomatic
3859 int style = (g_swell_osx_style & 2) ? -1 : 4 /* NSTableViewStylePlain */;
3861 // old SDKs default to something similar to NSTableViewStylePlain
3862 int style = (g_swell_osx_style & 2) ? 0 /* NSTableViewStyleAutomatic */ : -1;
3864 if (style >= 0) [obj setValue:[NSNumber numberWithInt:style] forKey:@"style"];
3868 HWND SWELL_MakeControl(const char *cname, int idx, const char *classname, int style, int x, int y, int w, int h, int exstyle)
3872 NSRect wcr=MakeCoords(x,y,w,h,false);
3873 ccprocrec *p=m_ccprocs;
3876 HWND hwnd=p->proc((HWND)m_make_owner,cname,idx,classname,style,
3877 (int)(wcr.origin.x+0.5),(int)(wcr.origin.y+0.5),(int)(wcr.size.width+0.5),(int)(wcr.size.height+0.5));
3880 if (exstyle) SetWindowLong(hwnd,GWL_EXSTYLE,exstyle);
3886 if (!stricmp(classname,"SysTabControl32"))
3888 SWELL_TabView *obj=[[SWELL_TabView alloc] init];
3889 if (1) // todo: only if on 10.4 maybe?
3895 [obj setDelegate:(id)obj];
3896 [obj setAllowsTruncatedLabels:YES];
3897 [obj setNotificationWindow:ACTIONTARGET];
3899 [obj setFrame:MakeCoords(x,y,w,h,false)];
3900 if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
3901 [m_make_owner addSubview:obj];
3902 SetAllowNoMiddleManRendering((HWND)m_make_owner,FALSE);
3906 else if (!stricmp(classname, "SysListView32")||!stricmp(classname, "SysListView32_LB"))
3908 SWELL_ListView *obj = [[SWELL_ListView alloc] init];
3909 set_listview_bigsur_style(obj);
3910 [obj setColumnAutoresizingStyle:NSTableViewNoColumnAutoresizing];
3911 [obj setFocusRingType:NSFocusRingTypeNone];
3912 [obj setDataSource:(id)obj];
3915 BOOL isLB=!stricmp(classname, "SysListView32_LB");
3916 [obj setSwellNotificationMode:isLB];
3920 [obj setHeaderView:nil];
3921 [obj setAllowsMultipleSelection:!!(style & LBS_EXTENDEDSEL)];
3925 if ((style & LVS_NOCOLUMNHEADER) || !(style & LVS_REPORT)) [obj setHeaderView:nil];
3926 [obj setAllowsMultipleSelection:!(style & LVS_SINGLESEL)];
3928 [obj setAllowsColumnReordering:NO];
3929 [obj setAllowsEmptySelection:YES];
3932 id target=ACTIONTARGET;
3933 [obj setDelegate:target];
3934 [obj setTarget:target];
3935 [obj setAction:@selector(onSwellCommand:)];
3936 if ([target respondsToSelector:@selector(swellOnControlDoubleClick:)])
3938 [obj setDoubleAction:@selector(swellOnControlDoubleClick:)];
3942 [obj setDoubleAction:@selector(onSwellCommand:)];
3944 NSScrollView *obj2=[[NSScrollView alloc] init];
3945 NSRect tr=MakeCoords(x,y,w,h,false);
3947 [obj2 setDocumentView:obj];
3948 [obj2 setHasVerticalScroller:YES];
3949 if (!isLB) [obj2 setHasHorizontalScroller:YES];
3950 [obj2 setAutohidesScrollers:YES];
3951 [obj2 setDrawsBackground:NO];
3953 if (style&SWELL_NOT_WS_VISIBLE) [obj2 setHidden:YES];
3954 [m_make_owner addSubview:obj2];
3957 if (isLB || !(style & LVS_REPORT))
3960 lvc.mask=LVCF_TEXT|LVCF_WIDTH;
3961 lvc.cx=(int)ceil(wdl_max(tr.size.width - 4.0,isLB ? 1200.0 : 300.0));
3962 lvc.pszText=(char*)"";
3963 ListView_InsertColumn((HWND)obj,0,&lvc);
3964 if (isLB && (style & LBS_OWNERDRAWFIXED))
3966 NSArray *ar=[obj tableColumns];
3968 if (ar && [ar count] && (c=[ar objectAtIndex:0]))
3970 SWELL_ODListViewCell *t=[[SWELL_ODListViewCell alloc] init];
3972 [t setOwnerControl:obj];
3980 else if (!stricmp(classname, "SysTreeView32"))
3982 SWELL_TreeView *obj = [[SWELL_TreeView alloc] init];
3983 set_listview_bigsur_style(obj);
3984 [obj setFocusRingType:NSFocusRingTypeNone];
3985 [obj setDataSource:(id)obj];
3987 id target=ACTIONTARGET;
3988 [obj setHeaderView:nil];
3989 [obj setDelegate:target];
3990 [obj setAllowsColumnReordering:NO];
3991 [obj setAllowsMultipleSelection:NO];
3992 [obj setAllowsEmptySelection:YES];
3995 [obj setTarget:target];
3996 [obj setAction:@selector(onSwellCommand:)];
3997 if ([target respondsToSelector:@selector(swellOnControlDoubleClick:)])
3998 [obj setDoubleAction:@selector(swellOnControlDoubleClick:)];
4000 [obj setDoubleAction:@selector(onSwellCommand:)];
4001 NSScrollView *obj2=[[NSScrollView alloc] init];
4002 NSRect tr=MakeCoords(x,y,w,h,false);
4004 [obj2 setDocumentView:obj];
4005 [obj2 setHasVerticalScroller:YES];
4006 [obj2 setAutohidesScrollers:YES];
4007 [obj2 setDrawsBackground:NO];
4009 if (style&SWELL_NOT_WS_VISIBLE) [obj2 setHidden:YES];
4010 [m_make_owner addSubview:obj2];
4014 NSTableColumn *col=[[NSTableColumn alloc] init];
4015 SWELL_ListViewCell *cell = [[SWELL_ListViewCell alloc] initTextCell:@""];
4016 [col setDataCell:cell];
4019 [col setWidth:(int)ceil(wdl_max(tr.size.width,300.0))];
4020 [col setEditable:NO];
4021 [[col dataCell] setWraps:NO];
4022 [obj addTableColumn:col];
4023 [obj setOutlineTableColumn:col];
4027 /// [obj setIndentationPerLevel:10.0];
4031 else if (!stricmp(classname, "msctls_progress32"))
4033 SWELL_ProgressView *obj=[[SWELL_ProgressView alloc] init];
4034 [obj setStyle:NSProgressIndicatorBarStyle];
4035 [obj setIndeterminate:NO];
4037 [obj setFrame:MakeCoords(x,y,w,h,false)];
4038 if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
4039 [m_make_owner addSubview:obj];
4043 else if (!stricmp(classname,"Edit"))
4045 return SWELL_MakeEditField(idx,x,y,w,h,style);
4047 else if (!stricmp(classname, "Static"))
4049 if ((style&SS_TYPEMASK) == SS_ETCHEDHORZ || (style&SS_TYPEMASK) == SS_ETCHEDVERT || (style&SS_TYPEMASK) == SS_ETCHEDFRAME)
4051 SWELL_BoxView *obj=[[SWELL_BoxView alloc] init];
4052 obj->m_etch_mode = style & SS_TYPEMASK;
4054 [obj setFrame:MakeCoords(x,y,w,h,false)];
4055 [m_make_owner addSubview:obj];
4059 NSTextField *obj=[[SWELL_TextField alloc] init];
4060 [obj setEditable:NO];
4061 [obj setSelectable:NO];
4062 [obj setBordered:NO];
4063 [obj setBezeled:NO];
4064 [obj setDrawsBackground:NO];
4065 if (m_transform.size.width < minwidfontadjust)
4066 [obj setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
4068 if (cname && *cname)
4070 NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(cname);
4071 [obj setStringValue:labelstr];
4075 if ((style&SS_TYPEMASK) == SS_LEFTNOWORDWRAP) [[obj cell] setWraps:NO];
4076 else if ((style&SS_TYPEMASK) == SS_CENTER) [[obj cell] setAlignment:NSCenterTextAlignment];
4077 else if ((style&SS_TYPEMASK) == SS_RIGHT) [[obj cell] setAlignment:NSRightTextAlignment];
4080 [obj setFrame:MakeCoords(x,y,w,h,true)];
4081 if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
4082 [m_make_owner addSubview:obj];
4083 if ((style & SS_TYPEMASK) == SS_BLACKRECT)
4085 [obj setHidden:YES];
4090 else if (!stricmp(classname,"Button"))
4092 if (style & BS_GROUPBOX)
4094 return SWELL_MakeGroupBox(cname, idx, x, y, w, h, style &~BS_GROUPBOX);
4096 if (style & BS_DEFPUSHBUTTON)
4098 return SWELL_MakeButton(1, cname, idx, x,y,w,h,style &~BS_DEFPUSHBUTTON);
4100 if (style & BS_PUSHBUTTON)
4102 return SWELL_MakeButton(0, cname, idx, x,y,w,h,style &~BS_PUSHBUTTON);
4104 SWELL_Button *button=[[SWELL_Button alloc] init];
4105 [button setTag:idx];
4106 NSRect fr=MakeCoords(x,y,w,h,true);
4107 SEL actionSel = @selector(onSwellCommand:);
4108 if ((style & 0xf) == BS_AUTO3STATE)
4110 [button setButtonType:NSSwitchButton];
4111 [button setAllowsMixedState:YES];
4113 else if ((style & 0xf) == BS_AUTOCHECKBOX)
4115 [button setButtonType:NSSwitchButton];
4116 [button setAllowsMixedState:NO];
4118 else if ((style & 0xf) == BS_AUTORADIOBUTTON)
4120 #ifdef MAC_OS_X_VERSION_10_8
4121 // Compiling with the OSX 10.8+ SDK and running on 10.8+ causes radio buttons with a common action selector to
4122 // be treated as a group. This works around that. if you need more than 8 groups (seriously?!), add the extra
4123 // functions in swell-dlg.mm and in the switch below
4127 if ((style & WS_GROUP) ||
4128 !(sv = [m_make_owner subviews]) ||
4130 !(v = [sv lastObject]) ||
4131 ![v isKindOfClass:[SWELL_Button class]] ||
4132 ([(SWELL_Button *)v swellGetRadioFlags]&2)) m_make_radiogroupcnt++;
4134 switch (m_make_radiogroupcnt & 7)
4136 case 0: actionSel = @selector(onSwellCommand0:); break;
4137 case 1: break; // default
4138 case 2: actionSel = @selector(onSwellCommand2:); break;
4139 case 3: actionSel = @selector(onSwellCommand3:); break;
4140 case 4: actionSel = @selector(onSwellCommand4:); break;
4141 case 5: actionSel = @selector(onSwellCommand5:); break;
4142 case 6: actionSel = @selector(onSwellCommand6:); break;
4143 case 7: actionSel = @selector(onSwellCommand7:); break;
4147 [button setButtonType:NSRadioButton];
4148 [button swellSetRadioFlags:(style & WS_GROUP)?3:1];
4150 else if ((style & 0xf) == BS_OWNERDRAW)
4152 SWELL_ODButtonCell *cell = [[SWELL_ODButtonCell alloc] init];
4153 [button setCell:cell];
4156 [button swellSetRadioFlags:4096];
4158 else // normal button
4160 if (style & BS_BITMAP)
4162 SWELL_ImageButtonCell * cell = [[SWELL_ImageButtonCell alloc] init];
4163 [button setCell:cell];
4166 if ((style & BS_XPOSITION_MASK) == BS_LEFT) [button setAlignment:NSLeftTextAlignment];
4167 // fr.size.width+=8;
4168 [button swellSetRadioFlags:4096];
4171 if (m_transform.size.width < minwidfontadjust)
4172 [button setFont:[NSFont systemFontOfSize:TRANSFORMFONTSIZE]];
4173 [button setFrame:fr];
4174 NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(cname);
4175 [button setTitle:labelstr];
4176 [button setTarget:ACTIONTARGET];
4177 [button setAction:actionSel];
4178 if (style&BS_LEFTTEXT) [button setImagePosition:NSImageRight];
4179 if (style&SWELL_NOT_WS_VISIBLE) [button setHidden:YES];
4180 [m_make_owner addSubview:button];
4181 if (m_sizetofits && (style & 0xf) != BS_OWNERDRAW) [button sizeToFit];
4182 if (m_doautoright) UpdateAutoCoords([button frame]);
4185 return (HWND)button;
4187 else if (!stricmp(classname,"REAPERhfader")||!stricmp(classname,"msctls_trackbar32"))
4189 NSSlider *obj=[[NSSlider alloc] init];
4191 [obj setMinValue:0.0];
4192 [obj setMaxValue:1000.0];
4193 [obj setFrame:MakeCoords(x,y,w,h,false)];
4194 if (!stricmp(classname, "msctls_trackbar32"))
4196 [[obj cell] setControlSize:NSMiniControlSize];
4198 [obj setTarget:ACTIONTARGET];
4199 [obj setAction:@selector(onSwellCommand:)];
4200 if (style&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
4201 [m_make_owner addSubview:obj];
4205 else if (!stricmp(classname,"COMBOBOX"))
4207 return SWELL_MakeCombo(idx, x, y, w, h, style);
4212 HWND SWELL_MakeCombo(int idx, int x, int y, int w, int h, int flags)
4214 if ((flags & 0x3) == CBS_DROPDOWNLIST)
4216 SWELL_PopUpButton *obj=[[SWELL_PopUpButton alloc] init];
4218 [obj setFont:[NSFont systemFontOfSize:10.0f]];
4219 NSRect rc=MakeCoords(x,y,w,(g_swell_osx_style&1) ? 24 : 18,true,true);
4220 if (g_swell_osx_style&1) rc.origin.y -= 2;
4222 [obj setSwellStyle:flags];
4224 [obj setAutoenablesItems:NO];
4225 [obj setTarget:ACTIONTARGET];
4226 [obj setAction:@selector(onSwellCommand:)];
4228 if (!(g_swell_osx_style&1))
4230 [obj setBezelStyle:NSShadowlessSquareBezelStyle ];
4231 [[obj cell] setArrowPosition:NSPopUpArrowAtBottom];
4233 if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
4234 [m_make_owner addSubview:obj];
4235 if (m_doautoright) UpdateAutoCoords([obj frame]);
4241 SWELL_ComboBox *obj=[[SWELL_ComboBox alloc] init];
4242 [obj setFocusRingType:NSFocusRingTypeNone];
4243 [obj setFont:[NSFont systemFontOfSize:10.0f]];
4244 [obj setEditable:(flags & 0x3) == CBS_DROPDOWNLIST?NO:YES];
4245 [obj setSwellStyle:flags];
4247 [obj setFrame:MakeCoords(x,y-1,w,22,true,true)];
4248 [obj setTarget:ACTIONTARGET];
4249 [obj setAction:@selector(onSwellCommand:)];
4250 [obj setDelegate:ACTIONTARGET];
4251 if (flags&SWELL_NOT_WS_VISIBLE) [obj setHidden:YES];
4252 [m_make_owner addSubview:obj];
4253 if (m_doautoright) UpdateAutoCoords([obj frame]);
4259 @implementation SWELL_BoxView
4261 STANDARD_CONTROL_NEEDSDISPLAY_IMPL(m_etch_mode ? "Static" : "Button")
4267 -(void) setTag:(NSInteger)tag
4272 -(void) drawRect:(NSRect) r
4274 // m_etch_mode override?
4277 -(int)swellIsEtchBox
4284 HWND SWELL_MakeGroupBox(const char *name, int idx, int x, int y, int w, int h, int style)
4286 SWELL_BoxView *obj=[[SWELL_BoxView alloc] init];
4287 obj->m_etch_mode = 0;
4289 // this just doesn't work, you can't color the border unless it's NSBoxCustom,
4290 // and I can't get it to show the title text if it's NSBoxCustom
4291 //[obj setBoxType:(NSBoxType)4]; // NSBoxCustom, so we can color the border
4292 //[obj setTitlePosition:(NSTitlePosition)2]; // NSAtTop, default but NSBoxCustom unsets it
4294 // [obj setTag:idx];
4295 if (1) // todo: only if on 10.4 maybe?
4300 NSString *labelstr=(NSString *)SWELL_CStringToCFString_FilterPrefix(name);
4301 [obj setTitle:labelstr];
4304 if ((style & BS_XPOSITION_MASK) == BS_CENTER)
4306 [[obj titleCell] setAlignment:NSCenterTextAlignment];
4308 [obj setFrame:MakeCoords(x,y,w,h,false)];
4309 [m_make_owner addSubview:obj positioned:NSWindowBelow relativeTo:nil];
4315 int TabCtrl_GetItemCount(HWND hwnd)
4317 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]])) return 0;
4318 SWELL_TabView *tv=(SWELL_TabView*)hwnd;
4319 return (int)[tv numberOfTabViewItems];
4322 BOOL TabCtrl_AdjustRect(HWND hwnd, BOOL fLarger, RECT *r)
4324 if (WDL_NOT_NORMALLY(!r || !hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]])) return FALSE;
4326 int sign=fLarger?-1:1;
4327 r->left+=sign*7; // todo: correct this?
4335 BOOL TabCtrl_DeleteItem(HWND hwnd, int idx)
4337 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]])) return 0;
4338 SWELL_TabView *tv=(SWELL_TabView*)hwnd;
4339 if (idx<0 || idx>= [tv numberOfTabViewItems]) return 0;
4340 [tv removeTabViewItem:[tv tabViewItemAtIndex:idx]];
4344 int TabCtrl_InsertItem(HWND hwnd, int idx, TCITEM *item)
4346 if (WDL_NOT_NORMALLY(!item || !hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]])) return -1;
4347 if (!(item->mask & TCIF_TEXT) || !item->pszText) return -1;
4348 SWELL_TabView *tv=(SWELL_TabView*)hwnd;
4350 const int ni = (int)[tv numberOfTabViewItems];
4352 else if (idx>ni) idx=ni;
4354 NSTabViewItem *tabitem=[[NSTabViewItem alloc] init];
4355 NSString *str=(NSString *)SWELL_CStringToCFString(item->pszText);
4356 [tabitem setLabel:str];
4358 id turd=[tv getNotificationWindow];
4359 [tv setNotificationWindow:nil];
4360 [tv insertTabViewItem:tabitem atIndex:idx];
4361 [tv setNotificationWindow:turd];
4366 int TabCtrl_SetCurSel(HWND hwnd, int idx)
4368 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]])) return -1;
4369 SWELL_TabView *tv=(SWELL_TabView*)hwnd;
4370 int ret=TabCtrl_GetCurSel(hwnd);
4371 if (idx>=0 && idx < [tv numberOfTabViewItems])
4373 [tv selectTabViewItemAtIndex:idx];
4378 int TabCtrl_GetCurSel(HWND hwnd)
4380 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TabView class]])) return 0;
4381 SWELL_TabView *tv=(SWELL_TabView*)hwnd;
4382 NSTabViewItem *item=[tv selectedTabViewItem];
4383 if (!item) return 0;
4384 return (int)[tv indexOfTabViewItem:item];
4387 void ListView_SetExtendedListViewStyleEx(HWND h, int mask, int style)
4389 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return;
4390 SWELL_ListView *tv=(SWELL_ListView*)h;
4392 if (mask & LVS_EX_SUBITEMIMAGES)
4394 tv->m_subitem_images = (style & LVS_EX_SUBITEMIMAGES) != 0;
4397 if (mask&LVS_EX_GRIDLINES)
4400 if (style&LVS_EX_GRIDLINES)
4402 s=NSTableViewSolidVerticalGridLineMask|NSTableViewSolidHorizontalGridLineMask;
4404 [tv setGridStyleMask:s];
4407 if (mask&LVS_EX_HEADERDRAGDROP)
4409 [tv setAllowsColumnReordering:!!(style&LVS_EX_HEADERDRAGDROP)];
4413 // todo LVS_EX_FULLROWSELECT (enabled by default on OSX)
4416 void SWELL_SetListViewFastClickMask(HWND hList, int mask)
4418 if (WDL_NOT_NORMALLY(!hList || ![(id)hList isKindOfClass:[SWELL_ListView class]])) return;
4419 SWELL_ListView *lv = (SWELL_ListView *)hList;
4420 lv->m_fastClickMask=mask;
4425 void ListView_SetImageList(HWND h, HIMAGELIST imagelist, int which)
4427 if (WDL_NOT_NORMALLY(!h)) return;
4429 SWELL_ListView *v=(SWELL_ListView *)h;
4431 v->m_status_imagelist_type=which;
4432 v->m_status_imagelist=(WDL_PtrList<HGDIOBJ__> *)imagelist;
4435 for (int x = 0; x < v->m_cols->GetSize(); x ++)
4437 NSTableColumn *col=(NSTableColumn*)v->m_cols->Get(x);
4438 if (![col isKindOfClass:[SWELL_StatusCell class]])
4440 SWELL_StatusCell *cell=[[SWELL_StatusCell alloc] initNewCell:!x];
4441 NSTextFieldCell *oldcell = [col dataCell];
4442 if (oldcell) [cell setAlignment:[oldcell alignment]];
4445 [col setDataCell:cell];
4448 if (!v->m_subitem_images)
4454 int ListView_GetColumnWidth(HWND h, int pos)
4456 if (!h || ![(id)h isKindOfClass:[SWELL_ListView class]]) return 0;
4457 SWELL_ListView *v=(SWELL_ListView *)h;
4458 if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return 0;
4460 NSTableColumn *col=v->m_cols->Get(pos);
4463 if ([col respondsToSelector:@selector(isHidden)] && [(SWELL_TableColumnExtensions*)col isHidden]) return 0;
4464 return (int) floor(0.5+[col width]);
4467 void ListView_InsertColumn(HWND h, int pos, const LVCOLUMN *lvc)
4469 if (WDL_NOT_NORMALLY(!h || !lvc || ![(id)h isKindOfClass:[SWELL_ListView class]])) return;
4473 SWELL_ListView *v=(SWELL_ListView *)h;
4474 NSTableColumn *col=[[NSTableColumn alloc] init];
4475 // note, not looking at lvc->mask at all
4477 [col setEditable:NO];
4478 // [col setResizingMask:2]; // user resizable, this seems to be the default
4480 if (lvc->fmt == LVCFMT_CENTER) [[col headerCell] setAlignment:NSCenterTextAlignment];
4481 else if (lvc->fmt == LVCFMT_RIGHT) [[col headerCell] setAlignment:NSRightTextAlignment];
4483 if (!v->m_lbMode && !(v->style & LVS_NOCOLUMNHEADER))
4485 NSString *lbl=(NSString *)SWELL_CStringToCFString(lvc->pszText);
4486 [[col headerCell] setStringValue:lbl];
4490 SWELL_ListViewCell *cell;
4491 if ((!pos || v->m_subitem_images) && v->m_status_imagelist)
4493 cell = [[SWELL_StatusCell alloc] initNewCell:!pos];
4497 cell = [[SWELL_ListViewCell alloc] initTextCell:@""];
4500 if (lvc->fmt == LVCFMT_CENTER) [cell setAlignment:NSCenterTextAlignment];
4501 else if (lvc->fmt == LVCFMT_RIGHT) [cell setAlignment:NSRightTextAlignment];
4502 [col setDataCell:cell];
4505 [v addTableColumn:col];
4506 if (pos >= 0 && pos < v->m_cols->GetSize())
4508 [v moveColumn:v->m_cols->GetSize() toColumn:pos];
4509 v->m_cols->Insert(pos,col);
4513 v->m_cols->Add(col);
4517 if (lvc->mask&LVCF_WIDTH)
4519 ListView_SetColumnWidth(h,pos,lvc->cx);
4524 void ListView_SetColumn(HWND h, int pos, const LVCOLUMN *lvc)
4526 if (WDL_NOT_NORMALLY(!h || !lvc || ![(id)h isKindOfClass:[SWELL_ListView class]])) return;
4527 SWELL_ListView *v=(SWELL_ListView *)h;
4528 if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return;
4530 NSTableColumn *col=v->m_cols->Get(pos);
4533 if (lvc->mask&LVCF_FMT)
4535 NSTextAlignment align = lvc->fmt == LVCFMT_CENTER ? NSCenterTextAlignment :
4536 lvc->fmt == LVCFMT_RIGHT ? NSRightTextAlignment : NSLeftTextAlignment;
4537 [[col headerCell] setAlignment:align];
4538 [[col dataCell] setAlignment:align];
4540 if (lvc->mask&LVCF_WIDTH)
4544 if ([col respondsToSelector:@selector(setHidden:)]) [(SWELL_TableColumnExtensions*)col setHidden:YES];
4548 if ([col respondsToSelector:@selector(setHidden:)]) [(SWELL_TableColumnExtensions*)col setHidden:NO];
4549 [col setWidth:lvc->cx];
4552 if (lvc->mask&LVCF_TEXT)
4554 if (!v->m_lbMode && !(v->style&LVS_NOCOLUMNHEADER))
4556 NSString *lbl=(NSString *)SWELL_CStringToCFString(lvc->pszText);
4557 [[col headerCell] setStringValue:lbl];
4563 bool ListView_DeleteColumn(HWND h, int pos)
4565 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return false;
4566 SWELL_ListView *v=(SWELL_ListView *)h;
4567 if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return false;
4568 [v removeTableColumn:v->m_cols->Get(pos)];
4569 v->m_cols->Delete(pos);
4573 void ListView_GetItemText(HWND hwnd, int item, int subitem, char *text, int textmax)
4575 LVITEM it={LVIF_TEXT,item,subitem,0,0,text,textmax,};
4576 ListView_GetItem(hwnd,&it);
4579 int ListView_InsertItem(HWND h, const LVITEM *item)
4581 if (WDL_NOT_NORMALLY(!h || !item || item->iSubItem || ![(id)h isKindOfClass:[SWELL_ListView class]])) return 0;
4583 SWELL_ListView *tv=(SWELL_ListView*)h;
4584 if (WDL_NOT_NORMALLY(!tv->m_lbMode && (tv->style & LVS_OWNERDATA))) return -1;
4585 if (WDL_NOT_NORMALLY(!tv->m_items)) return -1;
4589 else if (a > tv->m_items->GetSize()) a=tv->m_items->GetSize();
4591 if (!tv->m_lbMode && (item->mask & LVIF_TEXT))
4593 if (tv->style & LVS_SORTASCENDING)
4595 a=ptrlist_bsearch_mod((char *)item->pszText,tv->m_items,_listviewrowSearchFunc,NULL);
4597 else if (tv->style & LVS_SORTDESCENDING)
4599 a=ptrlist_bsearch_mod((char *)item->pszText,tv->m_items,_listviewrowSearchFunc2,NULL);
4603 SWELL_ListView_Row *nr=new SWELL_ListView_Row;
4604 nr->add_col((item->mask & LVIF_TEXT) ? item->pszText : "");
4605 if (item->mask & LVIF_PARAM) nr->m_param = item->lParam;
4606 tv->m_items->Insert(a,nr);
4610 if ((item->mask&LVIF_STATE) && (item->stateMask & (0xff<<16)))
4612 nr->set_img_idx(0,(item->state>>16)&0xff);
4617 if (a < tv->m_items->GetSize()-1)
4619 NSIndexSet *sel=[tv selectedRowIndexes];
4620 if (sel && [sel count])
4622 NSMutableIndexSet *ms = [[NSMutableIndexSet alloc] initWithIndexSet:sel];
4623 [ms shiftIndexesStartingAtIndex:a by:1];
4624 [tv selectRowIndexes:ms byExtendingSelection:NO];
4629 if (item->mask & LVIF_STATE)
4631 if (item->stateMask & LVIS_SELECTED)
4633 if (item->state&LVIS_SELECTED)
4635 bool isSingle = tv->m_lbMode ? !(tv->style & LBS_EXTENDEDSEL) : !!(tv->style&LVS_SINGLESEL);
4636 [tv selectRowIndexes:[NSIndexSet indexSetWithIndex:a] byExtendingSelection:isSingle?NO:YES];
4644 void ListView_SetItemText(HWND h, int ipos, int cpos, const char *txt)
4646 if (WDL_NOT_NORMALLY(!h || cpos < 0)) return;
4647 if (WDL_NOT_NORMALLY(![(id)h isKindOfClass:[SWELL_ListView class]])) return;
4649 SWELL_ListView *tv=(SWELL_ListView*)h;
4650 if (WDL_NOT_NORMALLY(!tv->m_lbMode && (tv->style & LVS_OWNERDATA))) return;
4651 if (WDL_NOT_NORMALLY(!tv->m_items || !tv->m_cols)) return;
4653 if (WDL_NOT_NORMALLY(cpos && cpos >= tv->m_cols->GetSize())) return; // always allow setting the first
4655 SWELL_ListView_Row *p=tv->m_items->Get(ipos);
4658 for (x = p->get_num_cols(); x < cpos; x ++)
4662 if (cpos < p->get_num_cols())
4664 p->set_col_txt(cpos,strdup(txt));
4666 else p->add_col(txt);
4668 [tv setNeedsDisplay];
4671 int ListView_GetNextItem(HWND h, int istart, int flags)
4673 if (WDL_NORMALLY(flags==LVNI_FOCUSED||flags==LVNI_SELECTED))
4675 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return -1;
4677 SWELL_ListView *tv=(SWELL_ListView*)h;
4679 if (flags==LVNI_SELECTED)
4681 //int orig_start=istart;
4682 if (istart++<0)istart=0;
4683 const int n = (int)[tv numberOfRows];
4686 if ([tv isRowSelected:istart]) return istart;
4692 return (int)[tv selectedRow];
4697 bool ListView_SetItem(HWND h, LVITEM *item)
4699 if (WDL_NOT_NORMALLY(!item || !h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return false;
4701 SWELL_ListView *tv=(SWELL_ListView*)h;
4702 if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4704 if (WDL_NOT_NORMALLY(!tv->m_items)) return false;
4705 SWELL_ListView_Row *row=tv->m_items->Get(item->iItem);
4706 if (WDL_NOT_NORMALLY(!row)) return false;
4708 if (item->mask & LVIF_PARAM)
4710 row->m_param=item->lParam;
4712 if ((item->mask & LVIF_TEXT) && item->pszText)
4714 ListView_SetItemText(h,item->iItem,item->iSubItem,item->pszText);
4716 if ((item->mask&LVIF_IMAGE) && item->iImage >= 0)
4718 row->set_img_idx(item->iSubItem,item->iImage+1);
4719 ListView_RedrawItems(h, item->iItem, item->iItem);
4722 if ((item->mask & LVIF_STATE) && item->stateMask)
4724 ListView_SetItemState(h,item->iItem,item->state,item->stateMask);
4730 bool ListView_GetItem(HWND h, LVITEM *item)
4732 if (WDL_NOT_NORMALLY(!item)) return false;
4733 if ((item->mask&LVIF_TEXT)&&item->pszText && item->cchTextMax > 0) item->pszText[0]=0;
4735 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return false;
4737 SWELL_ListView *tv=(SWELL_ListView*)h;
4738 if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4740 if (!tv->m_items) return false;
4742 SWELL_ListView_Row *row=tv->m_items->Get(item->iItem);
4743 if (!row) return false;
4745 if (item->mask & LVIF_PARAM) item->lParam=row->m_param;
4746 if (item->mask & LVIF_TEXT) if (item->pszText && item->cchTextMax>0)
4748 const char *p=row->get_col_txt(item->iSubItem);
4749 lstrcpyn_safe(item->pszText,p?p:"",item->cchTextMax);
4751 if (item->mask & LVIF_STATE)
4753 if (item->stateMask & (0xff<<16))
4755 item->state|=row->get_img_idx(item->iSubItem)<<16;
4761 if (item->iItem <0 || item->iItem >= tv->ownermode_cnt) return false;
4763 int mask = item->mask & (LVIF_PARAM|LVIF_TEXT);
4764 if (mask & LVIF_TEXT)
4766 if (!item->pszText || item->cchTextMax < 1) mask &= ~LVIF_TEXT;
4767 else *item->pszText = 0;
4771 NMLVDISPINFO nm={{(HWND)tv, (UINT_PTR)[tv tag], LVN_GETDISPINFO}};
4772 nm.item.mask = mask;
4773 nm.item.iItem = item->iItem;
4774 nm.item.iSubItem = item->iSubItem;
4775 nm.item.pszText = item->pszText;
4776 nm.item.cchTextMax = item->cchTextMax;
4777 SendMessage(GetParent(h),WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
4778 if (mask & LVIF_PARAM) item->lParam = nm.item.lParam;
4781 if (item->mask & LVIF_STATE)
4783 if ((item->stateMask&LVIS_SELECTED) && [tv isRowSelected:item->iItem]) item->state|=LVIS_SELECTED;
4784 if ((item->stateMask&LVIS_FOCUSED) && [tv selectedRow] == item->iItem) item->state|=LVIS_FOCUSED;
4789 int ListView_GetItemState(HWND h, int ipos, UINT mask)
4791 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return 0;
4792 SWELL_ListView *tv=(SWELL_ListView*)h;
4794 if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4796 if (!tv->m_items) return 0;
4797 SWELL_ListView_Row *row=tv->m_items->Get(ipos);
4799 if (mask & (0xff<<16))
4801 flag|=row->get_img_idx(0)<<16;
4806 if (ipos<0 || ipos >= tv->ownermode_cnt) return 0;
4809 if ((mask&LVIS_SELECTED) && [tv isRowSelected:ipos]) flag|=LVIS_SELECTED;
4810 if ((mask&LVIS_FOCUSED) && [tv selectedRow]==ipos) flag|=LVIS_FOCUSED;
4814 int swell_ignore_listview_changes;
4816 bool ListView_SetItemState(HWND h, int ipos, UINT state, UINT statemask)
4819 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return false;
4820 SWELL_ListView *tv=(SWELL_ListView*)h;
4821 static int _is_doing_all;
4822 const bool isSingle = tv->m_lbMode ? !(tv->style & LBS_EXTENDEDSEL) : !!(tv->style&LVS_SINGLESEL);
4827 int n=ListView_GetItemCount(h);
4828 NSIndexSet *oldSelection = NULL;
4829 if (statemask & LVIS_SELECTED)
4831 oldSelection = [tv selectedRowIndexes];
4832 [oldSelection retain];
4833 if (state & LVIS_SELECTED)
4837 statemask &= ~LVIS_SELECTED; // no-op and don't send LVN_ITEMCHANGED
4841 swell_ignore_listview_changes++;
4843 swell_ignore_listview_changes--;
4848 swell_ignore_listview_changes++;
4849 [tv deselectAll:nil];
4850 swell_ignore_listview_changes--;
4854 for (x = 0; x < n; x ++)
4856 if (statemask & ~LVIS_SELECTED)
4857 ListView_SetItemState(h,x,state,statemask & ~LVIS_SELECTED);
4859 if (statemask & LVIS_SELECTED)
4861 if ([oldSelection containsIndex:x] == !(state & LVIS_SELECTED))
4867 NMLISTVIEW nm={{(HWND)h,(UINT_PTR)[tv tag],LVN_ITEMCHANGED},x,0,state,};
4868 SendMessage(GetParent(h),WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
4874 [oldSelection release];
4876 ListView_RedrawItems(h,0,n-1);
4880 if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
4882 if (!tv->m_items) return false;
4883 SWELL_ListView_Row *row=tv->m_items->Get(ipos);
4884 if (!row) return false;
4885 if (statemask & (0xff<<16))
4887 if (row->get_img_idx(0)!=((state>>16)&0xff))
4889 row->set_img_idx(0,(state>>16)&0xff);
4896 if (ipos<0 || ipos >= tv->ownermode_cnt) return 0;
4899 if (statemask & LVIS_SELECTED)
4901 if (state & LVIS_SELECTED)
4903 if (![tv isRowSelected:ipos])
4906 swell_ignore_listview_changes++;
4907 [tv selectRowIndexes:[NSIndexSet indexSetWithIndex:ipos] byExtendingSelection:isSingle?NO:YES];
4908 swell_ignore_listview_changes--;
4913 if ([tv isRowSelected:ipos])
4916 swell_ignore_listview_changes++;
4917 [tv deselectRow:ipos];
4918 swell_ignore_listview_changes--;
4922 if (statemask & LVIS_FOCUSED)
4924 if (state&LVIS_FOCUSED)
4941 NMLISTVIEW nm={{(HWND)h,(UINT_PTR)[tv tag],LVN_ITEMCHANGED},ipos,0,state,};
4942 SendMessage(GetParent(h),WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
4947 ListView_RedrawItems(h,ipos,ipos);
4952 void ListView_RedrawItems(HWND h, int startitem, int enditem)
4954 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return;
4955 SWELL_ListView *tv=(SWELL_ListView*)h;
4956 if (!tv->m_items) return;
4960 void ListView_DeleteItem(HWND h, int ipos)
4962 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return;
4964 SWELL_ListView *tv=(SWELL_ListView*)h;
4965 if (!tv->m_items) return;
4967 if (ipos >=0 && ipos < tv->m_items->GetSize())
4969 if (ipos != tv->m_items->GetSize()-1)
4971 NSIndexSet *sel=[tv selectedRowIndexes];
4972 if (sel && [sel count])
4974 NSMutableIndexSet *ms = [[NSMutableIndexSet alloc] initWithIndexSet:sel];
4975 [ms shiftIndexesStartingAtIndex:ipos+1 by:-1];
4976 [tv selectRowIndexes:ms byExtendingSelection:NO];
4980 tv->m_items->Delete(ipos,true);
4987 void ListView_DeleteAllItems(HWND h)
4989 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return;
4991 SWELL_ListView *tv=(SWELL_ListView*)h;
4992 tv->ownermode_cnt=0;
4993 if (tv->m_items) tv->m_items->Empty(true);
4998 int ListView_GetSelectedCount(HWND h)
5000 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return 0;
5002 SWELL_ListView *tv=(SWELL_ListView*)h;
5003 return (int)[tv numberOfSelectedRows];
5006 int ListView_GetItemCount(HWND h)
5008 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return 0;
5010 SWELL_ListView *tv=(SWELL_ListView*)h;
5011 if (tv->m_lbMode || !(tv->style & LVS_OWNERDATA))
5013 if (!tv->m_items) return 0;
5015 return tv->m_items->GetSize();
5017 return tv->ownermode_cnt;
5020 int ListView_GetSelectionMark(HWND h)
5022 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return 0;
5024 SWELL_ListView *tv=(SWELL_ListView*)h;
5025 return (int)[tv selectedRow];
5028 int SWELL_GetListViewHeaderHeight(HWND h)
5030 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return 0;
5032 SWELL_ListView* tv=(SWELL_ListView*)h;
5033 NSTableHeaderView* hv=[tv headerView];
5034 NSRect r=[hv bounds];
5035 return (int)(r.size.height+0.5);
5038 void ListView_SetColumnWidth(HWND h, int pos, int wid)
5040 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return;
5041 SWELL_ListView *v=(SWELL_ListView *)h;
5042 if (!v->m_cols || pos < 0 || pos >= v->m_cols->GetSize()) return;
5044 NSTableColumn *col=v->m_cols->Get(pos);
5049 if ([col respondsToSelector:@selector(setHidden:)]) [(SWELL_TableColumnExtensions*)col setHidden:YES];
5053 if ([col respondsToSelector:@selector(setHidden:)]) [(SWELL_TableColumnExtensions*)col setHidden:NO];
5058 BOOL ListView_GetColumnOrderArray(HWND h, int cnt, int* arr)
5060 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return FALSE;
5061 SWELL_ListView* lv=(SWELL_ListView*)h;
5062 if (!lv->m_cols || lv->m_cols->GetSize() != cnt) return FALSE;
5065 for (i=0; i < cnt; ++i)
5067 arr[i]=[lv getColumnPos:i];
5073 BOOL ListView_SetColumnOrderArray(HWND h, int cnt, int* arr)
5075 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return FALSE;
5076 SWELL_ListView* lv=(SWELL_ListView*)h;
5077 if (!lv->m_cols || lv->m_cols->GetSize() != cnt) return FALSE;
5080 for (i=0; i < cnt; ++i)
5082 for (j=0; j < cnt; ++j)
5084 if (arr[j] == i) break;
5088 int pos=[lv getColumnPos:j];
5089 [lv moveColumn:pos toColumn:i];
5096 HWND ListView_GetHeader(HWND h)
5098 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return 0;
5102 int Header_GetItemCount(HWND h)
5104 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return 0;
5105 SWELL_ListView* lv=(SWELL_ListView*)h;
5106 if (lv->m_cols) return lv->m_cols->GetSize();
5110 BOOL Header_GetItem(HWND h, int col, HDITEM* hi)
5112 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]] || !hi)) return FALSE;
5113 SWELL_ListView* lv=(SWELL_ListView*)h;
5114 if (!lv->m_cols || col < 0 || col >= lv->m_cols->GetSize()) return FALSE;
5115 NSTableColumn* hcol=lv->m_cols->Get(col);
5116 if (WDL_NOT_NORMALLY(!hcol)) return FALSE;
5118 if (hi->mask&HDI_FORMAT)
5121 NSImage* img=[lv indicatorImageInTableColumn:hcol];
5124 NSString* imgname=[img name];
5127 if ([imgname isEqualToString:@"NSAscendingSortIndicator"]) hi->fmt |= HDF_SORTUP;
5128 else if ([imgname isEqualToString:@"NSDescendingSortIndicator"]) hi->fmt |= HDF_SORTDOWN;
5137 BOOL Header_SetItem(HWND h, int col, HDITEM* hi)
5139 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]] || !hi)) return FALSE;
5140 SWELL_ListView* lv=(SWELL_ListView*)h;
5141 if (!lv->m_cols || col < 0 || col >= lv->m_cols->GetSize()) return FALSE;
5142 NSTableColumn* hcol=lv->m_cols->Get(col);
5143 if (!hcol) return FALSE;
5145 if (hi->mask&HDI_FORMAT)
5148 if (hi->fmt&HDF_SORTUP) img=[NSImage imageNamed:@"NSAscendingSortIndicator"];
5149 else if (hi->fmt&HDF_SORTDOWN) img=[NSImage imageNamed:@"NSDescendingSortIndicator"];
5150 [lv setIndicatorImage:img inTableColumn:hcol];
5157 int ListView_HitTest(HWND h, LVHITTESTINFO *pinf)
5159 if (WDL_NOT_NORMALLY(!h || !pinf)) return -1;
5160 if (WDL_NOT_NORMALLY(![(id)h isKindOfClass:[SWELL_ListView class]])) return -1;
5162 SWELL_ListView *tv=(SWELL_ListView*)h;
5167 // rowAtPoint will return a row even if it is scrolled out of the clip view
5168 NSScrollView* sv=(NSScrollView *)NavigateUpScrollClipViews(tv);
5169 if (![sv isKindOfClass:[NSScrollView class]] && ![sv isKindOfClass:[NSClipView class]]) sv=NULL;
5171 NSRect r=[sv documentVisibleRect];
5172 int x=pinf->pt.x-r.origin.x;
5173 int y=pinf->pt.y-r.origin.y;
5175 if (x < 0) pinf->flags |= LVHT_TOLEFT;
5176 if (x >= r.size.width) pinf->flags |= LVHT_TORIGHT;
5177 if (y < 0) pinf->flags |= LVHT_ABOVE;
5178 if (y >= r.size.height) pinf->flags |= LVHT_BELOW;
5182 NSPoint pt = NSMakePoint( pinf->pt.x, pinf->pt.y );
5183 pinf->iItem=(int)[(NSTableView *)h rowAtPoint:pt];
5184 if (pinf->iItem >= 0)
5186 pinf->flags=LVHT_ONITEMLABEL;
5187 if (tv->m_status_imagelist)
5189 NSRect c0r = [tv frameOfCellAtColumn:[tv getColumnPos:0] row:pinf->iItem];
5190 if (pt.x >= c0r.origin.x && pt.x <= c0r.origin.x + [tv rowHeight])
5192 pinf->flags=LVHT_ONITEMSTATEICON;
5198 pinf->flags = y < 10 && ListView_GetItemCount(h)>0 ? LVHT_ABOVE : LVHT_NOWHERE;
5205 int ListView_SubItemHitTest(HWND h, LVHITTESTINFO *pinf)
5207 int row = ListView_HitTest(h, pinf);
5209 NSPoint pt=NSMakePoint(pinf->pt.x,pinf->pt.y);
5211 if (row < 0 && pt.y < 0)
5212 { // Fake the point in the client area of the listview to get the column # (like win32)
5215 pinf->iSubItem=(int)[(NSTableView *)h columnAtPoint:pt];
5219 void ListView_SetItemCount(HWND h, int cnt)
5221 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return;
5223 SWELL_ListView *tv=(SWELL_ListView*)h;
5224 if (!tv->m_lbMode && (tv->style & LVS_OWNERDATA))
5226 tv->ownermode_cnt=cnt;
5227 [tv noteNumberOfRowsChanged];
5231 void ListView_EnsureVisible(HWND h, int i, BOOL pok)
5233 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return;
5235 SWELL_ListView *tv=(SWELL_ListView*)h;
5238 if (!tv->m_lbMode && (tv->style & LVS_OWNERDATA))
5240 if (i >=tv->ownermode_cnt-1) i=tv->ownermode_cnt-1;
5244 if (tv->m_items && i >= tv->m_items->GetSize()) i=tv->m_items->GetSize()-1;
5248 [tv scrollRowToVisible:i];
5252 static bool ListViewGetRectImpl(HWND h, int item, int subitem, RECT* r) // subitem<0 for full item rect
5254 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_ListView class]])) return false;
5255 if (item < 0 || item > ListView_GetItemCount(h)) return false;
5256 SWELL_ListView *tv=(SWELL_ListView*)h;
5258 if (subitem >= 0 && (!tv->m_cols || subitem >= tv->m_cols->GetSize())) return false;
5259 subitem=[tv getColumnPos:subitem];
5262 if (subitem < 0) ar = [tv rectOfRow:item];
5263 else ar=[tv frameOfCellAtColumn:subitem row:item];
5264 NSSize sp=[tv intercellSpacing];
5266 ar.size.width += sp.width;
5267 ar.size.height += sp.height;
5268 NSRECT_TO_RECT(r,ar);
5273 bool ListView_GetSubItemRect(HWND h, int item, int subitem, int code, RECT *r)
5275 return ListViewGetRectImpl(h, item, subitem, r);
5278 bool ListView_GetItemRect(HWND h, int item, RECT *r, int code)
5280 return ListViewGetRectImpl(h, item, -1, r);
5283 int ListView_GetTopIndex(HWND h)
5285 NSTableView* tv = (NSTableView*)h;
5286 if (WDL_NOT_NORMALLY(!tv)) return -1;
5287 NSScrollView* sv = [tv enclosingScrollView];
5288 if (WDL_NOT_NORMALLY(!sv)) return -1;
5290 NSPoint pt = { 0, 0 };
5291 NSView *hdr = [tv headerView];
5292 if (hdr && ![hdr isHidden])
5294 NSRect fr=[hdr frame];
5295 if (fr.size.height > 0.0) pt.y = fr.origin.y + fr.size.height;
5297 pt.y += [sv documentVisibleRect].origin.y;
5298 return (int)[tv rowAtPoint:pt];
5301 int ListView_GetCountPerPage(HWND h)
5303 NSTableView* tv = (NSTableView*)h;
5304 if (WDL_NOT_NORMALLY(!tv)) return 0;
5305 NSScrollView* sv = [tv enclosingScrollView];
5306 if (WDL_NOT_NORMALLY(!sv)) return 0;
5308 NSRect tvr = [sv documentVisibleRect];
5309 int rowh = [tv rowHeight];
5310 return tvr.size.height/rowh;
5313 bool ListView_Scroll(HWND h, int xscroll, int yscroll)
5315 NSTableView* tv = (NSTableView*)h;
5316 NSScrollView* sv = [tv enclosingScrollView];
5317 if (WDL_NOT_NORMALLY(!sv)) return false;
5319 NSRect tvr = [sv documentVisibleRect];
5320 NSPoint pt = { tvr.origin.x, tvr.origin.y };
5321 if (xscroll > 0) pt.x += tvr.size.width-1;
5322 if (yscroll > 0) pt.y += tvr.size.height-1;
5324 const NSInteger nr = [tv numberOfRows];
5325 NSInteger rowidx = [tv rowAtPoint:pt];
5326 if (rowidx < 0) rowidx=0;
5327 else if (rowidx >= nr) rowidx=nr-1;
5329 const NSInteger nc = [tv numberOfColumns];
5330 NSInteger colidx = [tv columnAtPoint:pt];
5331 if (colidx < 0) colidx=0;
5332 else if (colidx >= nc) colidx = nc-1;
5334 // colidx is our column index, not the display order, convert
5335 if ([tv isKindOfClass:[SWELL_ListView class]]) colidx = [(SWELL_ListView*)tv getColumnPos:(int)colidx];
5337 NSRect ir = [tv frameOfCellAtColumn:colidx row:rowidx];
5341 if (ir.size.height) rowidx += yscroll / ir.size.height;
5343 if (rowidx < 0) rowidx=0;
5344 else if (rowidx >= nr) rowidx = nr-1;
5345 [tv scrollRowToVisible:rowidx];
5350 if (ir.size.width) colidx += xscroll / ir.size.width;
5352 if (colidx < 0) colidx=0;
5353 else if (colidx >= nc) colidx = nc-1;
5355 // scrollColumnToVisible takes display order, which we have here
5356 [tv scrollColumnToVisible:colidx];
5363 bool ListView_GetScroll(HWND h, POINT* p)
5365 NSTableView* tv = (NSTableView*)h;
5366 NSScrollView* sv = [tv enclosingScrollView];
5367 if (WDL_NORMALLY(sv))
5369 NSRect cr = [sv documentVisibleRect];
5378 void ListView_SortItems(HWND hwnd, PFNLVCOMPARE compf, LPARAM parm)
5380 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]])) return;
5381 SWELL_ListView *tv=(SWELL_ListView*)hwnd;
5382 if (tv->m_lbMode || (tv->style & LVS_OWNERDATA) || !tv->m_items) return;
5385 tmp.Resize(tv->m_items->GetSize()*sizeof(void *));
5388 for(x=0;x<tv->m_items->GetSize();x++)
5390 SWELL_ListView_Row *r = tv->m_items->Get(x);
5393 r->m_tmp = !![tv isRowSelected:x];
5397 __listview_mergesort_internal(tv->m_items->GetList(),tv->m_items->GetSize(),sizeof(void *),compf,parm,(char*)tmp.Get());
5400 NSMutableIndexSet *indexSet = [[NSMutableIndexSet alloc] init];
5402 for(x=0;x<tv->m_items->GetSize();x++)
5404 SWELL_ListView_Row *r = tv->m_items->Get(x);
5405 if (r && (r->m_tmp&1)) [indexSet addIndex:x];
5407 [tv selectRowIndexes:indexSet byExtendingSelection:NO];
5415 HWND WindowFromPoint(POINT p)
5417 NSArray *windows=[NSApp orderedWindows];
5418 const NSInteger cnt=windows ? [windows count] : 0;
5420 NSWindow *kw = [NSApp keyWindow];
5421 if (kw && windows && [windows containsObject:kw]) kw=NULL;
5423 NSWindow *bestwnd=0;
5424 for (NSInteger x = kw ? -1 : 0; x < cnt; x ++)
5427 if (x>=0) wnd=[windows objectAtIndex:x];
5428 if (wnd && [wnd isVisible] && HTTRANSPARENT != SendMessage((HWND)wnd, WM_NCHITTEST, 0, MAKELPARAM(p.x, p.y)))
5430 NSRect fr=[wnd frame];
5431 if (p.x >= fr.origin.x && p.x < fr.origin.x + fr.size.width &&
5432 p.y >= fr.origin.y && p.y < fr.origin.y + fr.size.height)
5440 if (!bestwnd) return 0;
5441 NSPoint pt=NSMakePoint(p.x,p.y);
5442 NSPoint lpt=[bestwnd convertScreenToBase:pt];
5443 NSView *v=[[bestwnd contentView] hitTest:lpt];
5444 if (v) return (HWND)v;
5445 return (HWND)[bestwnd contentView];
5448 void UpdateWindow(HWND hwnd)
5450 if (WDL_NORMALLY(hwnd && [(id)hwnd isKindOfClass:[NSView class]]))
5452 #ifndef SWELL_NO_METAL
5453 if ([(id)hwnd isKindOfClass:[SWELL_hwndChild class]] &&
5454 ((SWELL_hwndChild *)hwnd)->m_use_metal > 0)
5456 // do nothing for metal windows, let the timer catch it
5461 if ([(NSView *)hwnd needsDisplay])
5463 NSWindow *wnd = [(NSView *)hwnd window];
5464 [wnd displayIfNeeded];
5470 void SWELL_FlushWindow(HWND h)
5472 if (WDL_NORMALLY(h))
5475 if ([(id)h isKindOfClass:[NSView class]])
5477 #ifndef SWELL_NO_METAL
5478 if ([(id)h isKindOfClass:[SWELL_hwndChild class]] && ((SWELL_hwndChild *)h)->m_use_metal > 0)
5482 if ([(NSView *)h needsDisplay]) return;
5484 w = [(NSView *)h window];
5486 else if ([(id)h isKindOfClass:[NSWindow class]]) w = (NSWindow *)h;
5488 if (w && ![w viewsNeedDisplay])
5495 static void InvalidateSuperViews(NSView *view)
5498 view = [view superview];
5501 if ([view isKindOfClass:[SWELL_hwndChild class]])
5503 if (((SWELL_hwndChild *)view)->m_isdirty&2) break;
5504 ((SWELL_hwndChild *)view)->m_isdirty|=2;
5506 view = [view superview];
5511 int g_swell_in_paint;
5514 BOOL InvalidateRect(HWND hwnd, const RECT *r, int eraseBk)
5517 if (g_swell_in_paint)
5519 printf("swell-cocoa: calling InvalidateRect() from within paint, this is allowed but bad form.\n");
5520 // WDL_ASSERT(false);
5524 if (WDL_NOT_NORMALLY(!hwnd)) return FALSE;
5526 if ([view isKindOfClass:[NSWindow class]]) view=[view contentView];
5527 if (WDL_NORMALLY([view isKindOfClass:[NSView class]]))
5532 bool skip_parent_invalidate=false;
5533 if ([view isKindOfClass:[SWELL_hwndChild class]])
5535 #ifndef SWELL_NO_METAL
5536 SWELL_hwndChild *hc = (SWELL_hwndChild*)view;
5537 if (hc->m_use_metal > 0)
5539 if (![hc isHiddenOrHasHiddenAncestor])
5541 swell_addMetalDirty(hc,r);
5546 if (!(((SWELL_hwndChild *)view)->m_isdirty&1))
5548 ((SWELL_hwndChild *)view)->m_isdirty|=1;
5550 else skip_parent_invalidate=true; // if already dirty, then assume parents are already dirty too
5552 if (!skip_parent_invalidate)
5554 InvalidateSuperViews(view);
5559 if (tr.top>tr.bottom)
5561 int a = tr.top; tr.top=tr.bottom; tr.bottom=a;
5563 [sv setNeedsDisplayInRect:NSMakeRect(tr.left,tr.top,tr.right-tr.left,tr.bottom-tr.top)];
5565 else [sv setNeedsDisplay:YES];
5571 static HWND m_fakeCapture;
5572 static BOOL m_capChangeNotify;
5576 return m_fakeCapture;
5579 HWND SetCapture(HWND hwnd)
5581 HWND oc=m_fakeCapture;
5582 int ocn=m_capChangeNotify;
5584 m_capChangeNotify = hwnd && [(id)hwnd respondsToSelector:@selector(swellCapChangeNotify)] && [(SWELL_hwndChild*)hwnd swellCapChangeNotify];
5586 if (hwnd && WDL_NORMALLY([(id)hwnd isKindOfClass:[NSView class]]))
5587 [[(NSView *)hwnd window] disableCursorRects];
5589 if (ocn && oc && oc != hwnd) SendMessage(oc,WM_CAPTURECHANGED,0,(LPARAM)hwnd);
5594 void ReleaseCapture()
5596 HWND h=m_fakeCapture;
5598 if (m_capChangeNotify && h)
5600 SendMessage(h,WM_CAPTURECHANGED,0,0);
5605 HDC BeginPaint(HWND hwnd, PAINTSTRUCT *ps)
5607 if (WDL_NOT_NORMALLY(!ps)) return 0;
5608 memset(ps,0,sizeof(PAINTSTRUCT));
5609 if (WDL_NOT_NORMALLY(!hwnd)) return 0;
5611 if (![turd respondsToSelector:@selector(getSwellPaintInfo:)]) return 0;
5613 [(SWELL_hwndChild*)turd getSwellPaintInfo:(PAINTSTRUCT *)ps];
5617 BOOL EndPaint(HWND hwnd, PAINTSTRUCT *ps)
5619 WDL_ASSERT(hwnd != NULL && ps != NULL);
5623 LRESULT DefWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
5625 if (msg==WM_RBUTTONUP||msg==WM_NCRBUTTONUP)
5627 POINT p={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
5629 if (msg==WM_RBUTTONUP)
5631 ClientToScreen(hwnd,&p);
5632 HWND h=WindowFromPoint(p);
5633 if (h && IsChild(hwnd,h)) hwndDest=h;
5635 SendMessage(hwnd,WM_CONTEXTMENU,(WPARAM)hwndDest,MAKELONG(p.x&0xffff,p.y));
5638 else if (msg==WM_CONTEXTMENU || msg == WM_MOUSEWHEEL || msg == WM_MOUSEHWHEEL || msg == WM_GESTURE)
5640 if ([(id)hwnd isKindOfClass:[NSView class]])
5642 NSView *h=(NSView *)hwnd;
5643 while (h && [[h window] contentView] != h)
5646 if (h && [h respondsToSelector:@selector(onSwellMessage:p1:p2:)])
5648 return SendMessage((HWND)h,msg,wParam,lParam);
5653 else if (msg==WM_NCHITTEST)
5658 GetWindowRect(hwnd,&r);
5659 POINT pt={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
5661 if (r.top > r.bottom)
5663 pt.y = r.bottom + (r.top - pt.y); // translate coordinate into flipped-window
5665 int a=r.top; r.top=r.bottom; r.bottom=a;
5667 NCCALCSIZE_PARAMS p={{r,}};
5668 SendMessage(hwnd,WM_NCCALCSIZE,FALSE,(LPARAM)&p);
5669 if (!PtInRect(&p.rgrc[0],pt)) rv=HTNOWHERE;
5673 else if (msg==WM_KEYDOWN || msg==WM_KEYUP)
5675 // if not ctrl/cmd/opt modified, and not tab, and listview/treeview, do not bubble it up
5676 // (fixes triggering of menu items when searching for text etc)
5677 if (!(lParam & (FCONTROL|FALT|FLWIN)) && !(wParam == VK_TAB && (lParam&FVIRTKEY)))
5679 id fr = [[(NSView *)hwnd window] firstResponder];
5680 if ([fr isKindOfClass:[NSTableView class]] ||
5681 [fr isKindOfClass:[NSOutlineView class]]) return 1;
5683 if (wParam >= VK_LEFT && wParam <= VK_DOWN && [fr isKindOfClass:[NSButton class]])
5685 // do not bubble up left/right for any
5686 if (wParam == VK_LEFT || wParam == VK_RIGHT) return 1;
5688 // do not bubble up left/down for non-NSPopUpButton
5689 if (![fr isKindOfClass:[NSPopUpButton class]]) return 1;
5694 else if (msg == WM_DISPLAYCHANGE)
5696 if ([(id)hwnd isKindOfClass:[NSView class]])
5698 NSArray *ch = [(NSView *)hwnd subviews];
5702 for(x=0;x<[ch count]; x ++)
5704 NSView *v = [ch objectAtIndex:x];
5705 sendSwellMessage(v,WM_DISPLAYCHANGE,wParam,lParam);
5709 void SWELL_DoDialogColorUpdates(HWND hwnd, DLGPROC d, bool isUpdate);
5710 DLGPROC d = (DLGPROC)GetWindowLong(hwnd,DWL_DLGPROC);
5711 if (d) SWELL_DoDialogColorUpdates(hwnd,d,true);
5714 InvalidateRect((HWND)hwnd,NULL,FALSE);
5717 else if (msg == WM_CTLCOLORSTATIC && wParam)
5719 if (SWELL_osx_is_dark_mode(0))
5724 br = CreateSolidBrush(RGB(0,0,0)); // todo hm
5725 br->color = (CGColorRef) [[NSColor windowBackgroundColor] CGColor];
5726 CFRetain(br->color);
5728 SetTextColor((HDC)wParam,RGB(255,255,255));
5735 void SWELL_BroadcastMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
5737 NSArray *ch=[NSApp windows];
5739 for (int x=0;x<[ch count]; x ++)
5741 NSView *v = [[ch objectAtIndex:x] contentView];
5742 if (v && [v respondsToSelector:@selector(onSwellMessage:p1:p2:)])
5744 [(SWELL_hwndChild *)v onSwellMessage:uMsg p1:wParam p2:lParam];
5763 ///////////////// clipboard compatability (NOT THREAD SAFE CURRENTLY)
5766 BOOL DragQueryPoint(HDROP hDrop,LPPOINT pt)
5768 if (!hDrop) return 0;
5769 DROPFILES *df=(DROPFILES*)GlobalLock(hDrop);
5772 GlobalUnlock(hDrop);
5776 void DragFinish(HDROP hDrop)
5778 //do nothing for now (caller will free hdrops)
5781 UINT DragQueryFile(HDROP hDrop, UINT wf, char *buf, UINT bufsz)
5783 if (!hDrop) return 0;
5784 DROPFILES *df=(DROPFILES*)GlobalLock(hDrop);
5787 char *p=(char*)df + df->pFiles;
5788 if (wf == 0xFFFFFFFF)
5804 lstrcpyn_safe(buf,p,bufsz);
5814 GlobalUnlock(hDrop);
5828 static WDL_PtrList<void> m_clip_recs;
5829 static WDL_PtrList<NSString> m_clip_fmts;
5830 static WDL_PtrList<char> m_clip_curfmts;
5831 struct swell_pendingClipboardStates
5835 swell_pendingClipboardStates(UINT _type, HANDLE _h)
5840 ~swell_pendingClipboardStates()
5846 static WDL_PtrList<swell_pendingClipboardStates> m_clipsPending;
5848 bool OpenClipboard(HWND hwndDlg)
5850 m_clipsPending.Empty(true);
5851 RegisterClipboardFormat(NULL);
5853 NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
5854 m_clip_curfmts.Empty();
5855 if (SWELL_GetOSXVersion()>=0x1060)
5857 NSArray *list = [pasteboard
5858 readObjectsForClasses:[NSArray arrayWithObject:[NSURL class]]
5859 options:[NSMutableDictionary dictionaryWithCapacity:1]];
5860 if ([list count]) m_clip_curfmts.Add((char*)(INT_PTR)CF_HDROP);
5862 NSArray *ar=[pasteboard types];
5864 if (ar && [ar count])
5868 for (x = 0; x < [ar count]; x ++)
5870 NSString *s=[ar objectAtIndex:x];
5873 for (y = 0; y < m_clip_fmts.GetSize(); y ++)
5875 NSString *cs = m_clip_fmts.Get(y);
5876 if (cs && [s compare:cs]==NSOrderedSame)
5878 char *tok = (char*)(INT_PTR)(y+1);
5879 if (m_clip_curfmts.Find(tok)<0) m_clip_curfmts.Add(tok);
5889 void CloseClipboard() // frees any remaining items in clipboard
5891 m_clip_recs.Empty(GlobalFree);
5893 if (m_clipsPending.GetSize())
5896 NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
5898 NSMutableArray *ar = [[NSMutableArray alloc] initWithCapacity:m_clipsPending.GetSize()];
5901 for (x=0;x<m_clipsPending.GetSize();x++)
5903 swell_pendingClipboardStates *cs=m_clipsPending.Get(x);
5904 if (cs->type == CF_HDROP)
5910 NSString *fmt=m_clip_fmts.Get(cs->type-1);
5911 if (fmt) [ar addObject:fmt];
5915 if (hdrop_cnt || [ar count])
5918 [pasteboard declareTypes:ar owner:nil];
5919 else if (SWELL_GetOSXVersion() >= 0x1060)
5920 [pasteboard clearContents];
5921 for (x=0;x<m_clipsPending.GetSize();x++)
5923 swell_pendingClipboardStates *cs=m_clipsPending.Get(x);
5925 void *buf=GlobalLock(cs->h);
5928 int bufsz=GlobalSize(cs->h);
5929 if (cs->type == CF_TEXT)
5931 char *t = (char *)malloc(bufsz+1);
5934 memcpy(t,buf,bufsz);
5936 NSString *s = (NSString*)SWELL_CStringToCFString(t);
5937 [pasteboard setString:s forType:NSStringPboardType];
5942 else if (cs->type == CF_HDROP)
5944 if (WDL_NORMALLY(bufsz > sizeof(DROPFILES)))
5946 const DROPFILES *hdr = (const DROPFILES *)buf;
5948 WDL_NORMALLY(hdr->pFiles < bufsz) &&
5949 WDL_NORMALLY(!hdr->fWide) // todo deal with UTF-16
5952 NSMutableArray *list = [NSMutableArray arrayWithCapacity:20];
5953 const char *rd = (const char *)buf;
5954 DWORD rdo = hdr->pFiles;
5955 while (rdo < bufsz && rd[rdo])
5957 NSString *fnstr=(NSString *)SWELL_CStringToCFString(rd+rdo);
5958 NSURL *url = [NSURL fileURLWithPath:fnstr];
5960 if (url) [list addObject:url];
5961 rdo += strlen(rd+rdo)+1;
5964 if ([list count] && SWELL_GetOSXVersion() >= 0x1060)
5966 [pasteboard writeObjects:list];
5973 NSString *fmt=m_clip_fmts.Get(cs->type-1);
5976 NSData *data=[NSData dataWithBytes:buf length:bufsz];
5977 [pasteboard setData:data forType:fmt];
5980 GlobalUnlock(cs->h);
5985 m_clipsPending.Empty(true);
5989 UINT EnumClipboardFormats(UINT lastfmt)
5991 if (lastfmt == 0) return (UINT)(INT_PTR)m_clip_curfmts.Get(0);
5992 const int idx = m_clip_curfmts.Find((char *)(INT_PTR)lastfmt);
5993 return idx >= 0 ? (UINT)(INT_PTR)m_clip_curfmts.Get(idx+1) : 0;
5996 HANDLE GetClipboardData(UINT type)
5998 RegisterClipboardFormat(NULL);
5999 NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
6002 if (type == CF_TEXT)
6005 NSString *str = [pasteboard stringForType:NSStringPboardType];
6008 int l = (int) ([str length]*4 + 32);
6009 char *buf = (char *)malloc(l);
6011 SWELL_CFStringToCString(str,buf,l);
6013 l = (int) (strlen(buf)+1);
6015 memcpy(GlobalLock(h),buf,l);
6020 else if (type == CF_HDROP)
6022 if (SWELL_GetOSXVersion()>=0x1060)
6025 NSArray *list = [pasteboard
6026 readObjectsForClasses:[NSArray arrayWithObject:[NSURL class]]
6027 options:[NSMutableDictionary dictionaryWithCapacity:1]
6029 int nf = (int) [list count];
6032 WDL_TypedQueue<char> flist;
6033 flist.Add(NULL,sizeof(DROPFILES));
6034 for (int x=0;x<nf;x++)
6036 NSURL *url = (NSURL *)[list objectAtIndex:x];
6037 if ([url isFileURL])
6039 const char *ptr = [[url path] UTF8String];
6040 if (ptr && *ptr) flist.Add(ptr, (int)strlen(ptr)+1);
6043 if (flist.GetSize()>sizeof(DROPFILES))
6046 DROPFILES *hdr = (DROPFILES*)flist.Get();
6047 memset(hdr,0,sizeof(*hdr));
6048 hdr->pFiles = sizeof(DROPFILES);
6049 h=GlobalAlloc(0,flist.GetSize());
6050 if (h) memcpy(GlobalLock(h),flist.Get(),flist.GetSize());
6058 NSString *fmt=m_clip_fmts.Get(type-1);
6061 NSData *data=[pasteboard dataForType:fmt];
6062 if (!data) return 0;
6063 int l = (int)[data length];
6065 if (h) memcpy(GlobalLock(h),[data bytes],l);
6070 if (h) m_clip_recs.Add(h);
6074 void EmptyClipboard()
6076 m_clipsPending.Empty(true);
6080 void SetClipboardData(UINT type, HANDLE h)
6082 m_clipsPending.Add(new swell_pendingClipboardStates(type,h));
6085 UINT RegisterClipboardFormat(const char *desc)
6087 if (!m_clip_fmts.GetSize())
6089 m_clip_fmts.Add([NSStringPboardType retain]); // CF_TEXT
6090 m_clip_fmts.Add(NULL); // CF_HDROP
6092 if (!desc || !*desc) return 0;
6094 if (!strcmp(desc,"SWELL__CF_TEXT")) return CF_TEXT; // for legacy SWELL users
6096 NSString *s=(NSString*)SWELL_CStringToCFString(desc);
6098 for (x = 0; x < m_clip_fmts.GetSize(); x ++)
6100 NSString *ts=m_clip_fmts.Get(x);
6101 if (ts && [ts compare:s]==NSOrderedSame)
6108 return m_clip_fmts.GetSize();
6111 int EnumPropsEx(HWND hwnd, PROPENUMPROCEX proc, LPARAM lParam)
6113 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd respondsToSelector:@selector(swellEnumProps:lp:)])) return -1;
6114 return (int)[(SWELL_hwndChild *)hwnd swellEnumProps:proc lp:lParam];
6117 HANDLE GetProp(HWND hwnd, const char *name)
6119 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd respondsToSelector:@selector(swellGetProp:wantRemove:)])) return NULL;
6120 return (HANDLE)[(SWELL_hwndChild *)hwnd swellGetProp:name wantRemove:NO];
6123 BOOL SetProp(HWND hwnd, const char *name, HANDLE val)
6125 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd respondsToSelector:@selector(swellSetProp:value:)])) return FALSE;
6126 return (BOOL)!![(SWELL_hwndChild *)hwnd swellSetProp:name value:val];
6129 HANDLE RemoveProp(HWND hwnd, const char *name)
6131 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd respondsToSelector:@selector(swellGetProp:wantRemove:)])) return NULL;
6132 return (HANDLE)[(SWELL_hwndChild *)hwnd swellGetProp:name wantRemove:YES];
6136 int GetSystemMetrics(int p)
6143 NSScreen *s=[NSScreen mainScreen];
6144 if (!s) return 1024;
6145 return p==SM_CXSCREEN ? [s frame].size.width : [s frame].size.height;
6147 case SM_CXHSCROLL: return 16;
6148 case SM_CYHSCROLL: return 16;
6149 case SM_CXVSCROLL: return 16;
6150 case SM_CYVSCROLL: return 16;
6151 case SM_CYMENU: return (int)([[NSApp mainMenu] menuBarHeight] + 0.5);
6156 BOOL ScrollWindow(HWND hwnd, int xamt, int yamt, const RECT *lpRect, const RECT *lpClipRect)
6158 if (hwnd && [(id)hwnd isKindOfClass:[NSWindow class]]) hwnd=(HWND)[(id)hwnd contentView];
6159 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[NSView class]])) return FALSE;
6161 if (!xamt && !yamt) return FALSE;
6163 // move child windows only
6168 NSArray *ar=[(NSView*)hwnd subviews];
6169 NSInteger i,c=[ar count];
6172 NSView *v=(NSView *)[ar objectAtIndex:i];
6179 [(id)hwnd setNeedsDisplay:YES];
6183 NSRect r=[(NSView*)hwnd bounds];
6186 [(id)hwnd setBoundsOrigin:r.origin];
6187 [(id)hwnd setNeedsDisplay:YES];
6192 HWND FindWindowEx(HWND par, HWND lastw, const char *classname, const char *title)
6194 // note: this currently is far far far from fully functional, bleh
6197 if (!title) return NULL;
6199 // get a list of top level windows, find any that match
6200 // (this does not scan child windows, which is a todo really)
6202 NSArray *ch=[NSApp windows];
6203 NSInteger x=0,n=[ch count];
6208 NSWindow *w = [ch objectAtIndex:x];
6209 if ((HWND)w == lastw || (HWND)[w contentView] == lastw) break;
6214 NSString *srch=(NSString*)SWELL_CStringToCFString(title);
6215 for(;x<n && !rv; x ++)
6217 NSWindow *w = [ch objectAtIndex:x];
6218 if ([[w title] isEqualToString:srch])
6220 rv=(HWND)[w contentView];
6224 if (!GetClassName(rv,tmp,sizeof(tmp)) || strcmp(tmp,classname))
6233 HWND h=lastw?GetWindow(lastw,GW_HWNDNEXT):GetWindow(par,GW_CHILD);
6241 GetWindowText(h,buf,sizeof(buf));
6242 if (strcmp(title,buf)) isOk=false;
6244 if (isOk && classname)
6247 if (!GetClassName(h,tmp,sizeof(tmp)) || strcmp(tmp,classname))
6249 if (!stricmp(classname,"Static") && [(id)h isKindOfClass:[NSTextField class]])
6251 // allow finding "Static" to match a textfield
6259 h=GetWindow(h,GW_HWNDNEXT);
6264 BOOL TreeView_SetIndent(HWND hwnd, int indent)
6266 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]])) return 0;
6267 SWELL_TreeView* tv = (SWELL_TreeView*)hwnd;
6268 [tv setIndentationPerLevel:(float)indent];
6272 HTREEITEM TreeView_InsertItem(HWND hwnd, TV_INSERTSTRUCT *ins)
6274 if (WDL_NOT_NORMALLY(!hwnd || !ins || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]])) return 0;
6276 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
6278 HTREEITEM__ *par=NULL;
6281 if (ins->hParent && ins->hParent != TVI_ROOT && ins->hParent != TVI_FIRST && ins->hParent != TVI_LAST && ins->hParent != TVI_SORT)
6283 if ([tv findItem:ins->hParent parOut:&par idxOut:&inspos])
6285 par = (HTREEITEM__ *)ins->hParent;
6290 if (ins->hInsertAfter == TVI_FIRST) inspos=0;
6291 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;
6292 else inspos = par ? par->m_children.Find((HTREEITEM__*)ins->hInsertAfter)+1 : tv->m_items ? tv->m_items->Find((HTREEITEM__*)ins->hInsertAfter)+1 : 0;
6294 HTREEITEM__ *item=new HTREEITEM__;
6295 if (ins->item.mask & TVIF_CHILDREN)
6296 item->m_haschildren = !!ins->item.cChildren;
6297 if (ins->item.mask & TVIF_PARAM) item->m_param = ins->item.lParam;
6298 if (ins->item.mask & TVIF_TEXT) item->m_value = strdup(ins->item.pszText);
6301 if (!tv->m_items) tv->m_items = new WDL_PtrList<HTREEITEM__>;
6302 tv->m_items->Insert(inspos,item);
6304 else par->m_children.Insert(inspos,item);
6306 // [tv reloadData] invalidates the contents and breaks stuff
6307 // if we are in the middle of handling a treeview notification
6308 if (SWELL_GetOSXVersion() >= 0x1070)
6310 SWELL_DataHold *dh = par ? par->m_dh : NULL;
6311 NSIndexSet *idxset=[NSIndexSet indexSetWithIndex:inspos];
6313 [tv insertItemsAtIndexes:idxset inParent:dh withAnimation:0];
6321 return (HTREEITEM) item;
6324 BOOL TreeView_Expand(HWND hwnd, HTREEITEM item, UINT flag)
6326 if (WDL_NOT_NORMALLY(!hwnd || !item)) return false;
6328 if (WDL_NOT_NORMALLY(![(id)hwnd isKindOfClass:[SWELL_TreeView class]])) return false;
6330 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
6332 id itemid=((HTREEITEM__*)item)->m_dh;
6333 bool isExp=!![tv isItemExpanded:itemid];
6335 if (flag == TVE_EXPAND && !isExp) [tv expandItem:itemid];
6336 else if (flag == TVE_COLLAPSE && isExp) [tv collapseItem:itemid];
6337 else if (flag==TVE_TOGGLE)
6339 if (isExp) [tv collapseItem:itemid];
6340 else [tv expandItem:itemid];
6348 HTREEITEM TreeView_GetSelection(HWND hwnd)
6350 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]])) return NULL;
6352 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
6353 NSInteger idx=[tv selectedRow];
6354 if (idx<0) return NULL;
6356 SWELL_DataHold *t=[tv itemAtRow:idx];
6357 if (t) return (HTREEITEM)[t getValue];
6362 void TreeView_DeleteItem(HWND hwnd, HTREEITEM item)
6364 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]])) return;
6365 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
6367 HTREEITEM__ *par=NULL;
6370 if ([tv findItem:item parOut:&par idxOut:&idx])
6372 id retain_obj = [item->m_dh retain]; // workaround for macOS 10.10.5 bug using a cached pointer to this item in -beginUpdates
6376 HTREEITEM sel = TreeView_GetSelection(hwnd);
6377 bool is_sel = sel && (sel == item || item->FindItem(sel,NULL,NULL));
6378 par->m_children.Delete(idx,true);
6379 if (is_sel) TreeView_SelectItem(hwnd, par);
6381 else if (tv->m_items)
6383 tv->m_items->Delete(idx,true);
6386 if (SWELL_GetOSXVersion() >= 0x1070 && [tv respondsToSelector:@selector(beginUpdates)])
6388 SWELL_DataHold *dh = par ? par->m_dh : NULL;
6389 NSIndexSet *idxset=[NSIndexSet indexSetWithIndex:idx];
6391 [tv removeItemsAtIndexes:idxset inParent:dh withAnimation:0];
6398 [retain_obj release];
6402 void TreeView_DeleteAllItems(HWND hwnd)
6404 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]])) return;
6405 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
6407 if (tv->m_items) tv->m_items->Empty(true);
6411 void TreeView_EnsureVisible(HWND hwnd, HTREEITEM item)
6413 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]])) return;
6415 NSInteger row=[(SWELL_TreeView*)hwnd rowForItem:((HTREEITEM__*)item)->m_dh];
6417 [(SWELL_TreeView*)hwnd scrollRowToVisible:row];
6420 void TreeView_SelectItem(HWND hwnd, HTREEITEM item)
6422 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]])) return;
6424 NSInteger row=[(SWELL_TreeView*)hwnd rowForItem:((HTREEITEM__*)item)->m_dh];
6426 [(SWELL_TreeView*)hwnd selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
6431 NMTREEVIEW nm={{(HWND)hwnd,(UINT_PTR)[(SWELL_TreeView*)hwnd tag],TVN_SELCHANGED},};
6432 nm.itemNew.hItem = item;
6433 nm.itemNew.lParam = item ? item->m_param : 0;
6434 SendMessage(GetParent(hwnd),WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
6439 BOOL TreeView_GetItem(HWND hwnd, LPTVITEM pitem)
6441 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]] || !pitem) ||
6442 !(pitem->mask & TVIF_HANDLE) || !(pitem->hItem)) return FALSE;
6444 HTREEITEM__ *ti = (HTREEITEM__*)pitem->hItem;
6445 pitem->cChildren = ti->m_haschildren ? 1:0;
6446 pitem->lParam = ti->m_param;
6447 if ((pitem->mask&TVIF_TEXT)&&pitem->pszText&&pitem->cchTextMax>0)
6449 lstrcpyn_safe(pitem->pszText,ti->m_value?ti->m_value:"",pitem->cchTextMax);
6454 NSInteger itemRow = [(SWELL_TreeView*)hwnd rowForItem:ti->m_dh];
6455 if (itemRow >= 0 && [(SWELL_TreeView*)hwnd isRowSelected:itemRow])
6456 pitem->state |= TVIS_SELECTED;
6457 if ([(SWELL_TreeView*)hwnd isItemExpanded:ti->m_dh])
6458 pitem->state |= TVIS_EXPANDED;
6463 BOOL TreeView_SetItem(HWND hwnd, LPTVITEM pitem)
6465 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]] || !pitem) ||
6466 !(pitem->mask & TVIF_HANDLE) || !(pitem->hItem)) return FALSE;
6468 HTREEITEM__ *par=NULL;
6471 if (![(SWELL_TreeView*)hwnd findItem:pitem->hItem parOut:&par idxOut:&idx]) return FALSE;
6473 HTREEITEM__ *ti = (HTREEITEM__*)pitem->hItem;
6475 bool need_reload=false;
6476 if (pitem->mask & TVIF_CHILDREN)
6478 if (!ti->m_haschildren != !pitem->cChildren) need_reload=true;
6479 ti->m_haschildren = pitem->cChildren?1:0;
6481 if (pitem->mask & TVIF_PARAM) ti->m_param = pitem->lParam;
6483 if ((pitem->mask&TVIF_TEXT)&&pitem->pszText)
6486 ti->m_value=strdup(pitem->pszText);
6487 InvalidateRect(hwnd, 0, FALSE);
6490 if (pitem->stateMask & TVIS_SELECTED)
6492 NSInteger itemRow = [(SWELL_TreeView*)hwnd rowForItem:ti->m_dh];
6495 if (pitem->state&TVIS_SELECTED)
6497 [(SWELL_TreeView*)hwnd selectRowIndexes:[NSIndexSet indexSetWithIndex:itemRow] byExtendingSelection:NO];
6503 NMTREEVIEW nm={{(HWND)hwnd,(UINT_PTR)[(SWELL_TreeView*)hwnd tag],TVN_SELCHANGED},};
6504 nm.itemNew.hItem = ti;
6505 nm.itemNew.lParam = ti ? ti->m_param : 0;
6506 SendMessage(GetParent(hwnd),WM_NOTIFY,nm.hdr.idFrom,(LPARAM)&nm);
6513 // todo figure out unselect?!
6514 // [(SWELL_TreeView*)hwnd selectRowIndexes:[NSIndexSet indexSetWithIndex:itemRow] byExtendingSelection:NO];
6519 if (pitem->stateMask & TVIS_EXPANDED)
6520 TreeView_Expand(hwnd,pitem->hItem,(pitem->state&TVIS_EXPANDED)?TVE_EXPAND:TVE_COLLAPSE);
6524 [(SWELL_TreeView*)hwnd reloadItem:ti->m_dh];
6530 HTREEITEM TreeView_HitTest(HWND hwnd, TVHITTESTINFO *hti)
6532 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]] || !hti)) return NULL;
6533 SWELL_TreeView* tv = (SWELL_TreeView*)hwnd;
6537 // treeview might be clipped
6539 ClientToScreen(hwnd, &wp);
6541 GetWindowRect(hwnd, &wr);
6542 if (wp.x < wr.left || wp.x >= wr.right) return NULL;
6543 if (wp.y < wdl_min(wr.top, wr.bottom) || wp.y >= wdl_max(wr.top, wr.bottom)) return NULL;
6547 for (i = 0; i < [tv numberOfRows]; ++i)
6549 NSRect r = [tv rectOfRow:i];
6550 maxy = wdl_max(maxy, r.origin.y + r.size.height);
6551 if (x >= r.origin.x && x < r.origin.x+r.size.width && y >= r.origin.y && y < r.origin.y+r.size.height)
6553 SWELL_DataHold* t = [tv itemAtRow:i];
6554 if (t) return (HTREEITEM)[t getValue];
6560 hti->flags |= TVHT_NOWHERE;
6563 return NULL; // not hit
6566 HTREEITEM TreeView_GetRoot(HWND hwnd)
6568 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]])) return NULL;
6569 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
6571 if (!tv->m_items) return 0;
6572 return (HTREEITEM) tv->m_items->Get(0);
6575 HTREEITEM TreeView_GetParent(HWND hwnd, HTREEITEM item)
6577 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]])) return NULL;
6579 if (!item) return TreeView_GetRoot(hwnd);
6581 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
6582 HTREEITEM__ *par=NULL;
6584 [tv findItem:item parOut:&par idxOut:&idx];
6587 HTREEITEM TreeView_GetChild(HWND hwnd, HTREEITEM item)
6589 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]])) return NULL;
6591 HTREEITEM__ *titem=(HTREEITEM__ *)item;
6592 if (!titem || item == TVI_ROOT) return TreeView_GetRoot(hwnd);
6594 return (HTREEITEM) titem->m_children.Get(0);
6596 HTREEITEM TreeView_GetNextSibling(HWND hwnd, HTREEITEM item)
6598 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]])) return NULL;
6599 SWELL_TreeView *tv=(SWELL_TreeView*)hwnd;
6601 if (!item) return TreeView_GetRoot(hwnd);
6603 HTREEITEM__ *par=NULL;
6605 if ([tv findItem:item parOut:&par idxOut:&idx])
6609 return par->m_children.Get(idx+1);
6611 if (tv->m_items) return tv->m_items->Get(idx+1);
6616 void TreeView_SetBkColor(HWND hwnd, int color)
6618 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]])) return;
6619 [(NSOutlineView*)hwnd setBackgroundColor:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f
6620 green:GetGValue(color)/255.0f
6621 blue:GetBValue(color)/255.0f alpha:1.0f]];
6623 void TreeView_SetTextColor(HWND hwnd, int color)
6625 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_TreeView class]])) return;
6627 SWELL_TreeView *f = (SWELL_TreeView *)hwnd;
6628 [f->m_fgColor release];
6629 f->m_fgColor = [NSColor colorWithCalibratedRed:GetRValue(color)/255.0f
6630 green:GetGValue(color)/255.0f
6631 blue:GetBValue(color)/255.0f alpha:1.0f];
6632 [f->m_fgColor retain];
6634 void ListView_SetBkColor(HWND hwnd, int color)
6636 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]])) return;
6637 [(NSTableView*)hwnd setBackgroundColor:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f
6638 green:GetGValue(color)/255.0f
6639 blue:GetBValue(color)/255.0f alpha:1.0f]];
6642 void ListView_SetSelColors(HWND hwnd, int *colors, int ncolors) // this works for SWELL_ListView as well as SWELL_TreeView
6644 if (WDL_NOT_NORMALLY(!hwnd)) return;
6645 NSMutableArray *ar=[[NSMutableArray alloc] initWithCapacity:ncolors];
6649 const int color = colors ? *colors++ : 0;
6650 [ar addObject:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f
6651 green:GetGValue(color)/255.0f
6652 blue:GetBValue(color)/255.0f alpha:1.0f]];
6655 if ([(id)hwnd isKindOfClass:[SWELL_ListView class]])
6657 SWELL_ListView *lv = (SWELL_ListView*)hwnd;
6658 [lv->m_selColors release];
6661 else if ([(id)hwnd isKindOfClass:[SWELL_TreeView class]])
6663 SWELL_TreeView *lv = (SWELL_TreeView*)hwnd;
6664 [lv->m_selColors release];
6673 void ListView_SetGridColor(HWND hwnd, int color)
6675 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]])) return;
6676 [(NSTableView*)hwnd setGridColor:[NSColor colorWithCalibratedRed:GetRValue(color)/255.0f
6677 green:GetGValue(color)/255.0f
6678 blue:GetBValue(color)/255.0f alpha:1.0f]];
6680 void ListView_SetTextBkColor(HWND hwnd, int color)
6682 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]])) return;
6683 // not implemented atm
6685 void ListView_SetTextColor(HWND hwnd, int color)
6687 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[SWELL_ListView class]])) return;
6689 SWELL_ListView *f = (SWELL_ListView *)hwnd;
6690 [f->m_fgColor release];
6691 f->m_fgColor = [NSColor colorWithCalibratedRed:GetRValue(color)/255.0f
6692 green:GetGValue(color)/255.0f
6693 blue:GetBValue(color)/255.0f alpha:1.0f];
6694 [f->m_fgColor retain];
6698 BOOL ShellExecute(HWND hwndDlg, const char *action, const char *content1, const char *content2, const char *content3, int blah)
6700 if (content1 && (!strnicmp(content1,"http://",7) || !strnicmp(content1,"https://",8)))
6702 NSWorkspace *wk = [NSWorkspace sharedWorkspace];
6703 if (!wk) return FALSE;
6704 NSString *fnstr=(NSString *)SWELL_CStringToCFString(content1);
6705 NSURL *url = [NSURL URLWithString:fnstr];
6706 BOOL ret=url && [wk openURL:url];
6711 if (content1 && !stricmp(content1,"explorer.exe")) content1="";
6712 else if (content1 && (!stricmp(content1,"notepad.exe")||!stricmp(content1,"notepad"))) content1="TextEdit.app";
6714 if (content2 && !stricmp(content2,"explorer.exe")) content2="";
6716 if (content1 && content2 && *content1 && *content2)
6718 NSWorkspace *wk = [NSWorkspace sharedWorkspace];
6719 if (!wk) return FALSE;
6720 NSString *appstr=(NSString *)SWELL_CStringToCFString(content1);
6721 NSString *fnstr=(NSString *)SWELL_CStringToCFString(content2);
6722 BOOL ret=[wk openFile:fnstr withApplication:appstr andDeactivate:YES];
6727 else if ((content1&&*content1) || (content2&&*content2))
6729 const char *fn = (content1 && *content1) ? content1 : content2;
6730 NSWorkspace *wk = [NSWorkspace sharedWorkspace];
6731 if (!wk) return FALSE;
6732 NSString *fnstr = nil;
6735 if (fn && !strnicmp(fn, "/select,\"", 9))
6737 char* tmp = strdup(fn+9);
6738 if (*tmp && tmp[strlen(tmp)-1]=='\"') tmp[strlen(tmp)-1]='\0';
6741 if ([wk respondsToSelector:@selector(activateFileViewerSelectingURLs:)]) // 10.6+
6743 fnstr=(NSString *)SWELL_CStringToCFString(tmp);
6744 NSURL *url = [NSURL fileURLWithPath:fnstr isDirectory:false];
6747 [wk activateFileViewerSelectingURLs:[NSArray arrayWithObjects:url, nil]]; // NSArray (and NSURL) autoreleased
6753 if (WDL_remove_filepart(tmp))
6755 fnstr=(NSString *)SWELL_CStringToCFString(tmp);
6756 ret=[wk openFile:fnstr];
6762 else if (strlen(fn)>4 && !stricmp(fn+strlen(fn)-4,".app"))
6764 fnstr=(NSString *)SWELL_CStringToCFString(fn);
6765 ret=[wk launchApplication:fnstr];
6769 fnstr=(NSString *)SWELL_CStringToCFString(fn);
6770 ret=[wk openFile:fnstr];
6781 @implementation SWELL_FocusRectWnd
6783 -(BOOL)isOpaque { return YES; }
6784 -(void) drawRect:(NSRect)rect
6786 NSColor *col=[NSColor colorWithCalibratedRed:0.5 green:0.5 blue:0.5 alpha:1.0];
6789 CGRect r = CGRectMake(rect.origin.x,rect.origin.y,rect.size.width,rect.size.height);
6791 CGContextRef ctx = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
6793 CGContextFillRect(ctx,r);
6798 // r=NULL to "free" handle
6799 // otherwise r is in hwndPar coordinates
6800 void SWELL_DrawFocusRect(HWND hwndPar, RECT *rct, void **handle)
6802 if (!handle) return;
6803 NSWindow *wnd = (NSWindow *)*handle;
6809 NSWindow *ow=[wnd parentWindow];
6810 if (ow) [ow removeChildWindow:wnd];
6811 // [wnd setParentWindow:nil];
6821 ClientToScreen(hwndPar,((LPPOINT)&r));
6822 ClientToScreen(hwndPar,((LPPOINT)&r)+1);
6828 if (r.top>r.bottom) { int a=r.top; r.top=r.bottom;r.bottom=a; }
6829 NSRect rr=NSMakeRect(r.left,r.top,r.right-r.left,r.bottom-r.top);
6834 if ([(id)hwndPar isKindOfClass:[NSWindow class]]) par=(NSWindow *)hwndPar;
6835 else if ([(id)hwndPar isKindOfClass:[NSView class]]) par=[(NSView *)hwndPar window];
6839 if (wnd && ([wnd parentWindow] != par))
6841 NSWindow *ow=[wnd parentWindow];
6842 if (ow) [ow removeChildWindow:wnd];
6843 // [wnd setParentWindow:nil];
6851 *handle = wnd = [[NSWindow alloc] initWithContentRect:rr styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
6852 [wnd setOpaque:YES];
6853 [wnd setAlphaValue:0.5];
6854 [wnd setExcludedFromWindowsMenu:YES];
6855 [wnd setIgnoresMouseEvents:YES];
6856 [wnd setContentView:[[SWELL_FocusRectWnd alloc] init]];
6858 if (par) [par addChildWindow:wnd ordered:NSWindowAbove];
6861 [wnd setLevel:NSPopUpMenuWindowLevel];
6862 [wnd orderFront:wnd];
6864 // [wnd setParentWindow:par];
6865 // [wnd orderWindow:NSWindowAbove relativeTo:[par windowNumber]];
6868 [wnd setFrame:rr display:YES];
6873 @implementation SWELL_PopUpButton
6874 STANDARD_CONTROL_NEEDSDISPLAY_IMPL("combobox")
6878 self = [super init];
6886 -(void)setSwellStyle:(LONG)style { m_style=style; }
6887 -(LONG)getSwellStyle { return m_style; }
6888 -(LONG_PTR)getSwellUserData { return m_userdata; }
6889 -(void)setSwellUserData:(LONG_PTR)val { m_userdata=val; }
6892 @implementation SWELL_ComboBox
6893 STANDARD_CONTROL_NEEDSDISPLAY_IMPL("combobox")
6895 -(void)setSwellStyle:(LONG)style { m_style=style; }
6896 -(LONG)getSwellStyle { return m_style; }
6898 self = [super init];
6901 m_ids=new WDL_PtrList<char>;
6902 m_ignore_selchg = -1;
6903 m_disable_menu = false;
6909 -(void)dealloc { delete m_ids; [super dealloc]; }
6910 - (BOOL)becomeFirstResponder;
6912 BOOL didBecomeFirstResponder = [super becomeFirstResponder];
6913 if (didBecomeFirstResponder) SendMessage(GetParent((HWND)self),WM_COMMAND,MAKELONG([self tag],EN_SETFOCUS),(LPARAM)self);
6914 return didBecomeFirstResponder;
6917 - (NSMenu *)textView:(NSTextView *)view
6919 forEvent:(NSEvent *)event
6920 atIndex:(NSUInteger)charIndex
6922 return m_disable_menu ? nil : menu;
6925 - (void)swellDisableContextMenu:(bool)dis
6929 -(LONG_PTR)getSwellUserData { return m_userdata; }
6930 -(void)setSwellUserData:(LONG_PTR)val { m_userdata=val; }
6937 bool SWELL_HandleMouseEvent(NSEvent *evt)
6939 NSEventType etype = [evt type];
6940 if (GetCapture()) return false;
6941 if (etype >= NSLeftMouseDown && etype <= NSRightMouseDragged)
6946 NSWindow *w = [evt window];
6949 NSView *cview = [w contentView];
6950 NSView *besthit=NULL;
6953 NSPoint lpt = [evt locationInWindow];
6954 NSView *hitv=[cview hitTest:lpt];
6955 lpt = [w convertBaseToScreen:lpt];
6957 int xpos=(int)floor(lpt.x + 0.5);
6958 int ypos=(int)floor(lpt.y + 0.5);
6962 int ht=(int)sendSwellMessage(hitv,WM_NCHITTEST,0,MAKELPARAM(xpos,ypos));
6963 if (ht && ht != HTCLIENT) besthit=hitv;
6965 if (hitv==cview) break;
6966 hitv = [hitv superview];
6971 if (etype == NSLeftMouseDown) [besthit mouseDown:evt];
6972 else if (etype == NSLeftMouseUp) [besthit mouseUp:evt];
6973 else if (etype == NSLeftMouseDragged) [besthit mouseDragged:evt];
6974 else if (etype == NSRightMouseDown) [besthit rightMouseDown:evt];
6975 else if (etype == NSRightMouseUp) [besthit rightMouseUp:evt];
6976 else if (etype == NSRightMouseDragged) [besthit rightMouseDragged:evt];
6977 else if (etype == NSMouseMoved) [besthit mouseMoved:evt];
6986 int SWELL_GetWindowWantRaiseAmt(HWND h)
6988 SWELL_ModelessWindow* mw=0;
6989 if ([(id)h isKindOfClass:[SWELL_ModelessWindow class]])
6991 mw=(SWELL_ModelessWindow*)h;
6993 else if ([(id)h isKindOfClass:[NSView class]])
6995 NSWindow* wnd=[(NSView*)h window];
6996 if (wnd && [wnd isKindOfClass:[SWELL_ModelessWindow class]])
6998 mw=(SWELL_ModelessWindow*)wnd;
7005 if (mw) return mw->m_wantraiseamt;
7009 void SWELL_SetWindowWantRaiseAmt(HWND h, int amt)
7011 SWELL_ModelessWindow *mw=NULL;
7012 if ([(id)h isKindOfClass:[SWELL_ModelessWindow class]]) mw=(SWELL_ModelessWindow *)h;
7013 else if ([(id)h isKindOfClass:[NSView class]])
7015 NSWindow *w = [(NSView *)h window];
7016 if (w && [w isKindOfClass:[SWELL_ModelessWindow class]]) mw = (SWELL_ModelessWindow*)w;
7020 int diff = amt - mw->m_wantraiseamt;
7021 mw->m_wantraiseamt = amt;
7022 if (diff && [NSApp isActive]) [mw setLevel:[mw level]+diff];
7031 int SWELL_SetWindowLevel(HWND hwnd, int newlevel)
7033 NSWindow *w = (NSWindow *)hwnd;
7034 if (w && [w isKindOfClass:[NSView class]]) w= [(NSView *)w window];
7036 if (WDL_NORMALLY(w && [w isKindOfClass:[NSWindow class]]))
7038 int ol = (int)[w level];
7039 [w setLevel:newlevel];
7045 void SetAllowNoMiddleManRendering(HWND h, bool allow)
7047 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_hwndChild class]])) return;
7048 SWELL_hwndChild* v = (SWELL_hwndChild*)h;
7049 v->m_allow_nomiddleman = allow;
7052 void SetOpaque(HWND h, bool opaque)
7054 if (WDL_NOT_NORMALLY(!h || ![(id)h isKindOfClass:[SWELL_hwndChild class]])) return;
7055 SWELL_hwndChild* v = (SWELL_hwndChild*)h;
7056 [v setOpaque:opaque];
7059 void SetTransparent(HWND h)
7061 if (WDL_NOT_NORMALLY(!h)) return;
7063 if ([(id)h isKindOfClass:[NSWindow class]]) wnd=(NSWindow*)h;
7064 else if ([(id)h isKindOfClass:[NSView class]]) wnd=[(NSView*)h window];
7065 if (WDL_NORMALLY(wnd))
7067 [wnd setBackgroundColor:[NSColor clearColor]];
7072 int SWELL_GetDefaultButtonID(HWND hwndDlg, bool onlyIfEnabled)
7074 if (WDL_NOT_NORMALLY(![(id)hwndDlg isKindOfClass:[NSView class]])) return 0;
7075 NSWindow *wnd = [(NSView *)hwndDlg window];
7076 NSButtonCell * cell = wnd ? [wnd defaultButtonCell] : nil;
7078 if (!cell || !(view=[cell controlView])) return 0;
7079 int cmdid = (int)[view tag];
7080 if (cmdid && onlyIfEnabled)
7082 if (![cell isEnabled]) return 0;
7088 void SWELL_SetWindowRepre(HWND hwnd, const char *fn, bool isDirty)
7090 if (WDL_NOT_NORMALLY(!hwnd)) return;
7092 if ([(id)hwnd isKindOfClass:[NSWindow class]]) w=(NSWindow *)hwnd;
7093 if ([(id)hwnd isKindOfClass:[NSView class]]) w=[(NSView *)hwnd window];
7095 if (WDL_NORMALLY(w))
7097 if (GetProp((HWND)[w contentView],"SWELL_DisableWindowRepre")) return;
7099 [w setDocumentEdited:isDirty];
7101 if (!fn || !*fn) [w setRepresentedFilename:@""];
7104 NSString *str = (NSString *)SWELL_CStringToCFString(fn);
7105 [w setRepresentedFilename:str];
7111 void SWELL_SetWindowShadow(HWND hwnd, bool shadow)
7113 if (WDL_NOT_NORMALLY(!hwnd)) return;
7114 NSWindow *w = (NSWindow *)hwnd;
7115 if ([w isKindOfClass:[NSView class]]) w = [(NSView *)w window];
7116 if (WDL_NORMALLY(w && [w isKindOfClass:[NSWindow class]])) [w setHasShadow:shadow];
7119 #if 0 // not sure if this will interfere with coolSB
7120 BOOL ShowScrollBar(HWND hwnd, int nBar, BOOL vis)
7123 if (nBar == SB_HORZ || nBar == SB_BOTH) v |= WS_HSCROLL;
7124 if (nBar == SB_VERT || nBar == SB_BOTH) v |= WS_VSCROLL;
7127 int s=GetWindowLong(hwnd, GWL_STYLE);
7130 SetWindowLong(hwnd, GWL_STYLE, s);
7131 SetWindowPos(hwnd, 0, 0, 0, 0, 0, SWP_FRAMECHANGED|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
7139 void SWELL_GenerateDialogFromList(const void *_list, int listsz)
7141 #define SIXFROMLIST list->p1,list->p2,list->p3, list->p4, list->p5, list->p6
7142 SWELL_DlgResourceEntry *list = (SWELL_DlgResourceEntry*)_list;
7145 if (!strcmp(list->str1,"__SWELL_BUTTON"))
7147 SWELL_MakeButton(list->flag1,list->str2, SIXFROMLIST);
7149 else if (!strcmp(list->str1,"__SWELL_EDIT"))
7151 SWELL_MakeEditField(SIXFROMLIST);
7153 else if (!strcmp(list->str1,"__SWELL_COMBO"))
7155 SWELL_MakeCombo(SIXFROMLIST);
7157 else if (!strcmp(list->str1,"__SWELL_LISTBOX"))
7159 SWELL_MakeListBox(SIXFROMLIST);
7161 else if (!strcmp(list->str1,"__SWELL_GROUP"))
7163 SWELL_MakeGroupBox(list->str2,SIXFROMLIST);
7165 else if (!strcmp(list->str1,"__SWELL_CHECKBOX"))
7167 SWELL_MakeCheckBox(list->str2,SIXFROMLIST);
7169 else if (!strcmp(list->str1,"__SWELL_LABEL"))
7171 SWELL_MakeLabel(list->flag1, list->str2, SIXFROMLIST);
7173 else if (!strcmp(list->str1,"__SWELL_ICON"))
7175 // todo (str2 is likely a (const char *)(INT_PTR)resid
7177 else if (*list->str2)
7179 SWELL_MakeControl(list->str1, list->flag1, list->str2, SIXFROMLIST);
7186 BOOL EnumChildWindows(HWND hwnd, BOOL (*cwEnumFunc)(HWND,LPARAM),LPARAM lParam)
7188 if (WDL_NOT_NORMALLY(!hwnd || ![(id)hwnd isKindOfClass:[NSView class]])) return TRUE;
7189 NSArray *ar = [(NSView *)hwnd subviews];
7193 NSInteger x,n=[ar count];
7196 NSView *v = [ar objectAtIndex:x];
7199 if ([v isKindOfClass:[NSScrollView class]])
7201 NSView *sv=[(NSScrollView *)v documentView];
7204 if ([v isKindOfClass:[NSClipView class]])
7206 NSView *sv = [(NSClipView *)v documentView];
7210 if (!cwEnumFunc((HWND)v,lParam) || !EnumChildWindows((HWND)v,cwEnumFunc,lParam))
7222 void SWELL_GetDesiredControlSize(HWND hwnd, RECT *r)
7224 if (WDL_NORMALLY(hwnd && r && [(id)hwnd isKindOfClass:[NSControl class]]))
7226 NSControl *c = (NSControl *)hwnd;
7227 NSRect fr = [c frame];
7229 NSRect frnew=[c frame];
7232 r->right = (int)(frnew.size.width+0.5);
7233 r->bottom = (int)(frnew.size.height+0.5);
7237 BOOL SWELL_IsGroupBox(HWND hwnd)
7239 if (WDL_NORMALLY(hwnd) && [(id)hwnd isKindOfClass:[SWELL_BoxView class]])
7241 if (![(id)hwnd respondsToSelector:@selector(swellIsEtchBox)] || ![(SWELL_BoxView *)hwnd swellIsEtchBox])
7246 BOOL SWELL_IsButton(HWND hwnd)
7248 if (WDL_NORMALLY(hwnd) && [(id)hwnd isKindOfClass:[SWELL_Button class]]) return TRUE;
7251 BOOL SWELL_IsStaticText(HWND hwnd)
7253 if (WDL_NORMALLY(hwnd) && [(id)hwnd isKindOfClass:[NSTextField class]])
7255 NSTextField *obj = (NSTextField *)hwnd;
7256 if (![obj isEditable] && ![obj isSelectable])
7262 void SWELL_SetClassName(HWND hwnd, const char *p)
7264 if (WDL_NORMALLY(hwnd && [(id)hwnd isKindOfClass:[SWELL_hwndChild class]]))
7265 ((SWELL_hwndChild *)hwnd)->m_classname=p;
7268 int GetClassName(HWND hwnd, char *buf, int bufsz)
7270 if (WDL_NOT_NORMALLY(!hwnd || !buf || bufsz<1)) return 0;
7272 if ([(id)hwnd respondsToSelector:@selector(getSwellClass)])
7274 const char *cn = [(SWELL_hwndChild*)hwnd getSwellClass];
7275 if (cn) lstrcpyn_safe(buf,cn,bufsz);
7277 else if ([(id)hwnd isKindOfClass:[NSButton class]])
7279 lstrcpyn_safe(buf,"Button",bufsz);
7281 else if ([(id)hwnd isKindOfClass:[NSTextField class]])
7283 NSTextField *obj = (NSTextField *)hwnd;
7284 if (![obj isEditable] && ![obj isSelectable])
7285 lstrcpyn_safe(buf,"Static",bufsz);
7287 lstrcpyn_safe(buf,"Edit",bufsz);
7291 // default handling of other controls?
7294 return (int)strlen(buf);
7299 bool SWELL_SetAppAutoHideMenuAndDock(int ah)
7302 static NSUInteger _defpres;
7305 if (SWELL_GetOSXVersion()>=0x1060)
7308 _defpres = [(SWELL_AppExtensions*)[NSApplication sharedApplication] presentationOptions];
7317 const int NSApplicationPresentationAutoHideDock = (1 << 0),
7318 NSApplicationPresentationHideDock = (1<<1),
7319 NSApplicationPresentationAutoHideMenuBar = (1 << 2);
7321 if (ah>0) [(SWELL_AppExtensions*)[NSApplication sharedApplication] setPresentationOptions:((ah>=2?NSApplicationPresentationHideDock:NSApplicationPresentationAutoHideDock)|NSApplicationPresentationAutoHideMenuBar)];
7322 else [(SWELL_AppExtensions*)[NSApplication sharedApplication] setPresentationOptions:_defpres];
7329 void SWELL_DisableContextMenu(HWND hwnd, bool dis)
7331 if (WDL_NORMALLY(hwnd && [(id)hwnd respondsToSelector:@selector(swellDisableContextMenu:)]))
7332 [(SWELL_TextField*)hwnd swellDisableContextMenu:dis];
7335 extern char g_swell_disable_retina;
7336 int SWELL_IsRetinaHWND(HWND hwnd)
7338 if (!hwnd || SWELL_GetOSXVersion() < 0x1070) return 0;
7340 int retina_disabled = g_swell_disable_retina;
7342 if ([(id)hwnd isKindOfClass:[NSView class]])
7344 if (retina_disabled &&
7345 [(id)hwnd isKindOfClass:[SWELL_hwndChild class]] &&
7346 ((SWELL_hwndChild*)hwnd)->m_glctx != NULL)
7347 retina_disabled = 0;
7349 w = [(NSView *)hwnd window];
7351 else if ([(id)hwnd isKindOfClass:[NSWindow class]]) w = (NSWindow *)hwnd;
7353 if (retina_disabled) return 0;
7357 NSRect r=NSMakeRect(0,0,1,1);
7358 #if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_6
7359 NSRect str = [w convertRectToBacking:r];
7361 NSRect (*tmp)(id receiver, SEL operation, NSRect) = (NSRect (*)(id, SEL, NSRect))objc_msgSend_stret;
7362 NSRect str = tmp(w,sel_getUid("convertRectToBacking:"),r);
7365 if (str.size.width > 1.9) return 1;
7370 const char *SWELL_GetRecentPrefixRemoval(const char *p)
7372 for (int x = 0; x < s_prefix_removals.GetSize(); x ++)
7374 const char *s = s_prefix_removals.Get(x);
7375 if (!strcmp(s,p)) return s+strlen(s)+1;