Here is a solution.
Update v1.02.1
- Bugfixes
Update v1.02.2
- Bugfix Mouse position
Update v1.03.1
- Change NSString to NSPasteboardItem
Code: Select all
;-TOP Dump Object Methods
; by mk-soft, 29.12.2019 - 06.10.2023, v1.09.1
Declare.s DumpObjectMethods(*Object, SuperLevel = 0, HidePrivate = #True, ShowEncoding = #False, FirstArgument = 2)
Structure ArrayOfMethods
i.i[0]
EndStructure
ImportC ""
class_copyMethodList(*Class, *p_methodCount)
; -> An array of pointers of type Method describing
; the instance methods implemented by the class
; Any instance methods implemented by superclasses are Not included
; You must free the array with free()
class_getName(*Class) ; -> UnsafePointer<Int8> -> *string
sel_getName(*Selector); -> const char *
method_getName(*Method) ; -> Selector
method_getTypeEncoding(*Method) ; -> const char *
method_getReturnType(*Method, *dst, dst_len) ; -> void
method_getNumberOfArguments(*Method) ; -> unsigned int
method_getArgumentType(*Method, index, *dst, dst_len) ; -> void
NSGetSizeAndAlignment(*StringPtr, *p_size, *p_align)
; -> const char *
; Obtains the actual size and the aligned size of an encoded type.
EndImport
; ----
Procedure.s GetArgumentType(*String)
Protected r1.s, arg.s, size.i, ofs.i
arg = PeekS(*String, -1, #PB_UTF8)
r1 + arg + " - "
If Left(arg, 1) = "^"
r1 + "A pointer to type of "
arg = Mid(arg, 2)
EndIf
Select arg
Case "c" : r1 + "A char "
Case "i" : r1 + "An int "
Case "s" : r1 + "A short "
Case "l" : r1 + "A long "
Case "q" : r1 + "A long long"
Case "C" : r1 + "An unsigned char "
Case "I" : r1 + "An unsigned int "
Case "S" : r1 + "An unsigned short "
Case "L" : r1 + "An unsigned long "
Case "Q" : r1 + "An unsigned long long "
Case "f" : r1 + "A float "
Case "d" : r1 + "A double "
Case "B" : r1 + "A C++ bool Or a C99 _Bool "
Case "v" : r1 + "A void"
Case "*" : r1 + "A character string (char *) "
Case "@" : r1 + "An object (whether statically typed Or typed id) "
Case "#" : r1 + "A class object (Class) "
Case ":" : r1 + "A method selector (SEL) "
Default:
NSGetSizeAndAlignment(*String, @size, @ofs)
r1 + "[" + Str(size) + " bytes]"
EndSelect
If Right(arg, 1) = "?"
r1 + "An unknown type (e.g. function pointer)"
EndIf
ProcedureReturn r1
EndProcedure
; ----
Procedure.s DumpObjectMethods(*Object, SuperLevel = 0, HidePrivate = #True, ShowEncoding = #False, FirstArgument = 2)
Protected result.s, r1.s, i, c, n, methodCount, Method.s
Protected *Class, *SuperClass, *Method, *Methods.ArrayOfMethods
Protected *String
*Class = object_getclass_(*Object)
If *Class
*String = AllocateMemory(1024)
r1 = PeekS(class_getName(*Class), -1, #PB_UTF8)
If SuperLevel
For i = 1 To SuperLevel
*SuperClass = class_getsuperclass_(*Class)
If *SuperClass
*Class = *SuperClass
r1 + " -> " + PeekS(class_getName(*Class), -1, #PB_UTF8)
Else
Break
EndIf
Next
EndIf
*Methods = class_copyMethodList(*Class, @methodCount)
r1 + #LF$ + #LF$ + "Count of Methods: " + methodCount + #LF$
result = r1 + #LF$
Debug r1
r1 = ""
For i = 0 To methodCount - 1
*Method = *Methods\i[i];
Method = PeekS(sel_getName(method_getName(*Method)), -1, #PB_UTF8)
If HidePrivate And Left(Method, 1) = "_"
Continue
EndIf
r1 + "Method " + Method + #LF$
If ShowEncoding
r1 + " * Encoding " + PeekS(method_getTypeEncoding(*Method), -1, #PB_UTF8) + #LF$
EndIf
method_getReturnType(*Method, *String, 1024)
r1 + " -- ReturnType = " + GetArgumentType(*String) + #LF$
c = method_getNumberOfArguments(*Method)
For n = FirstArgument To c - 1
method_getArgumentType(*Method, n, *String, 1024)
r1 + " -- Argument " + Str(n - FirstArgument + 1) + " = " + GetArgumentType(*String) + #LF$
Next
result + r1 + #LF$
Debug r1
r1 = ""
Next
r1 + "End Class" + #LF$
result + r1 + #LF$
Debug r1
If *Methods
free_(*Methods)
EndIf
FreeMemory(*String)
Else
r1 = "Object is nil" + #LF$
result = r1
Debug r1
EndIf
ProcedureReturn result
EndProcedure
; ****
;-TOP EnableGadgetDrag
; Comment : EnableGadgetDrag for ListIconGadget and ListViewGadget
; Author : mk-soft
; Version : v1.03.1
; Create : 19.01.2025
; Update : 22.01.2025
; ----
ProcedureC MyTableViewDraggingSessionWillBeginAtPointForRowIndexes(Object, Selector, Table, Session, IndexSet, PointX.d, PointY.d)
;TODO Create drag image
EndProcedure
; ----
; Own delegate method tableView:pasteboardWriterForRow:
Global *NSPasteboardTypeString.Integer = dlsym_(#RTLD_DEFAULT, "NSPasteboardTypeString")
ProcedureC MyTableViewPasteboardWriterForRow(Object, Selector, Table, Row)
Protected window, gadget, column, text.s, count, pt.nspoint, string
; Check that the column is valid, otherwise no dragging image can be created and an error will occur.
window = GetActiveWindow()
gadget = CocoaMessage(0, Table, "tag")
If window >= 0
pt\x = WindowMouseX(window) - GadgetX(gadget)
pt\y = WindowMouseY(window) - GadgetY(gadget)
column = CocoaMessage(0, Table, "columnAtPoint:@", @pt)
If column >= 0
text = GetGadgetItemText(gadget, row, 0)
; Copy all columns
If GadgetType(gadget) = #PB_GadgetType_ListIcon
count = GetGadgetAttribute(gadget, #PB_ListIcon_ColumnCount) - 1
For column = 1 To count
text + #TAB$ + GetGadgetItemText(gadget, row, column)
Next
EndIf
; Return value is a pasteboard item
pasteboarditem = CocoaMessage(0, 0, "NSPasteboardItem new")
CocoaMessage(0, pasteboarditem, "setString:$", @text, "forType:", *NSPasteboardTypeString\i)
ProcedureReturn pasteboarditem
EndIf
; Cancel dragging
ProcedureReturn 0
EndIf
EndProcedure
; ----
Procedure EnableGadgetDrag(Gadget)
Static oldClassListIcon, newClassListIcon
Static oldClassListView, newClassListView
Protected NSTableView = GadgetID(Gadget)
Protected delegate, class, newClass, oldClass, selector
; Get delegate class
delegate = CocoaMessage(0, NSTableView, "delegate")
class = object_getClass_(delegate)
Select GadgetType(Gadget)
Case #PB_GadgetType_ListIcon
; Check is method exists
If Not newClassListIcon
; Create new delegate class
newClassListIcon = objc_allocateClassPair_(class, "PBListIconGadgetFunctionsEx", 0)
objc_registerClassPair_(newClassListIcon)
; Add new method
selector = sel_registerName_("tableView:pasteboardWriterForRow:")
imp = class_addMethod_(newClassListIcon, selector, @MyTableViewPasteboardWriterForRow(), "@@:@i")
selector = sel_registerName_("tableView:draggingSession:willBeginAtPoint:forRowIndexes:")
imp = class_addMethod_(newClassListIcon, selector, @MyTableViewDraggingSessionWillBeginAtPointForRowIndexes(), "@@:@@@@")
oldClassListIcon = object_setClass_(delegate, newClassListIcon)
Else
If class = oldClassListIcon
object_setClass_(delegate, newClassListIcon)
EndIf
EndIf
ProcedureReturn newClassListIcon
Case #PB_GadgetType_ListView
; Check is method exists
If Not newClassListView
; Create new delegate class
newClassListView = objc_allocateClassPair_(class, "PBListViewGadgetFunctionsEx", 0)
objc_registerClassPair_(newClassListView)
; Add new method
selector = sel_registerName_("tableView:pasteboardWriterForRow:")
imp = class_addMethod_(newClassListView, selector, @MyTableViewPasteboardWriterForRow(), "@@:@i")
selector = sel_registerName_("tableView:draggingSession:willBeginAtPoint:forRowIndexes:")
imp = class_addMethod_(newClassListView, selector, @MyTableViewDraggingSessionWillBeginAtPointForRowIndexes(), "@@:@@@@")
oldClassListView = object_setClass_(delegate, newClassListView)
Else
If class = oldClassListView
object_setClass_(delegate, newClassListView)
EndIf
EndIf
ProcedureReturn newClassListView
Default
ProcedureReturn 0
EndSelect
EndProcedure
; ********
;- Example
CompilerIf #PB_Compiler_IsMainFile
Procedure DoEventDropText()
Protected droptext.s, text.s, cnt, i
droptext = EventDropText()
cnt = CountString(droptext, #LF$) + 1
For i = 1 To cnt
text = StringField(droptext, i, #LF$)
ReplaceString(text, #TAB$, #LF$, #PB_String_InPlace)
AddGadgetItem(EventGadget(), -1, text)
Next
EndProcedure
; ----
Procedure UpdateWindow()
Protected dx, dy
dx = WindowWidth(0)
dy = WindowHeight(0) - StatusBarHeight(0) - MenuHeight()
; Resize Gadgets
ResizeGadget(0, 0, 0, dx / 2, dy)
ResizeGadget(1, dx / 2, 0, dx / 2, dy)
EndProcedure
Procedure Main()
Protected dx, dy
#WinStyle = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget
If OpenWindow(0, #PB_Ignore, #PB_Ignore, 1200, 400, "Test Window Drag and Drop Text", #WinStyle)
; MenuBar
CreateMenu(0, WindowID(0))
MenuTitle("&File")
MenuItem(99, "E&xit")
; StatusBar
CreateStatusBar(0, WindowID(0))
AddStatusBarField(#PB_Ignore)
; Gadgets
dx = WindowWidth(0)
dy = WindowHeight(0) - StatusBarHeight(0) - MenuHeight()
ListIconGadget(0, 0, 0, dx / 2, dy, "Column 0", 200, #PB_ListIcon_MultiSelect)
AddGadgetColumn(0, 1, "Column 1", 200)
ListIconGadget(1, dx / 2, 0, dx / 2, dy, "Column 0", 200)
AddGadgetColumn(1, 1, "Column 1", 200)
;ListViewGadget(1, dx / 2, 0, dx / 2, dy)
For i = 0 To 9
AddGadgetItem(0, -1, "Item 0." + i + #LF$ + "Item 1." + i)
Next
; Bind Events
BindEvent(#PB_Event_SizeWindow, @UpdateWindow(), 0)
BindEvent(#PB_Event_GadgetDrop, @DoEventDropText())
EnableGadgetDrag(0)
EnableGadgetDrag(1)
EnableGadgetDrop(0, #PB_Drop_Text, #PB_Drag_Copy)
EnableGadgetDrop(1, #PB_Drop_Text, #PB_Drag_Copy)
;delegate = CocoaMessage(0, GadgetID(0), "delegate")
;DumpObjectMethods(delegate, 0)
;DumpObjectMethods(delegate, 1)
; Main Loop
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Select EventWindow()
Case 0
Break
EndSelect
Case #PB_Event_Menu
Select EventMenu()
Case 99
PostEvent(#PB_Event_CloseWindow, 0, 0)
EndSelect
Case #PB_Event_Gadget
Select EventGadget()
EndSelect
EndSelect
ForEver
EndIf
EndProcedure : Main()
CompilerEndIf