ListIconGadget (GtkTreeView) - row height

Just starting out? Need help? Post your questions and find answers here.
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: ListIconGadget (GtkTreeView) - row height

Post by Shardik »

Sorry, but the solution took me much longer than I previously had estimated. Nevertheless I found a very simple solution which doesn't require to mess around with GtkSettings or rc styles. The following example code allows you to dynamically change the height of rows in a ListIconGadget (tested in Ubuntu 12.04 x64 with KDE and Unity):

Image

Code: Select all

EnableExplicit

ImportC ""
  gtk_scale_add_mark(*TrackBar.GtkScale, Value.D, Position.I, *MarkupText)
  gtk_tree_view_column_get_cell_renderers(*Column.GtkTreeViewColumn)
EndImport

Define *CellRenderer.GtkCellRenderer
Define CellRendererList.I
Define Column.I
Define i.I
Define OldRowHeight.L
Define RowHeight.L
Define RowWidth.L
Define TickMarkLabel.S
Define WindowEvent.I
Define xOffset.L
Define yOffset.L

OpenWindow(0, 200, 100, 418, 200, "Change ListIcon's row height")
ListIconGadget(0, 10, 10, WindowWidth(0) - 20, 94, "Name", 110, #PB_ListIcon_GridLines)
AddGadgetColumn(0, 1, "Address", GadgetWidth(0) - GetGadgetItemAttribute(0, 0, #PB_ListIcon_ColumnWidth) - 30)
AddGadgetItem(0, -1, "Harry Rannit" + #LF$ + "12 Parliament Way, Battle Street, By the Bay")
AddGadgetItem(0, -1, "Ginger Brokeit" + #LF$ + "130 PureBasic Road, BigTown, CodeCity")
AddGadgetItem(0, -1, "Didi Foundit" + #LF$ + "321 Logo Drive, Mouse House, Downtown")

Frame3DGadget(1, 10, GadgetY(0) + GadgetHeight(0) + 10, WindowWidth(0) - 20, 90, "Row height:")
TrackBarGadget(2, GadgetX(1) + 10, GadgetY(1) + 20, GadgetWidth(1) - 20, 55, 18, 40, #PB_TrackBar_Ticks)

; ----- Draw even tick marks with labels

For i = 18 To 40 Step 2
  TickMarkLabel = Str(i)
  gtk_scale_add_mark(GadgetID(2), i, #GTK_POS_BOTTOM, @TickMarkLabel)
Next i

; ----- Draw uneven tick marks without labels

For i = 19 To 39 Step 2
  gtk_scale_add_mark(GadgetID(2), i, #GTK_POS_BOTTOM, 0)
Next i

; ----- Get column 0
Column = gtk_tree_view_get_column_(GadgetID(0), 0)

If Column
  ; ----- Get list of cell renderers for column 0
  CellRendererList = gtk_tree_view_column_get_cell_renderers(Column)
  
  If CellRendererList
    ; ----- Get 2nd cell renderer from list to obtain current row height
    *CellRenderer = g_list_nth_data_(CellRendererList, 1)

    ; ----- Get current row height and display it in TrackBar
    gtk_cell_renderer_get_size_(*CellRenderer, GadgetID(0), 0, @xOffset, @yOffset, @RowWidth, @RowHeight)
    SetGadgetState(2, RowHeight)
    OldRowHeight = RowHeight

    ; ----- Get 1st cell renderer from list for changing row height
    *CellRenderer = g_list_nth_data_(CellRendererList, 0)
  EndIf
EndIf

Repeat
  WindowEvent = WaitWindowEvent()

  Select WindowEvent
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 2
        ; ----- Set new row height
        RowHeight = GetGadgetState(2)

        If RowHeight <> OldRowHeight
          *CellRenderer\height = RowHeight
          gtk_tree_view_column_clear_attributes_(Column, *CellRenderer)
          OldRowHeight = RowHeight
        EndIf
      EndIf
  EndSelect
ForEver
It's not possible to reduce a row's height below a specific minimum value (19 pixels in Ubuntu 12.04 x64 with KDE).
mdp wrote:NOW, if I increase a GtkCellRenderer\ypad ('ypad' can be replaced to 'height' in the example from Shardik), the row becomes taller, but how is it that if I try to zero that GtkCellRenderer\ypad, nothing happens?
I presume that you don't get the function of ypad correctly. I have written a second example code which lets you dynamically change the value of ypad and see the resulting effect: beginning with a ypad value of 8 (in KDE) the text is vertically moved down in a column until it is only partly visible. You can't move it upwards. The row's height never changes when changing the ypad value:

Image

Code: Select all

EnableExplicit

ImportC ""
  gtk_scale_add_mark(*TrackBar.GtkScale, Value.D, Position.I, *MarkupText)
  gtk_tree_view_column_get_cell_renderers(*Column.GtkTreeViewColumn)
EndImport

Procedure ChangeVerticalTextAlignment(NewYPad.L)
  Protected *CellRenderer.GtkCellRenderer
  Protected CellRendererList.I
  Protected Column.I

  ; ----- Get column 0
  Column = gtk_tree_view_get_column_(GadgetID(0), 0)

  ; ----- Get 2nd cell renderer from list of cell renderers of column 0
  If Column
    CellRendererList = gtk_tree_view_column_get_cell_renderers(Column)

    If CellRendererList
      *CellRenderer = g_list_nth_data_(CellRendererList, 1)
      g_list_free_(CellRendererList)
      *CellRenderer\height = 30 
      *CellRenderer\ypad = NewYPad 
    EndIf

    gtk_widget_queue_draw_(GadgetID(0))
  EndIf
EndProcedure

Define i.I
Define TickMarkLabel.S
Define NewYPad.L
Define OldYPad.L

OpenWindow(0, 200, 100, 413, 240, "Change vertical text position in column 0")
ListIconGadget(0, 10, 10, WindowWidth(0) - 20, 124, "Name", 110, #PB_ListIcon_GridLines)
AddGadgetColumn(0, 1, "Address", GadgetWidth(0) - GetGadgetItemAttribute(0, 0, #PB_ListIcon_ColumnWidth) - 30)
AddGadgetItem(0, -1, "Harry Rannit" + #LF$ + "12 Parliament Way, Battle Street, By the Bay")
AddGadgetItem(0, -1, "Ginger Brokeit" + #LF$ + "130 PureBasic Road, BigTown, CodeCity")
AddGadgetItem(0, -1, "Didi Foundit" + #LF$ + "321 Logo Drive, Mouse House, Downtown")

NewYPad = 2
OldYPad = 2
ChangeVerticalTextAlignment(NewYPad)

Frame3DGadget(1, 10, GadgetY(0) + GadgetHeight(0) + 10, WindowWidth(0) - 20, 90, "Vertical text alignment in column 0:")
TrackBarGadget(2, GadgetX(1) + 10, GadgetY(1) + 20, GadgetWidth(1) - 20, 55, 0, 20, #PB_TrackBar_Ticks)

For i = 0 To 20 Step 2
  TickMarkLabel = Str(i)
  gtk_scale_add_mark(GadgetID(2), i, #GTK_POS_BOTTOM, @TickMarkLabel)
Next i

For i = 1 To 19 Step 2
  gtk_scale_add_mark(GadgetID(2), i, #GTK_POS_BOTTOM, 0)
Next i

SetGadgetState(2, NewYPad)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 2
        ; ----- Set new vertical text position in row
        NewYPad = GetGadgetState(2)

        If NewYPad <> OldYPad
          ChangeVerticalTextAlignment(NewYPad)
          OldYPad = NewYPad
        EndIf
      EndIf
  EndSelect
ForEver
User avatar
Shardik
Addict
Addict
Posts: 2058
Joined: Thu Apr 21, 2005 2:38 pm
Location: Germany

Re: ListIconGadget (GtkTreeView) - row height

Post by Shardik »

Previously I already demonstrated how to get and set a ListIconGadget's row height on MacOS X with Cocoa framework.

srod already demonstrated how to get and set a ListIconGadget's row height on Windows.

So I combined all these solutions together with my Linux example from above to a cross-platform example which contains - as a further goodie - a cross-platform procedure to place the labels of a TrackbarGadget under their corresponding tick marks. I have tested this code example successfully on these operating systems with PB 5.11 in ASCII and Unicode mode:

- Windows XP SP3 x86
- Windows 7 SP1 x64 with PB 5.11 x86 and x64
- MacOS X 10.6.8 (Snow Leopard) with PB 5.11 x86 and x64
- MacOS X 10.8.3 (Mountain Lion) with PB 5.11 x86 and x64
- Lubuntu 12.10 x86
- Ubuntu 12.04 x64 with KDE
- Ubuntu 12.04 x64 with Unity

But nevertheless there remain subtle differences between the different operating systems:

- On MacOS X it's possible to decrease the row height beyond the initial default value (the text then may become partially hidden!). On Windows and Linux it's only possible to increase the row height!
- On MacOS X on increasing row height the text will stay in the upper part of the row while on Windows and Linux the text always remains centered!

Code: Select all

EnableExplicit

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Linux
    ImportC ""
      gtk_scale_add_mark(*TrackBar.GtkScale, Value.D, Position.I, *MarkupText)
      gtk_tree_view_column_get_cell_renderers(*Column.GtkTreeViewColumn)
    EndImport
    
    Define OldRowHeight.L
    Define RowHeight.L
    Define TrackBarHeight.I = 55

    Procedure DrawTickMarkLabels(TrackBarID.I)
      Protected i.I
      Protected Label.S
      Protected *LabelBuffer = AllocateMemory(8)
      Protected Maximum.I = GetGadgetAttribute(TrackBarID, #PB_TrackBar_Maximum)
      Protected Minimum.I = GetGadgetAttribute(TrackBarID, #PB_TrackBar_Minimum)

      For i = Minimum To Maximum
        Label = Str(i)
        PokeS(*LabelBuffer, Label, MemorySize(*LabelBuffer), #PB_Ascii)
        gtk_scale_add_mark(GadgetID(TrackBarID), i, #GTK_POS_BOTTOM, *LabelBuffer)
      Next i

      FreeMemory(*LabelBuffer)
    EndProcedure

    Procedure.I GetCellRenderer(ListIconID.I, CellRendererID.I)
      Static    *CellRenderer0.GtkCellRenderer
      Static    *CellRenderer1.GtkCellRenderer
      Protected CellRendererList.I
      Protected Column.I
      Protected i.I
      
      If *CellRenderer0 = 0
        ; ----- Get column 0
        Column = gtk_tree_view_get_column_(GadgetID(ListIconID), 0)
        
        If Column
          ; ----- Get list of cell renderers for column 0
          CellRendererList = gtk_tree_view_column_get_cell_renderers(Column)
          
          If CellRendererList
            ; ----- Get 1st cell renderer from list for changing row height
            *CellRenderer0 = g_list_nth_data_(CellRendererList, 0)
            ; ----- Get 2nd cell renderer from list to obtain current row height
            *CellRenderer1 = g_list_nth_data_(CellRendererList, 1)
          EndIf
        EndIf
      EndIf

      If CellRendererID = 0
        ProcedureReturn *CellRenderer0
      Else
        ProcedureReturn *CellRenderer1
      EndIf
    EndProcedure

    Procedure.L GetRowHeight(ListIconID.I)
      Protected *CellRenderer.GtkCellRenderer
      Protected RowHeight.L
      Protected RowWidth.L
      Protected xOffset.L
      Protected yOffset.L

      *CellRenderer = GetCellRenderer(ListIconID, 1)
      gtk_cell_renderer_get_size_(*CellRenderer, GadgetID(ListIconID), 0, @xOffset, @yOffset, @RowWidth, @RowHeight)
      ProcedureReturn RowHeight
    EndProcedure

    Procedure SetRowHeight(ListIconID.I, RowHeight.L)
      Protected *CellRenderer.GtkCellRenderer
      Protected Column.I

      Column = gtk_tree_view_get_column_(GadgetID(ListIconID), 0)
        
      If Column
        *CellRenderer = GetCellRenderer(ListIconID, 0)
        *CellRenderer\height = RowHeight
        gtk_tree_view_column_clear_attributes_(Column, *CellRenderer)
      EndIf
    EndProcedure
  CompilerCase #PB_OS_MacOS
    Define RowHeight.CGFloat
    Define OldRowHeight.CGFloat
    Define TrackBarHeight.I = 24
    
    Procedure DrawTickMarkLabels(TrackBarID.I)
      Protected i.I
      Protected Label.S
      Protected LabelWidth.I
      Protected Maximum.I = GetGadgetAttribute(TrackBarID, #PB_TrackBar_Maximum)
      Protected Minimum.I = GetGadgetAttribute(TrackBarID, #PB_TrackBar_Minimum)
      Protected Rectangle.NSRect
      Protected TickHeight.I
      Protected TickX.I
      Protected TickY.I
      
      For i = Minimum To Maximum
        CocoaMessage(@Rectangle, GadgetID(TrackBarID), "rectOfTickMarkAtIndex:", i - Minimum)
        TickX = Rectangle\origin\x
        TickY = Rectangle\origin\y
        TickHeight = Rectangle\size\height
        
        StartDrawing(WindowOutput(0))
          Label = Str(i)
          LabelWidth = TextWidth(Label)
        StopDrawing()
        
        TextGadget(#PB_Any, GadgetX(TrackBarID) + TickX - LabelWidth / 2 - 2, GadgetY(TrackBarID) + TickY + TickHeight, LabelWidth + 8, 15, Label)
      Next i
    EndProcedure
    
    Procedure.I GetRowHeight(ListIconID.I)
      Protected RowHeight.CGFloat
      
      CocoaMessage(@RowHeight, GadgetID(ListIconID), "rowHeight")
      ProcedureReturn Int(RowHeight)
    EndProcedure
    
    Procedure SetRowHeight(ListIconID.I, RowHeight.CGFloat)
      CocoaMessage(0, GadgetID(0), "setRowHeight:@", @RowHeight)
    EndProcedure
  CompilerCase #PB_OS_Windows
    Define OldRowHeight.I
    Define RowHeight.I
    Define TrackBarHeight.I = 30

    Procedure DrawTickMarkLabels(TrackBarID.I)
      Protected i.I
      Protected Label.S
      Protected LabelWidth.I
      Protected Maximum.I = GetGadgetAttribute(TrackBarID, #PB_TrackBar_Maximum)
      Protected Minimum.I = GetGadgetAttribute(TrackBarID, #PB_TrackBar_Minimum)
      Protected TickX.I
      Protected TickXDelta.I
      Protected TickXFirst.I

      For i = 0 To Maximum - Minimum - 2
        TickX = SendMessage_(GadgetID(TrackBarID), #TBM_GETTICPOS, i, 0)

        Select i
          Case 0
            TickXFirst = TickX
          Case 1
            TickXDelta = TickX - TickXFirst
        EndSelect

        StartDrawing(WindowOutput(0))
          Label = Str(i + Minimum + 1)
          LabelWidth = TextWidth(Label)
        StopDrawing()

        TextGadget(#PB_Any, GadgetX(TrackBarID) + TickX - LabelWidth / 2 - 2 + 4, GadgetY(TrackBarID) + GadgetHeight(TrackBarID) + 2, LabelWidth, 15, Label)
      Next i

      StartDrawing(WindowOutput(0))
        Label = Str(Minimum)
        LabelWidth = TextWidth(Label)
      StopDrawing()

      TextGadget(#PB_Any, GadgetX(TrackBarID) + LabelWidth / 2 - 2, GadgetY(TrackBarID) + GadgetHeight(TrackBarID) + 2, LabelWidth, 15, Label)

      StartDrawing(WindowOutput(0))
        Label = Str(Maximum)
        LabelWidth = TextWidth(Label)
      StopDrawing()

      TextGadget(#PB_Any, GadgetX(TrackBarID) + TickX + TickXDelta - LabelWidth / 2 - 2 + 4, GadgetY(TrackBarID) + GadgetHeight(TrackBarID) + 2, LabelWidth, 15, Label)
    EndProcedure
    
    Procedure.I GetRowHeight(ListIconID.I)
      Protected Rectangle.RECT
      
      Rectangle\left = #LVIR_BOUNDS
      SendMessage_(GadgetID(ListIconID), #LVM_GETITEMRECT, 0, Rectangle)
      ProcedureReturn Rectangle\bottom - Rectangle\top - 1
    EndProcedure
    
    Procedure SetRowHeight(ListIconID.I, RowHeight.I)
      Protected ImageHandle.I
      
      ImageHandle = ImageList_Create_(1, RowHeight, #ILC_COLORDDB, 0, 0)
      SendMessage_(GadgetID(ListIconID), #LVM_SETIMAGELIST, #LVSIL_SMALL, ImageHandle)
      ImageList_Destroy_(ImageHandle)
    EndProcedure
CompilerEndSelect

Define i.I
Define TickLabelList.S

OpenWindow(0, 200, 100, 470, 210, "Change ListIcon's row height")

ListIconGadget(0, 10, 10, WindowWidth(0) - 20, 94, "Name", 110, #PB_ListIcon_GridLines)
AddGadgetColumn(0, 1, "Address", GadgetWidth(0) - GetGadgetItemAttribute(0, 0, #PB_ListIcon_ColumnWidth) - 30)
AddGadgetItem(0, -1, "Harry Rannit" + #LF$ + "12 Parliament Way, Battle Street, By the Bay")
AddGadgetItem(0, -1, "Ginger Brokeit" + #LF$ + "130 PureBasic Road, BigTown, CodeCity")
AddGadgetItem(0, -1, "Didi Foundit" + #LF$ + "321 Logo Drive, Mouse House, Downtown")

Frame3DGadget(1, 10, GadgetY(0) + GadgetHeight(0) + 10, WindowWidth(0) - 20, 80, "Row height:")
TrackBarGadget(2, GadgetX(1) + 10, GadgetY(1) + 20, GadgetWidth(1) - 20, TrackBarHeight, 10, 30, #PB_TrackBar_Ticks)
DrawTickMarkLabels(2)

RowHeight = GetRowHeight(0)
OldRowHeight = RowHeight
SetGadgetState(2, RowHeight)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget
      If EventGadget() = 2
        RowHeight = GetGadgetState(2)

        If RowHeight <> OldRowHeight
          SetRowHeight(0, RowHeight)
          OldRowHeight = RowHeight
        EndIf
      EndIf
  EndSelect
ForEver
mdp
Enthusiast
Enthusiast
Posts: 115
Joined: Mon Apr 18, 2005 8:28 pm

Re: ListIconGadget (GtkTreeView) - row height

Post by mdp »

Sorry, I just re-emerged...
I checked your code, Shardik, but it would still take me a while and some extra study of GTK+ (I really am a newby at it) to get clearer ideas and experiment... I cannot believe the TreeView rows cannot be shrunk below that value.

By the way: you mention that It's not possible to reduce a row's height below a specific minimum value (19 pixels in Ubuntu 12.04 x64 with KDE) - did you have the chance to test on other distributions (maybe 32bit, considering that in your tests the x64 distros return a wrong value for the vertical-separator)?
Post Reply