How can I add a second Callback to a ListIconGadget() ?
I need one to be able to edit the items and one to add a ComboBoxGadget() in one row of the ListIconGadget().
How to add a second Callback ???
How to add a second Callback ???
macOS Catalina 10.15.7
Re: How to add a second Callback ???
I'm not sure what you mean by a second callback.
Can't you use BindEvent ?
Can't you use BindEvent ?
Windows (x64)
Raspberry Pi OS (Arm64)
Raspberry Pi OS (Arm64)
Re: How to add a second Callback ???
In this example only one callback work. If I remove the first one the second will work.wilbert wrote:I'm not sure what you mean by a second callback.
Can't you use BindEvent ?
Code: Select all
ImportC ""
sel_registerName(MethodName.S)
class_addMethod(Class.I, Selector.I, Implementation.I, Types.S)
EndImport
Procedure.S ConvertToUTF8(String.S)
Protected UTF8String.S = Space(StringByteLength(String))
PokeS(@UTF8String, String, -1, #PB_UTF8)
ProcedureReturn UTF8String
EndProcedure
ProcedureC EditingFinishedCallback(Object.I, Selector.I, Notification.I)
Protected EditedCell.I
Protected EditedColumn.I = CocoaMessage(0, GadgetID(0), "editedColumn")
Protected EditedRow.I = CocoaMessage(0, GadgetID(0), "editedRow")
Protected EditedText.S
EditedCell = CocoaMessage(0, Notification, "object")
EditedText = PeekS(CocoaMessage(0, CocoaMessage(0, EditedCell, "stringValue"),
"UTF8String"), -1, #PB_UTF8)
SetGadgetItemText(0, EditedRow, EditedText, EditedColumn)
Debug "Edit finished"
EndProcedure
ProcedureC GetViewForCellCallback(Object.I, Selector.I, TableView.I,
ColumnObject.I, Row.I)
Protected CellContent.S
Protected Column.I
Protected ColumnID.S = PeekS(CocoaMessage(0, CocoaMessage(0,
ColumnObject, "identifier"), "UTF8String"), -1, #PB_UTF8)
Protected ComboBox.I
Protected TextFrame.NSRect
Protected View.I
Column = Val(ColumnID)
If Column = 1
; ----- If column = 1, create ComboBox and return it
ComboBox = CocoaMessage(0, 0, "NSComboBox new")
CocoaMessage(0, ComboBox, "addItemWithObjectValue:$",
@"AAA")
CocoaMessage(0, ComboBox, "addItemWithObjectValue:$",
@"BBB")
CocoaMessage(0, ComboBox, "addItemWithObjectValue:$",
@"CCC")
View = ComboBox
Else
; ----- If Column <> 1, read current cell content, create new view with
; NSTextField, write current content into that view and return it
CellContent = GetGadgetItemText(0, Row, Column)
TextFrame\size\width = GetGadgetItemAttribute(0,
#PB_ListIcon_ColumnWidth, Column)
TextFrame\size\height = 18
View = CocoaMessage(0, CocoaMessage(0, 0, "NSTextField new"),
"initWithFrame:@", TextFrame)
CocoaMessage(0, View, "setStringValue:$", @CellContent)
EndIf
ProcedureReturn View
EndProcedure
Define CursorLocation.NSPoint
Define AppDelegate.I = CocoaMessage(0, CocoaMessage(0, 0,
"NSApplication sharedApplication"), "delegate")
Define DelegateClass.I = CocoaMessage(0, AppDelegate, "class")
Define NotificationCenter.I = CocoaMessage(0, 0,
"NSNotificationCenter defaultCenter")
Define SelectedColumn.I
Define Selector.I = sel_registerName(ConvertToUTF8("textDidEndEditing:"))
Define RowHeight.CGFloat = 25
Define Selector2.I = sel_registerName_("tableView:viewForTableColumn:row:")
OpenWindow(0, 200, 100, 430, 195, "Editable ListIconGadget demo II")
ListIconGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20, "Name", 110)
AddGadgetColumn(0, 1, "Address1", 292)
AddGadgetColumn(0, 2, "Address2", GadgetWidth(0) - GetGadgetItemAttribute(0,
0, #PB_ListIcon_ColumnWidth) - 8)
AddGadgetItem(0, -1, "Harry Rannit" + #LF$ + "")
AddGadgetItem(0, -1, "Ginger Brokeit" + #LF$ + "")
AddGadgetItem(0, -1, "Didi Foundit" + #LF$ + "")
CocoaMessage(0, GadgetID(0), "setSelectionHighlightStyle:", -1)
; ----- Increase row height to be able to display larger ComboBox
CocoaMessage(0, GadgetID(0), "setRowHeight:@", @RowHeight)
; ----- Initialize callback that returns a new NSView (view-based) instead
; of the old NSCell (cell-based) for each cell drawn
class_addMethod_(DelegateClass, Selector2, @GetViewForCellCallback(), "v@:@@@")
CocoaMessage(0, GadgetID(0), "setDelegate:", AppDelegate)
class_addMethod(DelegateClass, Selector, @EditingFinishedCallback(), "v@:@")
CocoaMessage(0, NotificationCenter,
"addObserver:", AppDelegate,
"selector:", Selector,
"name:$", @"NSControlTextDidEndEditingNotification",
"object:", GadgetID(0))
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Gadget
If EventGadget() = 0 And EventType() = #PB_EventType_LeftClick
CursorLocation\x = WindowMouseX(0)
CursorLocation\y = WindowHeight(0) - WindowMouseY(0)
CocoaMessage(@CursorLocation, GadgetID(0),
"convertPoint:@", @CursorLocation, "fromView:", 0)
SelectedColumn = CocoaMessage(0, GadgetID(0),
"columnAtPoint:@", @CursorLocation)
CocoaMessage(0, GadgetID(0),
"editColumn:", SelectedColumn,
"row:", GetGadgetState(0),
"withEvent:", 0,
"select:", #YES)
EndIf
EndSelect
ForEver
macOS Catalina 10.15.7
Re: How to add a second Callback ???
Sorry, but your problem can't be solved by a second callback. You have taken my example for adding ComboBoxes to cells in a column of a ListIconGadget and added my example to edit single cells. Unfortunately my first example is a hack. Although the example is working fine, it's messing around with PureBasic internals by replacing PureBasic's NSCells (cell-based) in the ListIconGadget with view-based NSComboBoxes and NSTextFields. As a result the PureBasic event loop doesn't work correctly anymore for the ListIconGadget, so that the method editColumn:row:withEvent:select: in the event loop is never called!
The only solution seems to be to replace PureBasic's NSCell objects (cell-based) by NSComboBoxCell objects (also cell-based). This seems to work so far, but until now I wasn't able to detect the selection of a ComboBox element and display the chosen element in the ComboBox. After selecting an element from the ComboBox, the selected element is always briefly displayed in the ComboBox but cleared after a very short period. I currently don't know whether this technique is possibly interfering with PureBasic internals...
The only solution seems to be to replace PureBasic's NSCell objects (cell-based) by NSComboBoxCell objects (also cell-based). This seems to work so far, but until now I wasn't able to detect the selection of a ComboBox element and display the chosen element in the ComboBox. After selecting an element from the ComboBox, the selected element is always briefly displayed in the ComboBox but cleared after a very short period. I currently don't know whether this technique is possibly interfering with PureBasic internals...
Re: How to add a second Callback ???
I have finally found a solution which utilizes NSComboBoxCells to display ComboBoxes in a column of a ListIconGadget. It's possible to edit the content of normal cells and ComboBox cells (and thereby add new ComboBox items). You may disable the editing of ComboBox cells by setting #ComboBoxEdtitableState to #False.
I have tested this example successfully with PB 5.44 x86 and x64 in ASCII and Unicode mode with these MacOS versions:
- 10.6.8 (Snow Leopard) (it's only compilable with PB 5.44 x86; to compile it with x64 it's necessary to use PB 5.43 x64!)
- 10.8.6 (Mountain Lion)
- 10.9.5 (Mavericks)
- 10.12.1 (Sierra)
I have tested this example successfully with PB 5.44 x86 and x64 in ASCII and Unicode mode with these MacOS versions:
- 10.6.8 (Snow Leopard) (it's only compilable with PB 5.44 x86; to compile it with x64 it's necessary to use PB 5.43 x64!)
- 10.8.6 (Mountain Lion)
- 10.9.5 (Mavericks)
- 10.12.1 (Sierra)
Code: Select all
EnableExplicit
#ListIcon = 0
#ComboBoxColumn = 1
#ComboBoxEditableState = #True ; #True enables editing of ComboBox,
; #False disables it
Define AppDelegate.I = CocoaMessage(0,
CocoaMessage(0, 0, "NSApplication sharedApplication"), "delegate")
Define ColumnObject.I
Define i.I
Define ComboBoxCell.I
Define CursorLocation.NSPoint
Define DelegateClass.I = CocoaMessage(0, AppDelegate, "class")
Define NotificationCenter.I = CocoaMessage(0, 0,
"NSNotificationCenter defaultCenter")
Define RowHeight.CGFloat = 21
Define SelectedCell.I
Define SelectedColumn.I
Define SelectedRow.I
Define Selector1.I = sel_registerName_("itemChanged:")
Define Selector2.I = sel_registerName_("textDidEndEditing:")
Define SubclassedComboBoxCell.I
ProcedureC ComboBoxSelectionChangedCallback(Object.I, Selector.I,
Notification.I)
Protected Cell.I
Protected ItemIndex.I
Protected ItemText.S
Protected Row.I
Cell = CocoaMessage(0, GadgetID(#ListIcon), "selectedCell")
If Cell
Row = CocoaMessage(0, GadgetID(#ListIcon), "selectedRow")
ItemIndex = CocoaMessage(0, Cell, "indexOfSelectedItem")
If ItemIndex >= 0
ItemText = PeekS(CocoaMessage(0, CocoaMessage(0,
Cell, "itemObjectValueAtIndex:", ItemIndex),
"UTF8String"), -1, #PB_UTF8)
If ItemText <> GetGadgetItemText(#ListIcon, Row, #ComboBoxColumn)
SetGadgetItemText(#ListIcon, Row, ItemText, #ComboBoxColumn)
EndIf
EndIf
EndIf
EndProcedure
ProcedureC EditingEndedCallback(Object.I, Selector.I, Notification.I)
Shared ComboBoxCell.I
Protected Cell.I
Protected Column.I = CocoaMessage(0, GadgetID(0), "editedColumn")
Protected Row.I = CocoaMessage(0, GadgetID(0), "editedRow")
Protected Text.S
Cell = CocoaMessage(0, Notification, "object")
Text = PeekS(CocoaMessage(0, CocoaMessage(0, Cell, "stringValue"),
"UTF8String"), -1, #PB_UTF8)
If Column = #ComboBoxColumn
If Trim(Text) <> ""
If CocoaMessage(0, ComboBoxCell,
"indexOfItemWithObjectValue:$", @Text) = #NSNotFound
CocoaMessage(0, ComboBoxCell, "addItemWithObjectValue:$", @Text)
EndIf
EndIf
EndIf
SetGadgetItemText(0, Row, Text, Column)
EndProcedure
OpenWindow(0, 200, 100, 250, 113, "ListIcon with ComboBoxes")
ListIconGadget(#ListIcon, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20,
"Friend", 70, #PB_ListIcon_GridLines)
AddGadgetColumn(#ListIcon, #ComboBoxColumn, "Country",
GadgetWidth(#ListIcon) - GetGadgetItemAttribute(#ListIcon, 0,
#PB_ListIcon_ColumnWidth) - 8)
AddGadgetItem(#ListIcon, -1, "Alice")
AddGadgetItem(#ListIcon, -1, "Bob")
AddGadgetItem(#ListIcon, -1, "Eve")
; ----- Increase row height to be able to display the larger ComboBox
CocoaMessage(0, GadgetID(#ListIcon), "setRowHeight:@", @RowHeight)
; ----- Disable highlighting of selected row
CocoaMessage(0, GadgetID(#ListIcon), "setSelectionHighlightStyle:", -1)
; ----- Center text in column 0 vertically
; Caution: _setVerticallyCentered: is an internal flag; it could simply
; disappear without warning in a future MacOS release and its use may
; lead to a rejection in Apple's AppStore!
ColumnObject = CocoaMessage(0, CocoaMessage(0,
GadgetID(#ListIcon), "tableColumns"), "objectAtIndex:", 0)
CocoaMessage(0, CocoaMessage(0, ColumnObject, "dataCell"),
"_setVerticallyCentered:", #YES)
; ----- Create a NSComboBoxCell (used internally as an editable ComboBox by
; PureBasic) and use it in all cells of column #ComboBoxColumn
ColumnObject = CocoaMessage(0, CocoaMessage(0,
GadgetID(#ListIcon), "tableColumns"), "objectAtIndex:", #ComboBoxColumn)
ComboBoxCell = CocoaMessage(0, 0, "NSComboBoxCell new")
CocoaMessage(0, ColumnObject, "setDataCell:", ComboBoxCell)
; ----- Remove border around button (special style for NSComboBoxCell in
; NSTableView)
CocoaMessage(0, ComboBoxCell, "setButtonBordered:", #NO)
; ----- Fill ComboBox
CocoaMessage(0, ComboBoxCell, "addItemWithObjectValue:$", @"France")
CocoaMessage(0, ComboBoxCell, "addItemWithObjectValue:$", @"Germany")
CocoaMessage(0, ComboBoxCell, "addItemWithObjectValue:$", @"USA")
; ----- Subclass ComboBoxCell
SubclassedComboBoxCell = objc_allocateClassPair_(CocoaMessage(0,
ComboBoxCell, "class"), "SubclassedComboBoxCell", 0)
objc_registerClassPair_(SubclassedComboBoxCell)
object_setClass_(ComboBoxCell, SubclassedComboBoxCell)
; ----- Set callback to detect selection change in ComboBox
class_addMethod_(DelegateClass, Selector1, @ComboBoxSelectionChangedCallback(),
"v@:@")
CocoaMessage(0, NotificationCenter,
"addObserver:", AppDelegate,
"selector:", Selector1,
"name:$", @"NSTableViewSelectionDidChangeNotification",
"object:", CocoaMessage(0, GadgetID(#ListIcon), "menu"))
; ----- Set callback to detect end of editing in ListIcon cell
class_addMethod_(DelegateClass, Selector2, @EditingEndedCallback(), "v@:@")
CocoaMessage(0, NotificationCenter,
"addObserver:", AppDelegate,
"selector:", Selector2,
"name:$", @"NSControlTextDidEndEditingNotification",
"object:", GadgetID(#ListIcon))
SetActiveGadget(#ListIcon)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
CocoaMessage(0, NotificationCenter, "removeObserver:", AppDelegate)
Break
Case #PB_Event_Gadget
If EventGadget() = #ListIcon And EventType() = #PB_EventType_LeftClick
CursorLocation\x = WindowMouseX(0)
CursorLocation\y = WindowHeight(0) - WindowMouseY(0)
CocoaMessage(@CursorLocation, GadgetID(#ListIcon),
"convertPoint:@", @CursorLocation, "fromView:", 0)
SelectedRow = CocoaMessage(0, GadgetID(#ListIcon),
"rowAtPoint:@", @CursorLocation)
SelectedColumn = CocoaMessage(0, GadgetID(#ListIcon),
"columnAtPoint:@", @CursorLocation)
If SelectedColumn = #ComboBoxColumn
SelectedCell = CocoaMessage(0, ColumnObject,
"dataCellForRow:", SelectedRow)
CocoaMessage(0, SelectedCell, "setEditable:", #ComboBoxEditableState)
CocoaMessage(0, GadgetID(#ListIcon),
"editColumn:", SelectedColumn,
"row:", GetGadgetState(#ListIcon),
"withEvent:", 0,
"select:", #YES)
Else
CocoaMessage(0, GadgetID(#ListIcon),
"editColumn:", SelectedColumn,
"row:", GetGadgetState(#ListIcon),
"withEvent:", 0,
"select:", #YES)
EndIf
EndIf
EndSelect
ForEver
; ----- Display countries currently selected in ComboBoxes
For i = 0 To 2
Debug Str(i + 1) + ". " + GetGadgetItemText(#ListIcon, i, 0) + " - " +
GetGadgetItemText(#ListIcon, i, #ComboBoxColumn)
Next i