Edit TreeGadget items?

Mac OSX specific forum
wombats
Enthusiast
Enthusiast
Posts: 662
Joined: Thu Dec 29, 2011 5:03 pm

Edit TreeGadget items?

Post by wombats »

Hi,

I'm trying to set it up so users can edit TreeGadget items, but it's safe to say I have absolutely no idea what I'm doing. I can't get it to start the editing. I'd like to be able to validate what they enter. Does anyone have any tips?

I started with this code by Shardik.

Code: Select all

EnableExplicit

Define AppDelegate.I = CocoaMessage(0, CocoaMessage(0, 0, "NSApplication sharedApplication"), "delegate")
Define DelegateClass.I = CocoaMessage(0, AppDelegate, "class")
Define Selector.I = sel_registerName_("tableView:viewForTableColumn:row:")

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 View.I
    View = CocoaMessage(0, CocoaMessage(0, 0, "NSTextField new"), "setEditable:", #YES)
  ProcedureReturn View
EndProcedure

OpenWindow(0, 200, 100, 430, 126, "")
TreeGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20)

AddGadgetItem(0, -1, "Harry Rannit")
AddGadgetItem(0, -1, "Ginger Brokeit")
AddGadgetItem(0, -1, "Didi Foundit")

class_addMethod_(DelegateClass, Selector, @GetViewForCellCallback(), "v@:@@@")
CocoaMessage(0, GadgetID(0), "setDelegate:", AppDelegate)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
User avatar
Shardik
Addict
Addict
Posts: 1984
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Edit TreeGadget items?

Post by Shardik »

I had already posted this example of a ListIconGadget with editable cells. Since internally a ListIconGadget in PureBasic is a NSTableView and a TreeGadget is a NSOutlineView which is based on a NSTableView, it would have been as easy as changing the ListIconGadget into a TreeGadget in my example. For your conveniance I have done that for you. (And I have removed the procedure ConvertToUTF8() because it isn't necessary anymore since Fred has removed a bug requiring this produre as a workaround.)

Code: Select all

EnableExplicit

ImportC ""
  sel_registerName(MethodName.S)
  class_addMethod(Class.I, Selector.I, Implementation.I, Types.S)
EndImport

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)
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("textDidEndEditing:")

OpenWindow(0, 200, 100, 220, 130, "Editable TreeGadget")
TreeGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20)
AddGadgetItem(0, -1, "Fruits")
AddGadgetItem(0, -1, "Apples", 0, 1)
AddGadgetItem(0, -1, "Bananas", 0, 1)
AddGadgetItem(0, -1, "Oranges", 0, 1)
SetGadgetItemState(0, 0, #PB_Tree_Expanded)
CocoaMessage(0, GadgetID(0), "setSelectionHighlightStyle:", -1)
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
wombats
Enthusiast
Enthusiast
Posts: 662
Joined: Thu Dec 29, 2011 5:03 pm

Re: Edit TreeGadget items?

Post by wombats »

Thanks, Shardik. I didn't see your ListIconGadget code.

It doesn't work in my project...it won't start the edit when I call:

Code: Select all

CocoaMessage(0, GadgetID(0),
          "editColumn:", SelectedColumn,
          "row:", GetGadgetState(0),
          "withEvent:", 0,
          "select:", #YES)
EndIf
I copied your code exactly. I commented out any other CocoaGadget code I have in there. Can you think of anything that could interfere with it?
User avatar
Shardik
Addict
Addict
Posts: 1984
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Edit TreeGadget items?

Post by Shardik »

Does my code example from above work unchanged?

If yes, try to post a stripped down version of your project that demonstrates the non-working edit operation.

And please state your MacOS version and your PureBasic version, 32-bit or 64-bit, ASCII or Unicode mode...
wombats
Enthusiast
Enthusiast
Posts: 662
Joined: Thu Dec 29, 2011 5:03 pm

Re: Edit TreeGadget items?

Post by wombats »

Yes, your code sample works fine unchanged.

It seems the problem is that my TreeGadget is a pointer within a Structure. Is that the wrong thing to do?

Code: Select all

EnableExplicit

Structure MyStructure
  *gadget
EndStructure

Global *test.MyStructure = AllocateStructure(MyStructure)

ImportC ""
  sel_registerName(MethodName.S)
  class_addMethod(Class.I, Selector.I, Implementation.I, Types.S)
EndImport

ProcedureC EditingFinishedCallback(Object.I, Selector.I, Notification.I)
  Protected EditedCell.I
  Protected EditedColumn.I = CocoaMessage(0, GadgetID(*test\gadget), "editedColumn")
  Protected EditedRow.I = CocoaMessage(0, GadgetID(*test\gadget), "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)
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("textDidEndEditing:")

OpenWindow(0, 200, 100, 220, 130, "Editable TreeGadget")

*test\gadget = TreeGadget(#PB_Any, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20)
AddGadgetItem(*test\gadget, -1, "Fruits")
AddGadgetItem(*test\gadget, -1, "Apples", 0, 1)
AddGadgetItem(*test\gadget, -1, "Bananas", 0, 1)
AddGadgetItem(*test\gadget, -1, "Oranges", 0, 1)
SetGadgetItemState(*test\gadget, 0, #PB_Tree_Expanded)
CocoaMessage(0, GadgetID(*test\gadget), "setSelectionHighlightStyle:", -1)
class_addMethod(DelegateClass, Selector, @EditingFinishedCallback(), "v@:@")
CocoaMessage(0, NotificationCenter,
  "addObserver:", AppDelegate,
  "selector:", Selector,
  "name:$", @"NSControlTextDidEndEditingNotification",
  "object:", GadgetID(*test\gadget))

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(*test\gadget),
          "convertPoint:@", @CursorLocation, "fromView:", 0)
        SelectedColumn = CocoaMessage(0, GadgetID(*test\gadget),
          "columnAtPoint:@", @CursorLocation)
        CocoaMessage(0, GadgetID(*test\gadget),
          "editColumn:", SelectedColumn,
          "row:", GetGadgetState(*test\gadget),
          "withEvent:", 0,
          "select:", #YES)
      EndIf
  EndSelect
ForEver
I am using PB v5.70b1 Unicode on macOS High Sierra.
User avatar
Shardik
Addict
Addict
Posts: 1984
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Edit TreeGadget items?

Post by Shardik »

In your code you have forgotten to modify 2 gadget references. Please change in procedure EditingFinishedCallback()

Code: Select all

SetGadgetItemText(0, EditedRow, EditedText, EditedColumn)
to

Code: Select all

  SetGadgetItemText(*test\gadget, EditedRow, EditedText, EditedColumn)
and in your event loop please change

Code: Select all

      If EventGadget() = 0 And EventType() = #PB_EventType_LeftClick
to

Code: Select all

      If EventGadget() = *test\gadget And EventType() = #PB_EventType_LeftClick
and your example will run like a charm... :wink:
wombats
Enthusiast
Enthusiast
Posts: 662
Joined: Thu Dec 29, 2011 5:03 pm

Re: Edit TreeGadget items?

Post by wombats »

You're right about that. That was a stupid mistake.

However...it's still not working in my project. I can't see what the problem is.
wombats
Enthusiast
Enthusiast
Posts: 662
Joined: Thu Dec 29, 2011 5:03 pm

Re: Edit TreeGadget items?

Post by wombats »

I am at my wits' end trying to get this to work in my project. It works if I create a second window and put the TreeGadget in that, but it doesn't work in my main window. I don't understand it.

I have commented out all the unrelated CocoaMessage commands, but that makes no difference.

I have tried recreating the setup of my project in an example (with the TreeGadget in containers, etc.) and it works fine there.

It works if I do this:

Code: Select all

CocoaMessage(0, GadgetID(tree), "setDelegate:", delegateClass)
However, the TreeGadget's items' text disappears.

I am so confused.
User avatar
Shardik
Addict
Addict
Posts: 1984
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Edit TreeGadget items?

Post by Shardik »

Sorry, but we are only able to help you if you post a stripped down example demonstrating your problems...
wombats
Enthusiast
Enthusiast
Posts: 662
Joined: Thu Dec 29, 2011 5:03 pm

Re: Edit TreeGadget items?

Post by wombats »

I know. I'm sorry I couldn't provide one earlier. I spent a long time picking apart my project to see what could be the problem and then I suddenly realised the difference between the TreeGadget in my project and the one in the example...the items in mine have images.

So when an item has an image, it cannot be edited. I am afraid this might be a showstopper for this functionality, though I hope not.

Code: Select all

EnableExplicit

ImportC ""
  sel_registerName(MethodName.S)
  class_addMethod(Class.I, Selector.I, Implementation.I, Types.S)
EndImport

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)
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("textDidEndEditing:")

CreateImage(0, 16, 16, 24, #Red)
CreateImage(1, 16, 16, 24, #Blue)

OpenWindow(0, 200, 100, 220, 130, "Editable TreeGadget")
TreeGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20)
AddGadgetItem(0, -1, "Fruits", ImageID(0))
AddGadgetItem(0, -1, "Apples", 0, 1)
AddGadgetItem(0, -1, "Bananas", ImageID(1), 1)
AddGadgetItem(0, -1, "Oranges", 0, 1)
SetGadgetItemState(0, 0, #PB_Tree_Expanded)
CocoaMessage(0, GadgetID(0), "setSelectionHighlightStyle:", -1)
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
User avatar
Shardik
Addict
Addict
Posts: 1984
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Edit TreeGadget items?

Post by Shardik »

wombats wrote:I know. I'm sorry I couldn't provide one earlier. I spent a long time picking apart my project to see what could be the problem and then I suddenly realised the difference between the TreeGadget in my project and the one in the example...the items in mine have images.
Thank you for taking the time to strip down your code until you were able to demonstrate the error.
wombats wrote:So when an item has an image, it cannot be edited. I am afraid this might be a showstopper for this functionality, though I hope not.
Unfortunately I haven't found a solution yet. Fred seems to use a custom object called "TreeItem". Only Fred or freak possibly know how to make it possible to edit a "TreeItem" containing both an image and a text. The only but complicated alternative I currently can think of is to program a pure API solution using the NSOutlineView on which the TreeGadget is based on. As a further complication the TreeGadget is based on an old cell-based approach which doesn't offer a combination of image and text with native Cocoa framework methods. From the Apple OpenSource site you may download the class ImageAndTextCell.m and header file ImageAndTextCell.h which you would have to implement in your PureBasic code.
wombats
Enthusiast
Enthusiast
Posts: 662
Joined: Thu Dec 29, 2011 5:03 pm

Re: Edit TreeGadget items?

Post by wombats »

Shardik wrote:
wombats wrote:I know. I'm sorry I couldn't provide one earlier. I spent a long time picking apart my project to see what could be the problem and then I suddenly realised the difference between the TreeGadget in my project and the one in the example...the items in mine have images.
Thank you for taking the time to strip down your code until you were able to demonstrate the error.
wombats wrote:So when an item has an image, it cannot be edited. I am afraid this might be a showstopper for this functionality, though I hope not.
Unfortunately I haven't found a solution yet. Fred seems to use a custom object called "TreeItem". Only Fred or freak possibly know how to make it possible to edit a "TreeItem" containing both an image and a text. The only but complicated alternative I currently can think of is to program a pure API solution using the NSOutlineView on which the TreeGadget is based on. As a further complication the TreeGadget is based on an old cell-based approach which doesn't offer a combination of image and text with native Cocoa framework methods. From the Apple OpenSource site you may download the class ImageAndTextCell.m and header file ImageAndTextCell.h which you would have to implement in your PureBasic code.
That's a shame. Thank you for looking into it.
User avatar
Shardik
Addict
Addict
Posts: 1984
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Edit TreeGadget items?

Post by Shardik »

I have found a workaround to edit tree items with an image. My example code does the following:
If a tree item selected for edit contains an image:
- Grab that image
- Delete that image from the item
- When text editing starts, no icon is displayed and text editing is possible
- After text editing ends, redisplay the image again

The first step was to find a way how to grab the image from a tree item. For this purpose I already posted this cross-platform example.

This is the complete example which I tested successfully on MacOS 10.6.8 'Snow Leopard' with PB 5.46 x86 in ASCII and Unicode mode and on MacOS 10.13.6 'High Sierra' with PB 5.46 x64 in ASCII and Unicode mode:

Code: Select all

EnableExplicit

Define AppDelegate.I = CocoaMessage(0, CocoaMessage(0, 0,
  "NSApplication sharedApplication"), "delegate")
Define Cell.I
Define CellImage.I
Define ClassName.S
Define DelegateClass.I = CocoaMessage(0, AppDelegate, "class")
Define NotificationCenter.I = CocoaMessage(0, 0,
  "NSNotificationCenter defaultCenter")
Define SelectedRow.I
Define Selector.I = sel_registerName_("textDidEndEditing:")

ProcedureC EditingFinishedCallback(Object.I, Selector.I, Notification.I)
  Shared CellImage.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)

  If CellImage
    SetGadgetItemImage(0, EditedRow, CellImage)
    CellImage = 0
  EndIf
EndProcedure

Procedure GetGadgetItemImage(TreeGadgetID.I, Row.I)
  Protected Item.I
  Protected CellImage.I

  Item = CocoaMessage(0, GadgetID(TreeGadgetID), "itemAtRow:", Row)
  CellImage = PeekI(PeekI(PeekI(Item + SizeOf(Integer))) + SizeOf(Integer) * 3)

  ProcedureReturn CellImage
EndProcedure

CreateImage(0, 16, 16, 24, $FF)
CreateImage(1, 16, 16, 24, $FF0000)

OpenWindow(0, 200, 100, 220, 130, "Editable TreeGadget")
TreeGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20)
AddGadgetItem(0, -1, "Fruit", ImageID(0))
AddGadgetItem(0, -1, "Apples", 0, 1)
AddGadgetItem(0, -1, "Bananas", ImageID(1), 1)
AddGadgetItem(0, -1, "Oranges", 0, 1)
SetGadgetItemState(0, 0, #PB_Tree_Expanded)
CocoaMessage(0, GadgetID(0), "setSelectionHighlightStyle:", -1)
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
        SelectedRow = GetGadgetState(0)
        Cell = CocoaMessage(0, GadgetID(0),
          "preparedCellAtColumn:", 0,
          "row:", SelectedRow)
        ClassName = PeekS(CocoaMessage(0, CocoaMessage(0,
          Cell, "className"), "UTF8String"), -1, #PB_UTF8)

        If ClassName = "PBIconTextCell"
          CellImage = GetGadgetItemImage(0, SelectedRow)
          SetGadgetItemImage(0, SelectedRow, 0)
        EndIf

        CocoaMessage(0, GadgetID(0), "setFocusedColumn:", 0)
        CocoaMessage(0, GadgetID(0),
          "editColumn:", 0,
          "row:", SelectedRow,
          "withEvent:", 0,
          "select:", #YES)
      EndIf
  EndSelect
ForEver
wombats
Enthusiast
Enthusiast
Posts: 662
Joined: Thu Dec 29, 2011 5:03 pm

Re: Edit TreeGadget items?

Post by wombats »

My apologies for not thanking you for that. This doesn't seem to work anymore in the latest PureBasic, unfortunately. I had created my own tree gadget using the CanvasGadget since drag and drop wasn't working on macOS, but now that's fixed, I'd like to use the proper TreeGadget. I couldn't get my own tree to work as well.

Am I remembering correctly that there was a relatively recent change and PureBasic now handles the item in a custom manner? Would that mean this isn't possible now?
User avatar
mk-soft
Always Here
Always Here
Posts: 5313
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Edit TreeGadget items?

Post by mk-soft »

That is correct.
Purebasic uses a new owner draw for the item cells.
This also applies to the ListViewGadget and ListIconGadget.
This means that all old examples no longer work.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Post Reply