PureBasic Forum
https://www.purebasic.fr/english/

Edit TreeGadget items?
https://www.purebasic.fr/english/viewtopic.php?f=19&t=71339
Page 1 of 1

Author:  wombats [ Tue Sep 04, 2018 8:05 pm ]
Post subject:  Edit TreeGadget items?

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:
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

Author:  Shardik [ Wed Sep 05, 2018 9:21 pm ]
Post subject:  Re: Edit TreeGadget items?

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:
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

Author:  wombats [ Thu Sep 06, 2018 8:40 am ]
Post subject:  Re: Edit TreeGadget items?

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:
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?

Author:  Shardik [ Thu Sep 06, 2018 9:57 am ]
Post subject:  Re: Edit TreeGadget items?

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...

Author:  wombats [ Thu Sep 06, 2018 10:16 am ]
Post subject:  Re: Edit TreeGadget items?

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:
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.

Author:  Shardik [ Thu Sep 06, 2018 8:57 pm ]
Post subject:  Re: Edit TreeGadget items?

In your code you have forgotten to modify 2 gadget references. Please change in procedure EditingFinishedCallback()
Code:
SetGadgetItemText(0, EditedRow, EditedText, EditedColumn)
to
Code:
  SetGadgetItemText(*test\gadget, EditedRow, EditedText, EditedColumn)
and in your event loop please change
Code:
      If EventGadget() = 0 And EventType() = #PB_EventType_LeftClick
to
Code:
      If EventGadget() = *test\gadget And EventType() = #PB_EventType_LeftClick
and your example will run like a charm... :wink:

Author:  wombats [ Fri Sep 07, 2018 10:32 am ]
Post subject:  Re: Edit TreeGadget items?

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.

Author:  wombats [ Sat Mar 16, 2019 6:05 pm ]
Post subject:  Re: Edit TreeGadget items?

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:
CocoaMessage(0, GadgetID(tree), "setDelegate:", delegateClass)
However, the TreeGadget's items' text disappears.

I am so confused.

Author:  Shardik [ Sat Mar 16, 2019 7:35 pm ]
Post subject:  Re: Edit TreeGadget items?

Sorry, but we are only able to help you if you post a stripped down example demonstrating your problems...

Author:  wombats [ Sun Mar 17, 2019 6:40 am ]
Post subject:  Re: Edit TreeGadget items?

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:
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

Author:  Shardik [ Mon Mar 25, 2019 2:54 pm ]
Post subject:  Re: Edit TreeGadget items?

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.

Author:  wombats [ Tue Apr 02, 2019 2:58 pm ]
Post subject:  Re: Edit TreeGadget items?

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.

Author:  Shardik [ Wed Jul 17, 2019 12:25 pm ]
Post subject:  Re: Edit TreeGadget items?

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:
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

Page 1 of 1 All times are UTC + 1 hour
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/