Any way to add separators to ListIconGadget/NSTableView?

Mac OSX specific forum
User avatar
Shardik
Addict
Addict
Posts: 1989
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Any way to add separators to ListIconGadget/NSTableView?

Post by Shardik »

I have modified my example with groups of fruit and a trailing line behind the group name to work with PB 6.00 x64 Beta 7 and pre Beta 7:

Code: Select all

EnableExplicit

#NSTableViewStylePlain = 4

Define AppDelegate.I = CocoaMessage(0, CocoaMessage(0, 0,
  "NSApplication sharedApplication"), "delegate")
Define DelegateClass.I = CocoaMessage(0, AppDelegate, "class")

ProcedureC WillDisplayCell(Object.I, Selector.I, TableView.I, Cell.I,
  *Column, Row.I)
  Protected Column.I
  Protected CellFrame.NSRect
  Protected CellText.S
  Protected GadgetID.I
  Protected LineFrame.NSRect
  Protected RowFrame.NSRect
  Protected TextSize.NSSize

  GadgetID = CocoaMessage(0, TableView, "tag")
  Column = CocoaMessage(0, CocoaMessage(0, TableView, "tableColumns"),
    "indexOfObject:", *Column)
  CellText = GetGadgetItemText(CocoaMessage(0, TableView, "tag"), Row, Column)
  CocoaMessage(0, Cell, "setStringValue:$", @CellText)

  If GetGadgetItemData(GadgetID, Row) = #True
    CocoaMessage(0, Cell, "_setVerticallyCentered:", #YES)

    If Column = 0
      CocoaMessage(@CellFrame, TableView,
        "frameOfCellAtColumn:", Column,
        "row:", Row)
      CocoaMessage(@TextSize, Cell, "cellSize")
      CocoaMessage(@RowFrame, GadgetID(GadgetID), "rectOfRow:", Row)

      ; ----- Draw line from end of text in column 0 to end of row

      LineFrame\origin\x = CellFrame\origin\x + TextSize\width + 10
      LineFrame\origin\y =  CellFrame\origin\y + CellFrame\size\height / 2 + 1
      LineFrame\size\height = 1
      LineFrame\size\width = RowFrame\size\width - TextSize\width - 20
      CocoaMessage(0, CocoaMessage(0, 0, "NSColor textColor"), "setFill")
      CocoaMessage(0, 0, "NSBezierPath fillRect:@", @LineFrame)
      CocoaMessage(0, Cell,
        "drawInteriorWithFrame:@", @LineFrame,
        "inView:", TableView)
      CocoaMessage(0, Cell, 
        "setTextColor:", CocoaMessage(0, 0, "NSColor textColor"))
    EndIf
  Else
    CocoaMessage(0, Cell, 
      "setTextColor:", CocoaMessage(0, 0, "NSColor textColor"))
  EndIf
EndProcedure

ProcedureC IsGroupRowCallback(Object.I, Selector.I, TableView.I, Row.I)
  Protected IsGroupRow.I

  IsGroupRow = GetGadgetItemData(CocoaMessage(0, TableView, "tag"), Row)

  ProcedureReturn IsGroupRow
EndProcedure

OpenWindow(0, 200, 100, 202, 270, "Group demo")
ListIconGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20,
  "Fruit", 90)
AddGadgetColumn(0, 1, "Euro/kg", 60)
AddGadgetItem(0, 0, "Stone fruits")
SetGadgetItemData(0, 0, #True)
AddGadgetItem(0, 1, "Apricots" + #LF$ + "2,99")
AddGadgetItem(0, 2, "Peaches" + #LF$ + "2,69")
AddGadgetItem(0, 3, "Plums" + #LF$ + "1,60")
AddGadgetItem(0, 4, "Berries")
SetGadgetItemData(0, 4, #True)
AddGadgetItem(0, 5, "Grapes" + #LF$ + "1,78")
AddGadgetItem(0, 6, "Raspberries" + #LF$ + "2,99")
AddGadgetItem(0, 7, "Strawberries" + #LF$ + "3,56")
CocoaMessage(0, GadgetID(0), "setUsesAlternatingRowBackgroundColors:", #YES)
CocoaMessage(0, CocoaMessage(0, GadgetID(0), "enclosingScrollView"),
  "setHasHorizontalScroller:", #False)

class_addMethod_(DelegateClass,
  sel_registerName_("tableView:isGroupRow:"),
  @IsGroupRowCallback(), "v@:@@")
class_addMethod_(DelegateClass,
  sel_registerName_("tableView:willDisplayCell:forTableColumn:row:"),
  @WillDisplayCell(), "v@:@@@@")
CocoaMessage(0, GadgetID(0), "setDelegate:", AppDelegate)

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

Re: Any way to add separators to ListIconGadget/NSTableView?

Post by Shardik »

This example is very similar to the previos one but changes the color of the group title and traling line to yellow (tested successfully on Big Sur with PB 6.00 x64 Beta 7 and 5.73 x64):

Image

Code: Select all

EnableExplicit

Define AppDelegate.I = CocoaMessage(0, CocoaMessage(0, 0,
  "NSApplication sharedApplication"), "delegate")
Define DelegateClass.I = CocoaMessage(0, AppDelegate, "class")

ProcedureC WillDisplayCell(Object.I, Selector.I, TableView.I, Cell.I,
  *Column, Row.I)
  Protected Column.I
  Protected CellFrame.NSRect
  Protected CellText.S
  Protected GadgetID.I
  Protected LineFrame.NSRect
  Protected RowFrame.NSRect
  Protected TextSize.NSSize

  GadgetID = CocoaMessage(0, TableView, "tag")
  Column = CocoaMessage(0, CocoaMessage(0, TableView, "tableColumns"),
    "indexOfObject:", *Column)
  CellText = GetGadgetItemText(CocoaMessage(0, TableView, "tag"), Row, Column)
  CocoaMessage(0, Cell, "setStringValue:$", @CellText)

  If GetGadgetItemData(0, Row)
    CocoaMessage(0, Cell, "_setVerticallyCentered:", #YES)

    If Column = 0
      CocoaMessage(@CellFrame, TableView,
        "frameOfCellAtColumn:", Column,
        "row:", Row)
      CocoaMessage(@TextSize, Cell, "cellSize")
      CocoaMessage(@RowFrame, GadgetID(GadgetID), "rectOfRow:", Row)

      ; ----- Draw line from end of text in column 0 to end of row

      LineFrame\origin\x = CellFrame\origin\x + TextSize\width + 10
      LineFrame\origin\y =  CellFrame\origin\y + CellFrame\size\height / 2
      LineFrame\size\height = 2
      LineFrame\size\width = RowFrame\size\width - TextSize\width - 20
      CocoaMessage(0, CocoaMessage(0, 0, "NSColor yellowColor"), "setFill")
      CocoaMessage(0, 0, "NSBezierPath fillRect:@", @LineFrame)
      CocoaMessage(0, Cell,
        "drawInteriorWithFrame:@", @LineFrame,
        "inView:", TableView)
      CocoaMessage(0, Cell, 
        "setTextColor:", CocoaMessage(0, 0, "NSColor yellowColor"))
    EndIf
  Else
    CocoaMessage(0, Cell, 
      "setTextColor:", CocoaMessage(0, 0, "NSColor textColor"))
  EndIf
EndProcedure

ProcedureC IsGroupRowCallback(Object.I, Selector.I, TableView.I, Row.I)
  Protected IsGroupRow.I

  IsGroupRow = GetGadgetItemData(CocoaMessage(0, TableView, "tag"), Row)

  ProcedureReturn IsGroupRow
EndProcedure

OpenWindow(0, 200, 100, 202, 250, "Group demo")
ListIconGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20,
  "Fruit", 90, #PB_ListIcon_GridLines)
AddGadgetColumn(0, 1, "Euro/kg", 60)
AddGadgetItem(0, 0, "Stone fruits")
SetGadgetItemData(0, 0, #True)
AddGadgetItem(0, 1, "Apricots" + #LF$ + "2,99")
AddGadgetItem(0, 2, "Peaches" + #LF$ + "2,69")
AddGadgetItem(0, 3, "Plums" + #LF$ + "1,60")
AddGadgetItem(0, 4, "Berries")
SetGadgetItemData(0, 4, #True)
AddGadgetItem(0, 5, "Grapes" + #LF$ + "1,78")
AddGadgetItem(0, 6, "Raspberries" + #LF$ + "2,99")
AddGadgetItem(0, 7, "Strawberries" + #LF$ + "3,56")

class_addMethod_(DelegateClass,
  sel_registerName_("tableView:isGroupRow:"),
  @IsGroupRowCallback(), "v@:@@")
class_addMethod_(DelegateClass,
  sel_registerName_("tableView:willDisplayCell:forTableColumn:row:"),
  @WillDisplayCell(), "v@:@@@@")
CocoaMessage(0, GadgetID(0), "setDelegate:", AppDelegate)
CocoaMessage(0, GadgetID(0), "setUsesAlternatingRowBackgroundColors:", #YES)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
User avatar
deseven
Enthusiast
Enthusiast
Posts: 362
Joined: Wed Jan 12, 2011 3:48 pm
Location: Serbia
Contact:

Re: Any way to add separators to ListIconGadget/NSTableView?

Post by deseven »

Hey Shardik, any chance you know how to draw some text there, not just a line? Can't figure it out myself :( I've loaded NSFont, but what's the drawing procedure for text?
User avatar
Shardik
Addict
Addict
Posts: 1989
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Any way to add separators to ListIconGadget/NSTableView?

Post by Shardik »

deseven wrote: Sat May 14, 2022 9:14 am Hey Shardik, any chance you know how to draw some text there, not just a line? Can't figure it out myself :(

Image


I have tested the example successfully with PB 5.73 x64 and PB 6.00 x64 Beta 10 with Asm and C backend on these MacOS versions:
  • MacOS 11.6.6 'Big Sur'
  • MacOS 12.4 'Monterey'

Code: Select all

EnableExplicit

Define AppDelegate.I = CocoaMessage(0, CocoaMessage(0, 0,
  "NSApplication sharedApplication"), "delegate")
Define DelegateClass.I = CocoaMessage(0, AppDelegate, "class")
Define GroupHeader1.S = "------- Stone fruits -------"
Define GroupHeader2.S = "--------- Berries ----------"

ProcedureC WillDisplayCell(Object.I, Selector.I, TableView.I, Cell.I,
  *Column, Row.I)
  Protected Column.I
  Protected CellFrame.NSRect
  Protected CellText.S
  Protected ListIconID.I
  Protected RowHeight.CGFloat

  ListIconID = CocoaMessage(0, TableView, "tag")
  Column = CocoaMessage(0, CocoaMessage(0, TableView, "tableColumns"),
    "indexOfObject:", *Column)
  CocoaMessage(ListIconID, Cell, "_setVerticallyCentered:", #YES)
  CellText = GetGadgetItemText(CocoaMessage(0, TableView, "tag"), Row, Column)

  If GetGadgetItemData(ListIconID, Row) <> 0
    If Column = 0
      CellText = PeekS(GetGadgetItemData(ListIconID, Row), -1)
      CocoaMessage(0, Cell,
        "setTextColor:", CocoaMessage(0, 0, "NSColor yellowColor"))
      CocoaMessage(0, Cell, "setStringValue:$", @CellText)
      CocoaMessage(0, Cell, "setLineBreakMode:", 0)
      CocoaMessage(0, Cell, "setTruncatesLastVisibleLine:", #NO)
      CellFrame\origin\x = 6
      CocoaMessage(@RowHeight, TableView, "rowHeight")
      CellFrame\origin\y = Row * RowHeight - 4
      CellFrame\size\width = GadgetWidth(ListIconID)
      CellFrame\size\height = 25
      CocoaMessage(0, Cell,
        "drawInteriorWithFrame:@", @CellFrame,
        "inView:", TableView)
    EndIf
  Else
    CocoaMessage(0, Cell, "setStringValue:$", @CellText)
    CocoaMessage(0, Cell, 
      "setTextColor:", CocoaMessage(0, 0, "NSColor textColor"))
  EndIf
EndProcedure

OpenWindow(0, 200, 100, 202, 245, "Group demo")
ListIconGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20,
  "Fruit", 90)
AddGadgetColumn(0, 1, "Euro/kg", 60)
AddGadgetItem(0, 0, "")
SetGadgetItemData(0, 0, @GroupHeader1)
AddGadgetItem(0, 1, "Apricots" + #LF$ + "2,99")
AddGadgetItem(0, 2, "Peaches" + #LF$ + "2,69")
AddGadgetItem(0, 3, "Plums" + #LF$ + "1,60")
AddGadgetItem(0, 4, "")
SetGadgetItemData(0, 4, @GroupHeader2)
AddGadgetItem(0, 5, "Grapes" + #LF$ + "1,78")
AddGadgetItem(0, 6, "Raspberries" + #LF$ + "2,99")
AddGadgetItem(0, 7, "Strawberries" + #LF$ + "3,56")
CocoaMessage(0, GadgetID(0), "setUsesAlternatingRowBackgroundColors:", #YES)
class_addMethod_(DelegateClass,
  sel_registerName_("tableView:willDisplayCell:forTableColumn:row:"),
  @WillDisplayCell(), "v@:@@@@")
CocoaMessage(0, GadgetID(0), "setDelegate:", AppDelegate)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
User avatar
deseven
Enthusiast
Enthusiast
Posts: 362
Joined: Wed Jan 12, 2011 3:48 pm
Location: Serbia
Contact:

Re: Any way to add separators to ListIconGadget/NSTableView?

Post by deseven »

Thank you! It almost works, just a couple of problems (also on beta 10, the first one is visible on your screenshot as well):

Image

Can you please also explain how it works? I'm kinda puzzled by it... Does drawInteriorWithFrame draw the text too and it can ignore column bounds because it draws on the row as a whole, not just on one single cell?
User avatar
Shardik
Addict
Addict
Posts: 1989
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Any way to add separators to ListIconGadget/NSTableView?

Post by Shardik »

deseven wrote: Mon Jun 20, 2022 8:38 pm Can you please also explain how it works? I'm kinda puzzled by it...

Sorry, but currently it's more some kind of hack. You are right: the group text is drawn twice. The first time the text is drawn only into column 0 and I had to suppress the ellipsis ("Stone fr...") by using these instructions (otherwise the ellipsis points would show through):

Code: Select all

      CocoaMessage(0, Cell, "setLineBreakMode:", 0)
      CocoaMessage(0, Cell, "setTruncatesLastVisibleLine:", #NO)

The 2nd drawing of the group text is done by

Code: Select all

      CellFrame\origin\x = 6
      CocoaMessage(@RowHeight, TableView, "rowHeight")
      CellFrame\origin\y = Row * RowHeight - 4
      CellFrame\size\width = GadgetWidth(ListIconID)
      CellFrame\size\height = 25
      CocoaMessage(0, Cell,
        "drawInteriorWithFrame:@", @CellFrame,
        "inView:", TableView)
Here the drawing uses the width of the whole ListIconGadget and overwrites the text of the first drawn text. Therefore the position has to be exactly the same as that of the first drawing...

I didn't find a way to suppress the first drawing. Perhaps the whole row of the group text should be cleared before the second drawing takes place.

Unfortunately I didn't do any tests until now on how the hack reacts on selecting a group row...
User avatar
deseven
Enthusiast
Enthusiast
Posts: 362
Joined: Wed Jan 12, 2011 3:48 pm
Location: Serbia
Contact:

Re: Any way to add separators to ListIconGadget/NSTableView?

Post by deseven »

Ah, I see. That's a really nice idea, I'll try to figure out how to get rid of the first draw. I already tried drawing a box on top of it, but it still goes under the original text, also having multiple text draws is probably far from ideal...
User avatar
Shardik
Addict
Addict
Posts: 1989
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: Any way to add separators to ListIconGadget/NSTableView?

Post by Shardik »

You may try the following improved example (tested successfully on MacOS 11.6.6 'Big Sur' with PB 5.73 x64 and PB 6.00 x64). By addition of the IsGroupRow() callback the group rows are now not selectable anymore (hence no artifacts) which is the default behaviour.

Code: Select all

EnableExplicit

Define AppDelegate.I = CocoaMessage(0, CocoaMessage(0, 0,
  "NSApplication sharedApplication"), "delegate")
Define DelegateClass.I = CocoaMessage(0, AppDelegate, "class")

ProcedureC IsGroupRow(Object.I, Selector.I, TableView.I, Row.I)
  Protected ListIconID.I
  Protected IsGroupRow.I

  ListIconID = CocoaMessage(0, TableView, "tag")

  If GetGadgetItemData(ListIconID, Row)
    IsGroupRow = #True
  Else
    IsGroupRow = #False
  EndIf

  ProcedureReturn IsGroupRow
EndProcedure

ProcedureC WillDisplayCell(Object.I, Selector.I, TableView.I, Cell.I, *Column,
  Row.I)
  Protected Column.I
  Protected CellFrame.NSRect
  Protected CellText.S
  Protected ListIconID.I

  ListIconID = CocoaMessage(0, TableView, "tag")
  Column = CocoaMessage(0, CocoaMessage(0, TableView, "tableColumns"),
    "indexOfObject:", *Column)
  CocoaMessage(0, Cell, "_setVerticallyCentered:", #YES)
  CellText = GetGadgetItemText(ListIconID, Row, Column)

  If GetGadgetItemData(ListIconID, Row)
    If Column = 0
      CocoaMessage(0, Cell, "setStringValue:$", @CellText)
      CocoaMessage(0, Cell, "setLineBreakMode:", 2)
      CocoaMessage(0, Cell,
        "setTextColor:", CocoaMessage(0, 0, "NSColor yellowColor"))
      CocoaMessage(@CellFrame, TableView,
        "frameOfCellAtColumn:", Column,
        "row:", Row)
      CellFrame\size\width = GadgetWidth(ListIconID)
      CocoaMessage(0, Cell,
        "drawInteriorWithFrame:@", @CellFrame,
        "inView:", TableView)
    EndIf
  Else
    CocoaMessage(0, Cell, 
      "setTextColor:", CocoaMessage(0, 0, "NSColor textColor"))
    CocoaMessage(0, Cell, "setStringValue:$", @CellText)
  EndIf
EndProcedure

OpenWindow(0, 200, 100, 202, 253, "Group demo")
ListIconGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20,
  "Fruit", 90)
AddGadgetColumn(0, 1, "Euro/kg", 60)
AddGadgetItem(0, 0, "------- Stone fruits -------")
SetGadgetItemData(0, 0, #True)
AddGadgetItem(0, 1, "Apricots" + #LF$ + "2,99")
AddGadgetItem(0, 2, "Peaches" + #LF$ + "2,69")
AddGadgetItem(0, 3, "Plums" + #LF$ + "1,60")
AddGadgetItem(0, 4, "--------- Berries ----------")
SetGadgetItemData(0, 4, #True)
AddGadgetItem(0, 5, "Grapes" + #LF$ + "1,78")
AddGadgetItem(0, 6, "Raspberries" + #LF$ + "2,99")
AddGadgetItem(0, 7, "Strawberries" + #LF$ + "3,56")
CocoaMessage(0, GadgetID(0), "setUsesAlternatingRowBackgroundColors:", #YES)
class_addMethod_(DelegateClass,
  sel_registerName_("tableView:willDisplayCell:forTableColumn:row:"),
  @WillDisplayCell(), "v@:@@@@")
class_addMethod_(DelegateClass,
  sel_registerName_("tableView:isGroupRow:"),
  @IsGroupRow(), "v@:@@")
CocoaMessage(0, GadgetID(0), "setDelegate:", AppDelegate)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
User avatar
deseven
Enthusiast
Enthusiast
Posts: 362
Joined: Wed Jan 12, 2011 3:48 pm
Location: Serbia
Contact:

Re: Any way to add separators to ListIconGadget/NSTableView?

Post by deseven »

Thank you Shardik, but I need those rows to be selectable, unfortunately... Pre Big Sur they were, even as group rows, but with NSTableView changes in recent macOS versions group rows are not selectable anymore (or the selection is not visible), so I got rid of using group rows completely.
Post Reply