1{%MainUnit gtk2wscomctrls.pp} 2{ 3 ***************************************************************************** 4 This file is part of the Lazarus Component Library (LCL) 5 6 See the file COPYING.modifiedLGPL.txt, included in this distribution, 7 for details about the license. 8 ***************************************************************************** 9} 10 11type 12 TLVHack = class(TCustomListView) 13 end; 14 TLVItemHack = class(TListItem) 15 end; 16 17//////////////////////////////////////// 18//// Event Code ///////////////////// 19//////////////////////////////////////// 20 21function IsOldGtk2: Boolean; 22begin 23 Result := (gtk_major_version = 2) and (gtk_minor_version < 10); 24end; 25 26procedure Gtk2_PixBufFromBitmap(const BitImage:TBitmap; out pixbuf:PGdkPixbuf); 27var 28GDIObj: PGDIObject; 29bitmap:PGdkBitmap; 30Width, Height:gint; 31pixmap: PGdkPixmap; 32begin 33GDIObj := {%H-}PGDIObject(BitImage.Handle); 34 case GDIObj^.GDIBitmapType of 35 gbBitmap: 36 begin 37 bitmap := GDIObj^.GDIBitmapObject; 38 gdk_drawable_get_size(bitmap, @Width, @Height); 39 pixbuf := CreatePixbufFromDrawable(bitmap, nil, False, 0, 0, 0, 0, Width, Height); 40 end; 41 gbPixmap: 42 begin 43 pixmap := GDIObj^.GDIPixmapObject.Image; 44 if pixmap <> nil then 45 begin 46 gdk_drawable_get_size(pixmap, @Width, @Height); 47 bitmap := CreateGdkMaskBitmap(BitImage.Handle, 0); 48 pixbuf := CreatePixbufFromImageAndMask(pixmap, 0, 0, Width, Height, nil, Bitmap); 49 end; 50 end; 51 gbPixbuf: 52 begin 53 pixbuf := gdk_pixbuf_copy(GDIObj^.GDIPixbufObject); 54 end; 55 end; 56end; 57 58procedure Gtk2_ItemCheckedChanged(renderer: PGtkCellRendererToggle; PathStr: Pgchar; WidgetInfo: PWidgetInfo);cdecl; 59var 60 LV: TLVHack; 61 Index: Integer; 62 ListItem: TLVItemHack; 63 ARect: TGdkRectangle; 64 R: TRect; 65 x, y, cellw, cellh: gint; 66begin 67 LV := TLVHack(WidgetInfo^.LCLObject); 68 Index := StrToInt(PathStr); 69 ListItem := TLVItemHack(LV.Items.Item[Index]); 70 if ListItem <> nil then 71 begin 72 ListItem.Checked := not ListItem.GetCheckedInternal; 73 if Assigned(LV.OnItemChecked) then 74 LV.OnItemChecked(TListView(WidgetInfo^.LCLObject), LV.Items.Item[Index]); 75 76 // we must update renderer row, otherwise visually it looks different 77 // if we change toggle state by keyboard (eg. pressing Space key) 78 R := ListItem.DisplayRect(drBounds); 79 ARect := GdkRectFromRect(R); 80 gtk_cell_renderer_get_size(PGtkCellRenderer(renderer), 81 WidgetInfo^.CoreWidget, @ARect, @x,@y, @cellw, @cellh); 82 with R do 83 gtk_widget_queue_draw_area(WidgetInfo^.CoreWidget, Left, Top, cellW, cellH); 84 end; 85end; 86 87procedure Gtk2_ItemFocusChanged(Widget: PGtkWidget; WidgetInfo: PWidgetInfo);cdecl; 88var 89 msg: TLMNotify; 90 NM: TNMListView; 91 path: PGtkTreePath; 92 pstr: PChar; 93 column: PGtkTreeViewColumn; 94 cell: PGtkCellRenderer; 95begin 96 // DebugLn('Gtk2_ItemFocusChanged'); 97 // the defocus of the oldrow isn't send 98 if GTK_IS_TREE_VIEW(Widget) then begin 99 path:=nil; 100 column:=nil; 101 gtk_tree_view_get_cursor(PGtkTreeView(Widget), path, column); 102 end 103 else 104 if GTK_IS_ICON_VIEW(Widget) then begin 105 path:=nil; 106 cell:=nil; 107 gtk_icon_view_get_cursor(PGtkIconView(Widget), path, cell); 108 end 109 else 110 path := nil; 111 112 if path = nil then 113 Exit; 114 115 gtk_tree_path_free(path); 116 117 msg.Msg := CN_NOTIFY; 118 119 FillChar(NM{%H-}, SizeOf(NM), 0); 120 NM.hdr.hwndfrom := {%H-}PtrUInt(WidgetInfo^.CoreWidget); 121 NM.hdr.code := LVN_ITEMCHANGED; 122 pstr:=gtk_tree_path_to_string(path); 123 NM.iItem := StrToInt(pstr); 124 g_free(pstr); 125 126 NM.iSubItem := 0; 127 NM.uNewState := LVIS_FOCUSED; 128 NM.uChanged := LVIF_STATE; 129 msg.NMHdr := @NM.hdr; 130 DeliverMessage(WidgetInfo^.LCLObject, msg); 131end; 132 133procedure Gtk2_ItemDeleted({%H-}model: PGtkTreeModel; path: PGtkTreePath; WidgetInfo: PWidgetInfo); cdecl; 134var 135 msg: TLMNotify; 136 NM: TNMListView; 137 pstr:PChar; 138begin 139 //DebugLn('Gtk2_ItemDeleted'); 140 msg.Msg := CN_NOTIFY; 141 142 FillChar(NM{%H-}, SizeOf(NM), 0); 143 NM.hdr.hwndfrom := {%H-}PtrUInt(WidgetInfo^.CoreWidget); 144 NM.hdr.code := LVN_DELETEITEM; 145 pstr := gtk_tree_path_to_string(path); 146 NM.iItem := StrToInt(pstr); 147 g_free(pstr); 148 msg.NMHdr := @NM.hdr; 149 DeliverMessage(WidgetInfo^.LCLObject, msg); 150end; 151 152procedure Gtk2_ItemInserted({%H-}model: PGtkTreeModel; path: PGtkTreePAth; {%H-}Iter: PGtkTreeIter; WidgetInfo: PWidgetInfo); cdecl; 153var 154 msg: TLMNotify; 155 NM: TNMListView; 156begin 157 //DebugLn('Gtk2_ItemInserted'); 158 msg.Msg := CN_NOTIFY; 159 160 FillChar(NM{%H-}, SizeOf(NM), 0); 161 NM.hdr.hwndfrom := {%H-}PtrUInt(WidgetInfo^.CoreWidget); 162 NM.hdr.code := LVN_INSERTITEM; 163 NM.iItem := gtk_tree_path_get_indices(path)^; 164 msg.NMHdr := @NM.hdr; 165 DeliverMessage(WidgetInfo^.LCLObject, msg); 166end; 167 168//This is only for when the tree view sorts itself. Not needed since the LCL does the sorting. 169//procedure Gtk2_ItemMoved(model: PGtkTreeModel; path: PGtkTreePAth; Iter: PGtkTreeIter; WidgetInfo: PWidgetInfo); cdecl; 170//begin 171//end; 172 173procedure Gtk2_ItemChanged({%H-}model: PGtkTreeModel; {%H-}path: PGtkTreePAth; {%H-}Iter: PGtkTreeIter; {%H-}WidgetInfo: PWidgetInfo); cdecl; 174begin 175 // OnChange Occurs immediately after an item in the list changes. 176 // The Item parameter is the list item that just changed. The Change parameter 177 // indicates the type of change that just occurred. Change is ctText if the 178 // Caption property of the item changed. Change is ctImage if the ImageIndex 179 // property of the item changed or the appropriate image list changed in the 180 // list view. Change is ctState if the Cut, Focused, or Selected property of 181 // the item changed. 182 // DebugLn('Gtk2_ItemChanged'); 183end; 184 185 186procedure Gtk2_ColumnClicked(column: PGtkTreeViewColumn; WidgetInfo: PWidgetInfo); cdecl; 187var 188 AColumn: TListColumn; 189 msg: TLMNotify; 190 NM: TNMListView; 191begin 192 AColumn := TListColumn(g_object_get_data(G_OBJECT(column), 'TListColumn')); 193 194 msg.Msg := CN_NOTIFY; 195 196 FillChar(NM{%H-}, SizeOf(NM), 0); 197 NM.hdr.hwndfrom := {%H-}PtrUInt(WidgetInfo^.CoreWidget); 198 NM.hdr.code := LVN_COLUMNCLICK; 199 NM.iItem := -1; 200 NM.iSubItem := AColumn.Index; 201 msg.NMHdr := @NM.hdr; 202 DeliverMessage(WidgetInfo^.LCLObject, msg); 203end; 204 205procedure BroadcastListSelection(Target : Pointer; AHandle : HWND; AIndex : Integer; 206 AState : Boolean); 207var 208 msg: TLMNotify; 209 NM: TNMListView; 210begin 211 msg.Msg := CN_NOTIFY; 212 213 FillChar(NM{%H-}, SizeOf(NM), 0); 214 NM.hdr.hwndfrom := AHandle; 215 NM.hdr.code := LVN_ITEMCHANGED; 216 NM.iItem := AIndex; 217 NM.iSubItem := 0; 218 if AState then 219 NM.uOldState := LVIS_SELECTED 220 else 221 NM.uNewState := LVIS_SELECTED; 222 NM.uChanged := LVIF_STATE; 223 msg.NMHdr := @NM.hdr; 224 if g_object_get_data({%H-}PGObject(TWinControl(Target).Handle),'lcl_gtkwidget_in_update') = nil then 225 begin 226 DeliverMessage(Target, msg); 227 if TLVHack(Target).Selected = TLVHack(Target).Items[AIndex] then 228 begin 229 NM.uOldState := 0; 230 NM.uNewState := LVIS_FOCUSED; 231 NM.uChanged := LVIF_STATE; 232 msg.NMHdr := @NM.hdr; 233 DeliverMessage(Target, msg); 234 end else 235 if TLVHack(Target).Selected = nil then 236 begin 237 NM.uOldState := LVIS_FOCUSED; 238 NM.uNewState := 0; 239 NM.uChanged := LVIF_STATE; 240 msg.NMHdr := @NM.hdr; 241 DeliverMessage(Target, msg); 242 end; 243 end; 244end; 245 246procedure Gtk2_ItemSelectionChanged(selection: PGtkTreeSelection; WidgetInfo: PWidgetInfo); cdecl; 247var 248 Widgets: PTVWidgets; 249 AIndex: String; 250 i: Integer; 251 Indices: Integer; 252 ListIndex: Integer; 253 List: PgList; 254 Path: PGtkTreePath; 255begin 256 // DebugLn('Gtk2_ItemSelectionChanged'); 257 Widgets := PTVWidgets(WidgetInfo^.UserData); 258 259 if (widgets = nil) or (Widgets^.ItemCache = nil) or 260 (Widgets^.ItemCache.Count=0) then 261 begin 262 // debugln(' Gtk2_ItemSelectionChanged ItemCache=nil ',tComponent(widgetInfo^.lclObject).name); 263 if IsOldGtk2 and (Widgets <> nil) and (Widgets^.ItemCache <> nil) then 264 begin 265 // debugLn('ItemsCache is valid ! count ',dbgs(Widgets^.ItemCache.Count)); 266 List := gtk_tree_selection_get_selected_rows(Selection, nil); 267 if (List <> nil) then 268 begin 269 if Assigned(Widgets^.OldTreeSelection) then 270 begin 271 // we must iterate because of multiselections 272 for i := 0 to g_list_length(Widgets^.OldTreeSelection) - 1 do 273 begin 274 Path := g_list_nth_data(Widgets^.OldTreeSelection, i); 275 if Path <> nil then 276 begin 277 Indices := gtk_tree_path_get_indices(Path)^; 278 ListIndex := Widgets^.ItemCache.IndexOf(IntToStr(Indices)); 279 if ListIndex = -1 then 280 Widgets^.ItemCache.AddObject(IntToStr(Indices), TObject(1)) 281 else 282 Widgets^.ItemCache.Objects[ListIndex] := TObject(1); 283 end; 284 end; 285 g_list_free(Widgets^.OldTreeSelection); 286 Widgets^.OldTreeSelection := g_list_alloc; 287 // we must iterate because of multiselections 288 for i := 0 to g_list_length(List) - 1 do 289 g_list_append(Widgets^.OldTreeSelection, g_list_nth_data(List, i)); 290 end; 291 // now compare new selection (add or set as selected) 292 for i := 0 to g_list_length(List) - 1 do 293 begin 294 Path := g_list_nth_data(List, i); 295 if Path <> nil then 296 begin 297 Indices := gtk_tree_path_get_indices(Path)^; 298 ListIndex := Widgets^.ItemCache.IndexOf(IntToStr(Indices)); 299 if ListIndex = -1 then 300 Widgets^.ItemCache.AddObject(IntToStr(Indices), TObject(0)) 301 else 302 Widgets^.ItemCache.Objects[ListIndex] := TObject(0); 303 end; 304 end; 305 g_list_free(List); 306 end else 307 begin 308 // complete selection is clear ! 309 if Assigned(Widgets^.OldTreeSelection) then 310 begin 311 for i := 0 to g_list_length(Widgets^.OldTreeSelection) - 1 do 312 begin 313 Path := g_list_nth_data(Widgets^.OldTreeSelection, i); 314 if Path <> nil then 315 begin 316 Indices := gtk_tree_path_get_indices(Path)^; 317 ListIndex := Widgets^.ItemCache.IndexOf(IntToStr(Indices)); 318 if ListIndex = -1 then 319 Widgets^.ItemCache.AddObject(IntToStr(Indices), TObject(1)) 320 else 321 Widgets^.ItemCache.Objects[ListIndex] := TObject(1); 322 end; 323 end; 324 g_list_free(Widgets^.OldTreeSelection); 325 Widgets^.OldTreeSelection := g_list_alloc; 326 end; 327 end; 328 end else 329 Exit; 330 end; 331 332 // DebugLn('Gtk2_ItemSelectionChanged Trigger OnSelectItem ? ', dbgs(not (wwiInvalidEvent in Widgets^.WidgetInfo^.Flags))); 333 // LCL sent selection ! 334 if wwiInvalidEvent in Widgets^.WidgetInfo^.Flags then 335 exit; 336 337 for i := 0 to Widgets^.ItemCache.Count -1 do 338 begin 339 AIndex := Widgets^.ItemCache.Strings[i]; 340 BroadcastListSelection(WidgetInfo^.LCLObject, {%H-}PtrUInt(Widgets^.MainView), 341 StrToInt(AIndex), Widgets^.ItemCache.Objects[i] <> nil); 342 end; 343 Widgets^.ItemCache.Clear; 344end; 345 346procedure Gtk2_IconViewSelectionChanged(AIconView: PGtkIconView; WidgetInfo: PWidgetInfo); cdecl; 347var 348 Widgets: PTVWidgets; 349 AIndex: String; 350 i: Integer; 351 List: PGList; 352 Path: PGtkTreePath; 353 pstr: PChar; 354begin 355 Widgets := PTVWidgets(WidgetInfo^.UserData); 356 357 if (Widgets=nil) or (Widgets^.ItemCache=nil) or (Widgets^.ItemCache.Count=0) then 358 begin 359 if (Widgets^.ItemCache <> nil) and (Widgets^.ItemCache.Count = 0) then 360 begin 361 List := gtk_icon_view_get_selected_items(AIconView); 362 if (List <> nil) then 363 begin 364 Path := PGtkTreePath(g_list_first(List)^.data); 365 pstr := gtk_tree_path_to_string(path); 366 Widgets^.ItemCache.Add(pstr); 367 g_free(pstr); 368 g_list_free(List); 369 end else 370 exit; 371 end else 372 Exit; 373 end; 374 375 // LCL already sent selection ! 376 if wwiInvalidEvent in Widgets^.WidgetInfo^.Flags then 377 exit; 378 379 for i := 0 to Widgets^.ItemCache.Count -1 do 380 begin 381 AIndex := Widgets^.ItemCache.Strings[i]; 382 BroadcastListSelection(WidgetInfo^.LCLObject, {%H-}PtrUInt(Widgets^.MainView), 383 StrToInt(AIndex), Widgets^.ItemCache.Objects[i] <> nil); 384 end; 385 Widgets^.ItemCache.Clear; 386end; 387 388function Gtk2WSLV_ItemSelected({%H-}selection: PGtkTreeSelection; {%H-}model: PGtkTreeModel; 389 path: PGtkTreePath; path_is_currently_selected: GBoolean; WidgetInfo: PWidgetInfo): GBoolean; cdecl; 390var 391 Widgets: PTVWidgets; 392 i: Integer; 393 Item: integer; 394begin 395 // DebugLn('Gtk2_ItemSelected '); 396 // this function is called *before* the item is selected 397 // The result should be True to allow the Item to change selection 398 Result := True; 399 400 Widgets := PTVWidgets(WidgetInfo^.UserData); 401 Item := gtk_tree_path_get_indices(path)^; 402 i := Widgets^.ItemCache.IndexOf(IntToStr(Item)); 403 if i = -1 Then 404 Widgets^.ItemCache.AddObject(IntToStr(Item), TObject(PtrInt(Ord(path_is_currently_selected)))) 405 else 406 Widgets^.ItemCache.Objects[i] := TObject(PtrInt(Ord(path_is_currently_selected))); 407end; 408 409procedure Gtk2WSLV_ListViewGetCheckedDataFunc({%H-}tree_column: PGtkTreeViewColumn; 410 cell: PGtkCellRenderer; tree_model: PGtkTreeModel; iter: PGtkTreeIter; WidgetInfo: PWidgetInfo); cdecl; 411var 412 APath: PGtkTreePath; 413 ListItem: TLVItemHack; 414begin 415 gtk_tree_model_get(tree_model, iter, [0, @ListItem, -1]); 416 417 if (ListItem = nil) and TCustomListView(WidgetInfo^.LCLObject).OwnerData then 418 begin 419 APath := gtk_tree_model_get_path(tree_model,iter); 420 ListItem := TLVItemHack(TCustomListView(WidgetInfo^.LCLObject).Items[gtk_tree_path_get_indices(APath)^]); 421 gtk_tree_path_free(APath); 422 end; 423 424 if ListItem = nil then 425 Exit; 426 gtk_cell_renderer_toggle_set_active(PGtkCellRendererToggle(cell), ListItem.GetCheckedInternal); 427end; 428 429 430procedure Gtk2WSLV_ListViewGetPixbufDataFuncForColumn(tree_column: PGtkTreeViewColumn; 431 cell: PGtkCellRenderer; tree_model: PGtkTreeModel; iter: PGtkTreeIter; WidgetInfo: PWidgetInfo); cdecl; 432var 433 ListItem: TListItem; 434 Images: TList; 435 Widgets: PTVWidgets; 436 ListColumn: TListColumn; 437 ImageIndex: Integer; 438 ColumnIndex: Integer; 439 APath: PGtkTreePath; 440 ImageList: TCustomImageList; 441 Bmp: TBitmap; 442 pixbuf: PGdkPixbuf; 443begin 444 PGtkCellRendererPixbuf(cell)^.pixbuf := nil; 445 Widgets := PTVWidgets(WidgetInfo^.UserData); 446 gtk_tree_model_get(tree_model, iter, [0, @ListItem, -1]); 447 448 ListColumn := TListColumn(g_object_get_data(G_OBJECT(tree_column), 'TListColumn')); 449 if ListColumn = nil then 450 Exit; 451 ColumnIndex := ListColumn.Index; 452 ImageList := nil; 453 Images := Widgets^.Images; 454 if TCustomListView(WidgetInfo^.LCLObject).OwnerData then 455 ImageList := TLVHack(WidgetInfo^.LCLObject).SmallImages; 456 if (Images = nil) and (ImageList = nil) then 457 begin 458 Exit; 459 end; 460 ImageIndex := -1; 461 462 if (ListItem = nil) and TCustomListView(WidgetInfo^.LCLObject).OwnerData then 463 begin 464 APath := gtk_tree_model_get_path(tree_model,iter); 465 ListItem := TCustomListView(WidgetInfo^.LCLObject).Items[gtk_tree_path_get_indices(APath)^]; 466 gtk_tree_path_free(APath); 467 end; 468 469 if ListItem = nil then 470 Exit; 471 472 if ColumnIndex = 0 then 473 ImageIndex := ListItem.ImageIndex 474 else 475 if ColumnIndex -1 <= ListItem.SubItems.Count-1 then 476 ImageIndex := ListItem.SubItemImages[ColumnIndex-1]; 477 478 if (ImageList <> nil) and 479 (ImageIndex > -1) and (ImageIndex <= ImageList.Count-1) then 480 begin 481 Bmp := TBitmap.create; 482 try 483 pixbuf := nil; 484 ImageList.GetBitmap(ImageIndex, Bmp); 485 Gtk2_PixBufFromBitmap(Bmp,pixbuf); 486 PGtkCellRendererPixbuf(cell)^.pixbuf :=pixbuf; 487 finally 488 Bmp.Free; 489 end; 490 end else 491 if (ImageIndex > -1) and (ImageIndex <= Images.Count-1) then 492 PGtkCellRendererPixbuf(cell)^.pixbuf := PGdkPixbuf(Images.Items[ImageIndex]) 493 else 494 PGtkCellRendererPixbuf(cell)^.pixbuf := nil; 495end; 496 497procedure Gtk2WSLV_ListViewGetPixbufDataFuncForIconView({%H-}cell_layout:PGtkCellLayout; 498 cell: PGtkCellRenderer; tree_model: PGtkTreeModel; iter: PGtkTreeIter; WidgetInfo: PWidgetInfo); cdecl; 499var 500 ListItem: TListItem; 501 Images: TList; 502 Widgets: PTVWidgets; 503 ImageIndex: Integer; 504 APath: PGtkTreePath; 505begin 506 PGtkCellRendererPixbuf(cell)^.pixbuf := nil; 507 Widgets := PTVWidgets(WidgetInfo^.UserData); 508 gtk_tree_model_get(tree_model, iter, [0, @ListItem, -1]); 509 510 Images := Widgets^.Images; 511 if Images = nil then 512 Exit; 513 ImageIndex := -1; 514 515 if (ListItem = nil) and TCustomListView(WidgetInfo^.LCLObject).OwnerData then 516 begin 517 APath := gtk_tree_model_get_path(tree_model,iter); 518 ListItem := TCustomListView(WidgetInfo^.LCLObject).Items[gtk_tree_path_get_indices(APath)^]; 519 gtk_tree_path_free(APath); 520 end; 521 522 if ListItem = nil then 523 Exit; 524 525 ImageIndex := ListItem.ImageIndex; 526 527 if (ImageIndex > -1) and (ImageIndex <= Images.Count-1) then 528 PGtkCellRendererPixbuf(cell)^.pixbuf := PGdkPixbuf(Images.Items[ImageIndex]) 529 else 530 PGtkCellRendererPixbuf(cell)^.pixbuf := nil; 531end; 532 533{ TGtk2WSCustomListView } 534 535class procedure TGtk2WSCustomListView.SetPropertyInternal(const ALV: TCustomListView; 536 const Widgets: PTVWidgets; const AProp: TListViewProperty; 537 const AIsSet: Boolean); 538const 539 BoolToSelectionMode: array[Boolean] of TGtkSelectionMode = ( 540 GTK_SELECTION_SINGLE, 541 GTK_SELECTION_MULTIPLE 542 ); 543begin 544 with Widgets^ do begin 545 case AProp of 546 lvpAutoArrange: begin 547 // TODO: implement ?? 548 end; 549 lvpCheckboxes: 550 begin 551 if TLVHack(ALV).ViewStyle in [vsReport,vsList] then 552 AddRemoveCheckboxRenderer(ALV, GetWidgetInfo(Widgets^.MainView), AIsSet); 553 end; 554 lvpColumnClick: begin 555 // allow only column modifications when in report mode 556 if TLVHack(ALV).ViewStyle <> vsReport then Exit; 557 gtk_tree_view_set_headers_clickable(PGtkTreeView(MainView), AIsSet); 558 end; 559 lvpFlatScrollBars: begin 560 // TODO: implement ?? 561 end; 562 lvpFullDrag: begin 563 // TODO: implement ?? 564 end; 565 lvpGridLines: begin 566 // TODO: better implementation 567 // maybe possible with some cellwidget hacking 568 // this create rows with alternating colors 569 if GTK_IS_TREE_VIEW(MainView) then 570 begin 571 if gtk_tree_view_set_grid_lines <> nil then 572 begin 573 if AIsSet then 574 gtk_tree_view_set_grid_lines(PGtkTreeView(MainView), GTK_TREE_VIEW_GRID_LINES_BOTH) 575 else 576 gtk_tree_view_set_grid_lines(PGtkTreeView(MainView), GTK_TREE_VIEW_GRID_LINES_NONE); 577 578 end else 579 gtk_tree_view_set_rules_hint(PGtkTreeView(MainView), AIsSet); 580 end; 581 end; 582 lvpHideSelection: begin 583 // TODO: implement 584 // should be possible with some focus in/out events 585 end; 586 lvpHotTrack: begin 587 // TODO: implement 588 // should be possible with some mouse tracking 589 end; 590 lvpMultiSelect: begin 591 if GTK_IS_TREE_VIEW(MainView) then 592 gtk_tree_selection_set_mode(TreeSelection, BoolToSelectionMode[AIsSet]) 593 else 594 if GTK_IS_ICON_VIEW(MainView) then 595 gtk_icon_view_set_selection_mode(PGtkIconView(MainView), BoolToSelectionMode[AIsSet]); 596 end; 597 lvpOwnerDraw: 598 begin 599 // It must send CN_DRAWITEM with ItemID and proper rect of item 600 // then LCL does all other stuff. Note that OwnerDraw should work only 601 // in case of vsReport, according to embarcadero docs. 602 // http://docwiki.embarcadero.com/Libraries/XE4/en/Vcl.ComCtrls.TCustomListView.OnDrawItem 603 // NOTE: this is automatically handled by cell renderer (Gtk2CellRenderer). 604 end; 605 lvpReadOnly: begin 606 // TODO: implement inline editor ? 607 end; 608 lvpRowSelect: begin 609 // TODO: implement ??? 610 // how to do cell select 611 end; 612 lvpShowColumnHeaders: begin 613 // allow only column modifications when in report mode 614 if TLVHack(ALV).ViewStyle <> vsReport then Exit; 615 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW (MainView), AIsSet); 616 end; 617 lvpShowWorkAreas: begin 618 // TODO: implement ??? 619 end; 620 lvpWrapText: begin 621 // TODO: implement ??? 622 end; 623 end; 624 end; 625end; 626 627class procedure TGtk2WSCustomListView.SetNeedDefaultColumn(const ALV: TCustomListView; const AValue: Boolean); 628var 629 Widgets: PTVWidgets; 630 WidgetInfo: PWidgetInfo; 631 GtkColumn: PGtkTreeViewColumn; 632 pixrenderer, 633 textrenderer: PGtkCellRenderer; 634begin 635 if not WSCheckHandleAllocated(ALV, 'SetNeedDefaultColumn') 636 then Exit; 637 638 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 639 WidgetInfo := GetWidgetInfo({%H-}PGtkWidget(ALV.Handle)); 640 641 GtkColumn := g_object_get_data(G_OBJECT(Widgets^.MainView), 'LCL_DEFAULT_COLUMN'); 642 if AValue then 643 begin 644 if GtkColumn = nil then 645 begin 646 GtkColumn := gtk_tree_view_column_new(); 647 648 gtk_widget_unset_flags(PGtkWidget(GtkColumn), GTK_CAN_FOCUS); 649 650 // add renderers 651 pixrenderer := gtk_cell_renderer_pixbuf_new(); 652 textrenderer := LCLIntfCellRenderer_New; 653 654 if GTK_IS_TREE_VIEW(Widgets^.MainView) then 655 begin 656 gtk_tree_view_column_pack_start(GtkColumn, pixrenderer, FALSE); 657 //gtk_tree_view_column_set_attributes(GtkColumn, pixrenderer,['pixbuf', 0, nil]); 658 gtk_tree_view_column_pack_start(GtkColumn, textrenderer, True); 659 //gtk_tree_view_column_set_attributes(GtkColumn, textrenderer, ['text',0, nil]); 660 661 gtk_tree_view_column_set_cell_data_func(GtkColumn, pixrenderer, TGtkTreeCellDataFunc(@Gtk2WSLV_ListViewGetPixbufDataFuncForColumn), WidgetInfo, nil); 662 gtk_tree_view_column_set_cell_data_func(GtkColumn, textrenderer, TGtkTreeCellDataFunc(@LCLIntfCellRenderer_CellDataFunc), WidgetInfo, nil); 663 664 // insert column 665 gtk_tree_view_insert_column(GTK_TREE_VIEW(Widgets^.MainView), GtkColumn, 0); 666 end 667 else 668 if GTK_IS_ICON_VIEW(Widgets^.MainView) then 669 begin 670 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(Widgets^.MainView), pixrenderer, False); 671 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(Widgets^.MainView), textrenderer, True); 672 gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(Widgets^.MainView), pixrenderer, TGtkCellLayoutDataFunc(@Gtk2WSLV_ListViewGetPixbufDataFuncForIconView), WidgetInfo, nil); 673 gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(Widgets^.MainView), textrenderer, TGtkCellLayoutDataFunc(@LCLIntfCellRenderer_CellDataFunc), WidgetInfo, nil); 674 end; 675 g_object_set_data(G_OBJECT(Widgets^.MainView), 'LCL_DEFAULT_COLUMN', GtkColumn); 676 end; 677 end 678 else begin // No Column Needed 679 if GtkColumn <> nil then 680 begin 681 if GTK_IS_TREE_VIEW(Widgets^.MainView) and GTK_IS_TREE_VIEW_COLUMN(GtkColumn) then 682 gtk_tree_view_remove_column(PGtkTreeView(Widgets^.MainView), GtkColumn) 683 else 684 if GTK_IS_TREE_VIEW_COLUMN(GtkColumn) and G_IS_OBJECT(GtkColumn) then 685 g_object_unref(GtkColumn); 686 g_object_set_data(G_OBJECT(Widgets^.MainView), 'LCL_DEFAULT_COLUMN', nil); 687 end; 688 end; 689end; 690 691class procedure TGtk2WSCustomListView.AddRemoveCheckboxRenderer( 692 const ALV: TCustomListView; const WidgetInfo: PWidgetInfo; const Add: Boolean); 693var 694 togglerenderer, 695 pixrenderer, 696 textrenderer: PGtkCellRenderer; 697 column: PGtkTreeViewColumn; 698 renderers: PGList; 699begin 700 column := gtk_tree_view_get_column(PGtkTreeView(WidgetInfo^.CoreWidget), 0); 701 702 if column = nil then 703 Exit; 704 705 renderers := gtk_tree_view_column_get_cell_renderers(column); 706 textrenderer := PGtkCellRenderer(g_list_last(renderers)^.data); 707 pixrenderer := PGtkCellRenderer(g_list_last(renderers)^.prev^.data); 708 g_list_free(renderers); 709 g_object_ref(G_OBJECT(pixrenderer)); 710 g_object_ref(G_OBJECT(textrenderer)); 711 712 if Add then 713 begin 714 gtk_cell_layout_clear(GTK_CELL_LAYOUT(column)); 715 togglerenderer := gtk_cell_renderer_toggle_new(); 716 717 gtk_tree_view_column_pack_start(column, togglerenderer, FALSE); 718 gtk_tree_view_column_pack_start(column, pixrenderer, FALSE); 719 gtk_tree_view_column_pack_start(column, textrenderer, True); 720 gtk_tree_view_column_set_cell_data_func(column, togglerenderer, TGtkTreeCellDataFunc(@Gtk2WSLV_ListViewGetCheckedDataFunc), WidgetInfo, nil); 721 gtk_tree_view_column_set_cell_data_func(column, pixrenderer, TGtkTreeCellDataFunc(@Gtk2WSLV_ListViewGetPixbufDataFuncForColumn), WidgetInfo, nil); 722 gtk_tree_view_column_set_cell_data_func(column, textrenderer, TGtkTreeCellDataFunc(@LCLIntfCellRenderer_CellDataFunc), WidgetInfo, nil); 723 // connect toggled signal 724 g_signal_connect(togglerenderer, 'toggled', TGTKSignalFunc(@Gtk2_ItemCheckedChanged), GetWidgetInfo({%H-}PGtkWidget(ALV.Handle))); 725 726 end 727 else 728 begin 729 gtk_cell_layout_clear(GTK_CELL_LAYOUT(column)); 730 731 gtk_tree_view_column_pack_start(column, pixrenderer, FALSE); 732 gtk_tree_view_column_pack_start(column, textrenderer, True); 733 gtk_tree_view_column_set_cell_data_func(column, pixrenderer, TGtkTreeCellDataFunc(@Gtk2WSLV_ListViewGetPixbufDataFuncForColumn), WidgetInfo, nil); 734 gtk_tree_view_column_set_cell_data_func(column, textrenderer, TGtkTreeCellDataFunc(@LCLIntfCellRenderer_CellDataFunc), WidgetInfo, nil); 735 736 end; 737 if G_IS_OBJECT(pixrenderer) then 738 g_object_unref(G_OBJECT(pixrenderer)); 739 if G_IS_OBJECT(textrenderer) then 740 g_object_unref(G_OBJECT(textrenderer)); 741end; 742 743class function TGtk2WSCustomListView.GetViewModel(const AView: PGtkWidget): PGtkTreeModel; 744begin 745 if GTK_IS_TREE_VIEW(AView) then 746 Result := gtk_tree_view_get_model(PGtkTreeView(AView)) 747 else 748 if GTK_IS_ICON_VIEW(AView) then 749 Result := gtk_icon_view_get_model(PGtkIconView(AView)) 750 else 751 Result := nil; 752end; 753 754class procedure TGtk2WSCustomListView.SetListCallbacks(const AScrollWidget: PGtkWidget; 755 const Widgets: PTVWidgets; const AWidgetInfo: PWidgetInfo); 756begin 757 TGtk2WSBaseScrollingWinControl.SetCallbacks(AScrollWidget, AWidgetInfo); 758 TGtk2WSWinControl.SetCallbacks(PGtkObject(Widgets^.MainView), TComponent(AWidgetInfo^.LCLObject)); 759 760 // the callbacks for OnColumnClick are set when the column is created in ColumnInsert 761 762 if GTK_IS_TREE_VIEW(Widgets^.MainView) then 763 begin 764 if IsOldGtk2 then 765 // bug in 2.8, issue #19820 766 else 767 gtk_tree_selection_set_select_function(Widgets^.TreeSelection,TGtkTreeSelectionFunc(@Gtk2WSLV_ItemSelected), gpointer(AWidgetInfo),nil); 768 SignalConnect(PGtkWidget(Widgets^.TreeSelection), 'changed', @Gtk2_ItemSelectionChanged, AWidgetInfo); 769 SignalConnect(PGtkWidget(Widgets^.MainView), 'toggle-cursor-row', @Gtk2_ItemFocusChanged, AWidgetInfo); 770 end 771 else 772 if GTK_IS_ICON_VIEW(Widgets^.MainView) then 773 begin 774 SignalConnect(Widgets^.MainView, 'selection-changed', @Gtk2_IconViewSelectionChanged, AWidgetInfo); 775 SignalConnect(Widgets^.MainView, 'toggle-cursor-item', @Gtk2_ItemFocusChanged, AWidgetInfo); 776 end; 777 SignalConnect(PGtkWidget(Widgets^.TreeModel), 'row-changed', @Gtk2_ItemChanged, AWidgetInfo); 778 SignalConnect(PGtkWidget(Widgets^.TreeModel), 'row-inserted', @Gtk2_ItemInserted, AWidgetInfo); 779 SignalConnect(PGtkWidget(Widgets^.TreeModel), 'row-deleted', @Gtk2_ItemDeleted, AWidgetInfo); 780end; 781 782class procedure TGtk2WSCustomListView.ColumnDelete(const ALV: TCustomListView; 783 const AIndex: Integer); 784var 785 Widgets: PTVWidgets; 786 GtkColumn: PGtkTreeViewColumn; 787begin 788 if not WSCheckHandleAllocated(ALV, 'ColumnDelete') 789 then Exit; 790 791 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 792 793 if not GTK_IS_TREE_VIEW(Widgets^.MainView) then 794 Exit; 795 796 GtkColumn := gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), AIndex); 797 if (GtkColumn<>nil) and GTK_IS_TREE_VIEW_COLUMN(GtkColumn) then 798 gtk_tree_view_remove_column(PGtkTreeView(Widgets^.MainView), GtkColumn); 799end; 800 801class function TGtk2WSCustomListView.ColumnGetWidth(const ALV: TCustomListView; 802 const AIndex: Integer; const AColumn: TListColumn): Integer; 803var 804 Widgets: PTVWidgets; 805 GtkColumn: PGtkTreeViewColumn; 806begin 807 Result := -1; 808 809 if not WSCheckHandleAllocated(ALV, 'ColumnGetWidth') 810 then Exit; 811 812 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 813 if not GTK_IS_TREE_VIEW(Widgets^.MainView) then 814 Exit; 815 GtkColumn := gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), AIndex); 816 if GtkColumn <> nil then 817 begin 818 Result := gtk_tree_view_column_get_width(GtkColumn); 819 if Result = 0 then 820 Result := gtk_tree_view_column_get_fixed_width(GtkColumn); 821 end; 822end; 823 824class procedure TGtk2WSCustomListView.ColumnInsert(const ALV: TCustomListView; 825 const AIndex: Integer; const AColumn: TListColumn); 826var 827 Widgets: PTVWidgets; 828 column: PGtkTreeViewColumn; 829 pixrenderer, 830 textrenderer: PGtkCellRenderer; 831 WidgetInfo: PWidgetInfo; 832begin 833 if not WSCheckHandleAllocated(ALV, 'ColumnInsert') 834 then Exit; 835 836 WidgetInfo := GetWidgetInfo({%H-}PGtkWidget(ALV.Handle)); 837 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 838 839 if not GTK_IS_TREE_VIEW(Widgets^.MainView) then 840 Exit; 841 842 column := gtk_tree_view_column_new(); 843 844 gtk_widget_unset_flags(PGtkWidget(column), GTK_CAN_FOCUS); 845 846 // add renderers 847 pixrenderer := gtk_cell_renderer_pixbuf_new(); 848 textrenderer := LCLIntfCellRenderer_New;//gtk_cell_renderer_text_new(); 849 850 gtk_tree_view_column_pack_start(column, pixrenderer, False); 851 //gtk_tree_view_column_set_attributes(column, pixrenderer,['pixbuf', RealIndex, nil]); 852 gtk_tree_view_column_pack_start(column, textrenderer, True); 853 //gtk_tree_view_column_set_attributes(column, textrenderer, ['text', 0, nil]); 854 855 gtk_tree_view_column_set_cell_data_func(column, pixrenderer, TGtkTreeCellDataFunc(@Gtk2WSLV_ListViewGetPixbufDataFuncForColumn), WidgetInfo, nil); 856 gtk_tree_view_column_set_cell_data_func(column, textrenderer, TGtkTreeCellDataFunc(@LCLIntfCellRenderer_CellDataFunc), WidgetInfo, nil); 857 //gtk_tree_view_column_set_cell_data_func(column, textrenderer, TGtkTreeCellDataFunc(@Gtk2WSLV_ListViewGetTextDataFunc), WidgetInfo, nil); 858 859 860 //store the TColumn in the column data for callbacks 861 g_object_set_data(G_OBJECT(column), PChar('TListColumn'), gpointer(AColumn)); 862 863 // set callback for OnClick 864 SignalConnect(PGtkWidget(column), 'clicked', @Gtk2_ColumnClicked, Widgets^.WidgetInfo); 865 866 // insert column 867 gtk_tree_view_insert_column(GTK_TREE_VIEW(Widgets^.MainView), Column, AIndex); 868 869 //set clickable 870 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); 871// do not set these here, it will be set by the lcl 872(* 873 // set title 874 gtk_tree_view_column_set_title(column, PChar(AColumn.Caption)); 875 //set width 876 gtk_tree_view_column_set_fixed_width(Column, AColumn.Width); 877 // set Visible 878 gtk_tree_view_column_set_visible(Column, AColumn.Visible); 879 // set MinWidth 880 if AColumn.MinWidth > 0 then 881 gtk_tree_view_column_set_min_width(Column, AColumn.MinWidth); 882 // set MaxWidth 883 if AColumn.MaxWidth > 0 then 884 gtk_tree_view_column_set_max_width(Column, AColumn.MaxWidth); 885 886 //set resizable 887 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN (column), True); 888 889*) 890end; 891 892class procedure TGtk2WSCustomListView.ColumnMove(const ALV: TCustomListView; 893 const AOldIndex, ANewIndex: Integer; const AColumn: TListColumn); 894var 895 Widgets: PTVWidgets; 896 Column: PGtkTreeViewColumn; 897 PrevColumn: PGtkTreeViewColumn; 898begin 899 if not WSCheckHandleAllocated(ALV, 'ColumnMove') then Exit; 900 901 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 902 if not GTK_IS_TREE_VIEW(Widgets^.MainView) then Exit; 903 904 Column := gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), AOldIndex); 905 if Column <> nil then 906 begin 907 if ANewIndex = 0 then 908 PrevColumn := nil 909 else 910 PrevColumn := gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), ANewIndex); 911 gtk_tree_view_move_column_after(PGtkTreeView(Widgets^.MainView), Column, PrevColumn); 912 end; 913end; 914 915class procedure TGtk2WSCustomListView.ColumnSetAlignment(const ALV: TCustomListView; 916 const AIndex: Integer; const AColumn: TListColumn; 917 const AAlignment: TAlignment); 918var 919 Widgets: PTVWidgets; 920 GtkColumn: PGtkTreeViewColumn; 921 Alignment: gfloat; 922 Value: TGValue; 923 renderers: PGList; 924 textrenderer: PGtkCellRenderer; 925begin 926 if not WSCheckHandleAllocated(ALV, 'ColumnSetAlignment') 927 then Exit; 928 929 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 930 931 if not GTK_IS_TREE_VIEW(Widgets^.MainView) then 932 Exit; 933 934 GtkColumn := gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), AIndex); 935 if GtkColumn <> nil then 936 begin 937 renderers := gtk_tree_view_column_get_cell_renderers(GtkColumn); 938 textrenderer := PGtkCellRenderer(g_list_last(renderers)^.data); 939 g_list_free(renderers); 940 941 Alignment := AlignToGtkAlign(AAlignment); 942 Value.g_type := G_TYPE_FLOAT; 943 Value.data[0].v_float:= Alignment; 944 g_object_set_property(G_OBJECT(textrenderer), PChar('xalign'), @Value); 945 946 {now we call set alignment because it calls update over visible rows in col} 947 gtk_tree_view_column_set_alignment(GtkColumn, Alignment); 948 end; 949end; 950 951class procedure TGtk2WSCustomListView.ColumnSetAutoSize(const ALV: TCustomListView; 952 const AIndex: Integer; const AColumn: TListColumn; const AAutoSize: Boolean); 953const 954 SizingMap: array[Boolean] of TGtkTreeViewColumnSizing = ( 955 GTK_TREE_VIEW_COLUMN_FIXED, 956 GTK_TREE_VIEW_COLUMN_AUTOSIZE 957 ); 958var 959 Widgets: PTVWidgets; 960 GtkColumn: PGtkTreeViewColumn; 961begin 962 if not WSCheckHandleAllocated(ALV, 'ColumnSetAutoSize') 963 then Exit; 964 965 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 966 967 if not GTK_IS_TREE_VIEW(Widgets^.MainView) then 968 Exit; 969 970 GtkColumn := gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), AIndex); 971 if GtkColumn <> nil then 972 begin 973 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(GtkColumn), True); 974 gtk_tree_view_column_set_sizing(GtkColumn, SizingMap[AAutoSize]); 975 end; 976end; 977 978class procedure TGtk2WSCustomListView.ColumnSetCaption(const ALV: TCustomListView; 979 const AIndex: Integer; const AColumn: TListColumn; const ACaption: String); 980var 981 Widgets: PTVWidgets; 982 GtkColumn: PGtkTreeViewColumn; 983begin 984 if not WSCheckHandleAllocated(ALV, 'ColumnSetCaption') 985 then Exit; 986 987 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 988 989 if not GTK_IS_TREE_VIEW(Widgets^.MainView) then 990 Exit; 991 992 GtkColumn := gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), AIndex); 993 if GtkColumn <> nil then 994 gtk_tree_view_column_set_title(GtkColumn, PChar(ACaption)); 995end; 996 997class procedure TGtk2WSCustomListView.ColumnSetImage(const ALV: TCustomListView; 998 const AIndex: Integer; const AColumn: TListColumn; const AImageIndex: Integer 999 ); 1000begin 1001 if not WSCheckHandleAllocated(ALV, 'ColumnSetImage') 1002 then Exit; 1003 1004 // ToDo: TGtk2WSCustomListView.ColumnSetImage 1005 //DebugLn('TODO: Gtk2. TGtk2WSCustomListView.ColumnSetImage'); 1006end; 1007 1008class procedure TGtk2WSCustomListView.ColumnSetMaxWidth(const ALV: TCustomListView; 1009 const AIndex: Integer; const AColumn: TListColumn; const AMaxWidth: Integer); 1010var 1011 Widgets: PTVWidgets; 1012 GtkColumn: PGtkTreeViewColumn; 1013begin 1014 if not WSCheckHandleAllocated(ALV, 'ColumnSetMaxWidth') 1015 then Exit; 1016 1017 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1018 if not GTK_IS_TREE_VIEW(Widgets^.MainView) then 1019 Exit; 1020 GtkColumn := gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), AIndex); 1021 if GtkColumn <> nil then 1022 gtk_tree_view_column_set_max_width(GtkColumn, AMaxWidth - Ord(AMaxWidth=0)); 1023end; 1024 1025class procedure TGtk2WSCustomListView.ColumnSetMinWidth(const ALV: TCustomListView; 1026 const AIndex: Integer; const AColumn: TListColumn; const AMinWidth: integer); 1027var 1028 Widgets: PTVWidgets; 1029 GtkColumn: PGtkTreeViewColumn; 1030begin 1031 if not WSCheckHandleAllocated(ALV, 'ColumnSetMinWidth') 1032 then Exit; 1033 1034 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1035 if not GTK_IS_TREE_VIEW(Widgets^.MainView) then 1036 Exit; 1037 GtkColumn := gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), AIndex); 1038 if GtkColumn <> nil then 1039 gtk_tree_view_column_set_min_width(GtkColumn, AMinWidth - Ord(AMinWidth=0)); 1040end; 1041 1042class procedure TGtk2WSCustomListView.ColumnSetWidth(const ALV: TCustomListView; const AIndex: Integer; const AColumn: TListColumn; const AWidth: Integer); 1043var 1044 Widgets: PTVWidgets; 1045 GtkColumn: PGtkTreeViewColumn; 1046begin 1047 if not WSCheckHandleAllocated(ALV, 'ColumnSetWidth') 1048 then Exit; 1049 1050 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1051 if not GTK_IS_TREE_VIEW(Widgets^.MainView) then 1052 Exit; 1053 GtkColumn := gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), AIndex); 1054 if GtkColumn <> nil then 1055 begin 1056 GtkColumn^.width := 0; 1057 gtk_tree_view_column_set_fixed_width(GtkColumn, AWidth + Ord(AWidth<1)); 1058 end; 1059end; 1060 1061class procedure TGtk2WSCustomListView.ColumnSetVisible(const ALV: TCustomListView; 1062 const AIndex: Integer; const AColumn: TListColumn; const AVisible: Boolean); 1063var 1064 Widgets: PTVWidgets; 1065 GtkColumn: PGtkTreeViewColumn; 1066begin 1067 if not WSCheckHandleAllocated(ALV, 'ColumnSetVisible') 1068 then Exit; 1069 1070 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1071 if not GTK_IS_TREE_VIEW(Widgets^.MainView) then 1072 Exit; 1073 with Widgets^ do 1074 begin 1075 GtkColumn := gtk_tree_view_get_column(PGtkTreeView(MainView), AIndex); 1076 if AVisible then 1077 g_object_set_data(G_OBJECT(GtkColumn), PChar('Visible'), gpointer(ptrint(1))) 1078 else 1079 g_object_set_data(G_OBJECT(GtkColumn), PChar('Visible'), gpointer(ptrint(0))); 1080 if TLVHack(ALV).ViewStyle = vsReport then begin 1081 gtk_tree_view_column_set_visible(GtkColumn, AVisible); 1082 end; 1083 end; 1084end; 1085 1086class procedure TGtk2WSCustomListView.ColumnSetSortIndicator( 1087 const ALV: TCustomListView; const AIndex: Integer; 1088 const AColumn: TListColumn; const ASortIndicator: TSortIndicator); 1089const 1090 GtkOrder : array [ TSortIndicator] of TGtkSortType = (0, GTK_SORT_ASCENDING, GTK_SORT_DESCENDING); 1091var 1092 Widgets: PTVWidgets; 1093 GtkColumn: PGtkTreeViewColumn; 1094begin 1095 if not WSCheckHandleAllocated(ALV, 'ColumnSetCaption') 1096 then Exit; 1097 1098 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1099 1100 if not GTK_IS_TREE_VIEW(Widgets^.MainView) then 1101 Exit; 1102 1103 GtkColumn := gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), AIndex); 1104 if GtkColumn <> nil then 1105 begin 1106 if ASortIndicator = siNone then 1107 gtk_tree_view_column_set_sort_indicator(GtkColumn, false) 1108 else 1109 begin 1110 gtk_tree_view_column_set_sort_indicator(GtkColumn, true); 1111 gtk_tree_view_column_set_sort_order(GtkColumn, GtkOrder[ASortIndicator]); 1112 end; 1113 end; 1114end; 1115 1116class procedure TGtk2WSCustomListView.ItemDelete(const ALV: TCustomListView; 1117 const AIndex: Integer); 1118var 1119 Widgets: PTVWidgets; 1120 {$IFDEF USEORIGTREEMODEL} 1121 Iter: TGtkTreeIter; 1122 {$ENDIF} 1123begin 1124 if not WSCheckHandleAllocated(ALV, 'ItemDelete') 1125 then Exit; 1126 1127 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1128 1129 with Widgets^ do begin 1130 {$IFDEF USEORIGTREEMODEL} 1131 if gtk_tree_model_iter_nth_child(TreeModel, @Iter, nil, AIndex) then 1132 begin 1133 gtk_list_store_remove(TreeModel, @Iter); 1134 end; 1135 {$ELSE} 1136 PLCLListViewModel(TreeModel)^.NotifyRowDeleted(AIndex); 1137 {$ENDIF} 1138 end; 1139end; 1140 1141class function TGtk2WSCustomListView.ItemDisplayRect(const ALV: TCustomListView; const AIndex, ASubItem: Integer; 1142 ACode: TDisplayCode): TRect; 1143var 1144 Widgets: PTVWidgets; 1145 ItemRect, IconRect: TGdkRectangle; 1146 Column: PGtkTreeViewColumn; 1147 Path: PGtkTreePath; 1148 X, Y, L, T, W, H: GInt; 1149 ARect: TGdkRectangle; 1150 R: TRect; 1151 ANewCell: PGtkCellRenderer; 1152 ANewPath: PGtkTreePath; 1153 APGList: PGList; 1154 pixrenderer: PGtkCellRenderer; 1155 AWidth: gint; 1156 AHeight: gint; 1157begin 1158 Result := Rect(0, 0, 0, 0); 1159 if not WSCheckHandleAllocated(ALV, 'ItemDisplayRect') then 1160 Exit; 1161 1162 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1163 with Widgets^ do 1164 begin 1165 if gtk_widget_realized(MainView) = False then 1166 exit; 1167 Path := gtk_tree_path_new_from_indices(AIndex, -1); 1168 try 1169 if GTK_IS_TREE_VIEW(MainView) then 1170 begin 1171 Column := gtk_tree_view_get_column(PGtkTreeView(MainView), ASubItem); 1172 gtk_tree_view_get_cell_area(PGtkTreeView(MainView), Path, Column, @ItemRect); 1173 if gtk_tree_view_get_headers_visible(PGtkTreeView(MainView)) then 1174 begin 1175 gtk_tree_view_column_cell_get_size(gtk_tree_view_get_column(PGtkTreeView(MainView), 0), 1176 @ARect, @L, @T, @W, @H); 1177 inc(ItemRect.y, H); 1178 end; 1179 1180 if (ACode in [drIcon, drLabel]) and not TLVHack(ALV).OwnerDraw then 1181 begin 1182 IconRect := ItemRect; 1183 APGList := gtk_tree_view_column_get_cell_renderers(gtk_tree_view_get_column(PGtkTreeView(MainView), 0)); 1184 pixrenderer := PGtkCellRenderer(g_list_last(APGList)^.prev^.data); 1185 gtk_cell_renderer_get_fixed_size(pixrenderer, @AWidth, @AHeight); 1186 if AWidth > 0 then 1187 IconRect.Width := AWidth - 2; 1188 if AHeight > 0 then 1189 IconRect.Height := AHeight - 2; 1190 g_list_free(APGList); 1191 if ACode = drIcon then 1192 ItemRect := IconRect 1193 else 1194 begin 1195 ItemRect.x += AWidth + 2; 1196 ItemRect.y += 2; // offset 1197 ItemRect.Width -= AWidth + 2; 1198 ItemRect.Height -= 2; // offset 1199 end; 1200 end; 1201 1202 end 1203 else 1204 if GTK_IS_ICON_VIEW(MainView) then 1205 begin 1206 ItemRect.x := 0; 1207 ItemRect.y := 0; 1208 ItemRect.width := gtk_icon_view_get_item_width(PGtkIconView(MainView)); 1209 ItemRect.height := 0; 1210 if Path <> nil then 1211 begin 1212 ANewPath := nil; 1213 ANewCell := nil; 1214 R := ALV.ClientRect; 1215 l := 0; 1216 t := 0; 1217 Result := Rect(0, 0, 0, 0); 1218 while t < R.Bottom - 1 do 1219 begin 1220 l := 0; 1221 while l < R.Right - 1 do 1222 begin 1223 if gtk_icon_view_get_item_at_pos(PGtkIconView(MainView), l, t, ANewPath, ANewCell) then 1224 begin 1225 if (ANewPath <> nil) and (gtk_tree_path_compare(Path, ANewPath) = 0) then 1226 begin 1227 gtk_cell_renderer_get_size(ANewCell, PGtkWidget(MainView), @ItemRect, @x,@y,@w,@h); 1228 Result := Rect(l, t, w + l, h + t); 1229 ItemRect := GdkRectFromRect(Result); 1230 if ANewPath <> nil then 1231 gtk_tree_path_free(ANewPath); 1232 break; 1233 end; 1234 if ANewPath <> nil then 1235 gtk_tree_path_free(ANewPath); 1236 end; 1237 inc(l, 1); 1238 end; 1239 1240 inc(t, 1); 1241 1242 if not IsRectEmpty(Result) then 1243 break; 1244 end; 1245 end; 1246 end; 1247 finally 1248 gtk_tree_path_free(Path); 1249 end; 1250 Result := RectFromGdkRect(ItemRect); 1251 end; 1252end; 1253 1254class procedure TGtk2WSCustomListView.ItemExchange(const ALV: TCustomListView; 1255 AItem: TListItem; const AIndex1, AIndex2: Integer); 1256var 1257 Widgets: PTVWidgets; 1258 Path: PGtkTreePath; 1259 ItemRect: TGdkRectangle; 1260begin 1261 if not WSCheckHandleAllocated(ALV, 'ItemExchange') then 1262 exit; 1263 // gtk2 needs only update 1264 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1265 if GetViewModel(Widgets^.MainView) = nil then 1266 exit; 1267 1268 if not gtk_widget_realized(Widgets^.MainView) then 1269 exit; 1270 1271 if GTK_IS_TREE_VIEW(Widgets^.MainView) then 1272 begin 1273 Path := gtk_tree_path_new_from_indices(AIndex1, -1); 1274 gtk_tree_view_get_cell_area(PGtkTreeView(Widgets^.MainView), Path, nil, @ItemRect); 1275 gtk_tree_path_free(Path); 1276 if ItemRect.height = 0 then 1277 begin 1278 Path := gtk_tree_path_new_from_indices(AIndex2, -1); 1279 gtk_tree_view_get_cell_area(PGtkTreeView(Widgets^.MainView), Path, nil, @ItemRect); 1280 gtk_tree_path_free(Path); 1281 end; 1282 end else 1283 ItemRect.height := 1; // force redraw 1284 1285 if ItemRect.height <> 0 then // item is visible 1286 gtk_widget_queue_draw(Widgets^.MainView); 1287end; 1288 1289class procedure TGtk2WSCustomListView.ItemMove(const ALV: TCustomListView; 1290 AItem: TListItem; const AFromIndex, AToIndex: Integer); 1291var 1292 Widgets: PTVWidgets; 1293 Path: PGtkTreePath; 1294 ItemRect: TGdkRectangle; 1295begin 1296 if not WSCheckHandleAllocated(ALV, 'ItemMove') then 1297 exit; 1298 // gtk2 needs only update 1299 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1300 if GetViewModel(Widgets^.MainView) = nil then 1301 exit; 1302 1303 if not gtk_widget_realized(Widgets^.MainView) then 1304 exit; 1305 1306 if GTK_IS_TREE_VIEW(Widgets^.MainView) then 1307 begin 1308 Path := gtk_tree_path_new_from_indices(AFromIndex, -1); 1309 gtk_tree_view_get_cell_area(PGtkTreeView(Widgets^.MainView), Path, nil, @ItemRect); 1310 gtk_tree_path_free(Path); 1311 if ItemRect.height = 0 then 1312 begin 1313 Path := gtk_tree_path_new_from_indices(AToIndex, -1); 1314 gtk_tree_view_get_cell_area(PGtkTreeView(Widgets^.MainView), Path, nil, @ItemRect); 1315 gtk_tree_path_free(Path); 1316 end; 1317 end else 1318 ItemRect.height := 1; // force redraw 1319 1320 if ItemRect.height <> 0 then // item is visible 1321 gtk_widget_queue_draw(Widgets^.MainView); 1322end; 1323 1324class function TGtk2WSCustomListView.ItemGetChecked(const ALV: TCustomListView; 1325 const AIndex: Integer; const AItem: TListItem): Boolean; 1326begin 1327 Result := TLVItemHack(AItem).GetCheckedInternal; 1328end; 1329 1330class function TGtk2WSCustomListView.ItemGetState(const ALV: TCustomListView; 1331 const AIndex: Integer; const AItem: TListItem; const AState: TListItemState; 1332 out AIsSet: Boolean): Boolean; 1333var 1334 Widgets: PTVWidgets; 1335 Path: PGtkTreePath; 1336 pstr: PChar; 1337 Column: PGtkTreeViewColumn; 1338 Cell: PGtkCellRenderer; 1339begin 1340 Result := False; 1341 1342 if not WSCheckHandleAllocated(ALV, 'ItemGetState') 1343 then Exit; 1344 1345 AIsSet := False; 1346 1347 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1348 1349 with Widgets^ do 1350 begin 1351 if GetViewModel(MainView) = nil then 1352 Exit; // we are in the midst of a begin update end update pair and the following will fail and cause gtk debug messages 1353 case AState of 1354 lisCut, 1355 lisDropTarget: 1356 begin 1357 //TODO: do something with the rowcolor ? 1358 end; 1359 1360 lisFocused: 1361 begin 1362 if GTK_IS_TREE_VIEW(MainView) then begin 1363 Path:=nil; 1364 Column:=nil; 1365 gtk_tree_view_get_cursor(PGtkTreeView(MainView), Path, Column) 1366 end 1367 else 1368 if GTK_IS_ICON_VIEW(MainView) then 1369 gtk_icon_view_get_cursor(PGtkIconView(MainView), Path, Cell{%H-}) 1370 else 1371 Path := nil; 1372 if (Path<>nil) then 1373 begin 1374 pstr := gtk_tree_path_to_string(path); 1375 AIsSet:=(StrToInt(pstr) = AIndex); 1376 g_free(pstr); 1377 end else 1378 AIsSet:=false; 1379 1380 gtk_tree_path_free(Path); 1381 Result := True; 1382 end; 1383 1384 lisSelected: 1385 begin 1386 Path := gtk_tree_path_new_from_string(PChar(IntToStr(AIndex))); 1387 if GTK_IS_TREE_VIEW(MainView) then 1388 AIsSet := gtk_tree_selection_path_is_selected(TreeSelection, Path) 1389 else 1390 if GTK_IS_ICON_VIEW(MainView) then 1391 AIsSet := gtk_icon_view_path_is_selected(PGtkIconView(MainView), Path) 1392 else 1393 AIsSet := False; 1394 gtk_tree_path_free(Path); 1395 Result := True; 1396 end; 1397 end; 1398 end; 1399end; 1400 1401class procedure TGtk2WSCustomListView.ItemInsert(const ALV: TCustomListView; 1402 const AIndex: Integer; const AItem: TListItem); 1403var 1404 Widgets: PTVWidgets; 1405 {$IFDEF USEORIGTREEMODEL} 1406 Iter: TGtkTreeIter; 1407 Index: Integer; 1408 {$ENDIF} 1409begin 1410 if not WSCheckHandleAllocated(ALV, 'ItemInsert') 1411 then Exit; 1412 1413 1414 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1415 1416 with Widgets^ do 1417 begin 1418 {$IFDEF USEORIGTREEMODEL} 1419 if AIndex = -1 then 1420 Index := gtk_tree_model_iter_n_children(TreeModel, nil) 1421 else 1422 Index := AIndex; 1423 gtk_list_store_insert_with_values(PGtkListStore(TreeModel), @Iter, Index, 0, Pointer(AItem), -1); 1424 {$ELSE} 1425 if not (lisfWSItemsCreated in ALV.Items.Flags) then 1426 Exit; 1427 1428 PLCLListViewModel(TreeModel)^.NotifyRowInserted(AIndex); 1429 {$ENDIF} 1430 end; 1431end; 1432 1433class procedure TGtk2WSCustomListView.ItemSetChecked( 1434 const ALV: TCustomListView; const AIndex: Integer; const AItem: TListItem; 1435 const AChecked: Boolean); 1436begin 1437 if not WSCheckHandleAllocated(ALV, 'ItemSetChecked') 1438 then Exit; 1439 // nothing needed here 1440end; 1441 1442class procedure TGtk2WSCustomListView.ItemSetImage(const ALV: TCustomListView; 1443 const AIndex: Integer; const AItem: TListItem; const ASubIndex, 1444 AImageIndex: Integer); 1445var 1446 Widgets: PTVWidgets; 1447 Path: PGtkTreePath; 1448 ItemRect: TGdkRectangle; 1449 BitImage: TBitmap; 1450 pixbuf: PGDKPixBuf; 1451 i, ImgListWidth: Integer; 1452 ImgList: TCustomImageList; 1453 ImgListRes: TCustomImageListResolution; 1454 1455begin 1456 if not WSCheckHandleAllocated(ALV, 'ItemSetImage') 1457 then Exit; 1458 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1459 with Widgets^ do 1460 begin 1461 if not gtk_widget_realized(MainView) then 1462 begin 1463 // DebugLn('WARNING: TGtk2WSCustomListView.ItemSetImage: MainView is not realized.'); 1464 Exit; 1465 end; 1466 Path := gtk_tree_path_new_from_indices(AIndex, -1); 1467 if GTK_IS_TREE_VIEW(MainView) then 1468 gtk_tree_view_get_cell_area(PGtkTreeView(MainView), Path, nil, @ItemRect) 1469 else 1470 ItemRect.height := 1; // force redraw 1471 gtk_tree_path_free(Path); 1472 if ItemRect.height <> 0 then // item is visible 1473 begin 1474 if (TListView(ALV).ViewStyle in [vsSmallIcon, vsReport, vsList]) then 1475 begin 1476 ImgList := TListView(ALV).SmallImages; 1477 ImgListWidth := TListView(ALV).SmallImagesWidth; 1478 end 1479 else 1480 if (TListView(ALV).ViewStyle = vsIcon) then 1481 begin 1482 ImgList := TListView(ALV).LargeImages; 1483 ImgListWidth := TListView(ALV).LargeImagesWidth; 1484 end; 1485 1486 if Assigned(ImgList) and (ImgList.Count > 0) and (AImageIndex >= 0) then 1487 begin 1488 ImgListRes := ImgList.ResolutionForPPI[ImgListWidth, ALV.Font.PixelsPerInch, ALV.GetCanvasScaleFactor].Resolution; 1489 if (ImgList.Count <> Widgets^.Images.Count) then 1490 begin 1491 if (TListView(ALV).ViewStyle in [vsSmallIcon, vsReport, vsList]) then 1492 SetImageList(ALV, lvilSmall, ImgListRes) 1493 else 1494 SetImageList(ALV, lvilLarge, ImgListRes); 1495 exit; 1496 end; 1497 1498 if (Widgets^.Images <> nil) then 1499 begin 1500 for i := 0 to Widgets^.Images.Count-1 do 1501 if i = AImageIndex then 1502 gdk_pixbuf_unref(PGdkPixBuf(Widgets^.Images.Items[i])); 1503 1504 pixbuf := nil; 1505 BitImage := TBitmap.Create; 1506 try 1507 ImgListRes.GetBitmap(AImageIndex, BitImage); 1508 Gtk2_PixBufFromBitmap(BitImage,pixbuf); 1509 Widgets^.Images.Items[AImageIndex] := pixbuf; 1510 if GTK_IS_TREE_VIEW(MainView) then 1511 gtk_tree_view_column_queue_resize(gtk_tree_view_get_column(PGtkTreeView(MainView), ASubIndex)); 1512 finally 1513 BitImage.Free; 1514 end; 1515 end; 1516 end; 1517 gtk_widget_queue_draw(MainView); 1518 end; 1519 end; 1520end; 1521 1522class procedure TGtk2WSCustomListView.ItemSetState(const ALV: TCustomListView; 1523 const AIndex: Integer; const AItem: TListItem; const AState: TListItemState; 1524 const AIsSet: Boolean); 1525var 1526 Widgets: PTVWidgets; 1527 Path: PGtkTreePath; 1528 BroadcastMsg: Boolean; 1529begin 1530 if not WSCheckHandleAllocated(ALV, 'ItemSetState') 1531 then Exit; 1532 1533 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1534 // wwiInvalidEvent flag save us from infinite loop ! 1535 // when this flag is included TreeSelection 'changed' won't 1536 // trigger - and it shouldn't LCL setted up selection. 1537 // fixes #16399 1538 Include(Widgets^.WidgetInfo^.Flags, wwiInvalidEvent); 1539 try 1540 BroadcastMsg := False; 1541 with Widgets^ do 1542 begin 1543 if GetViewModel(MainView) = nil then 1544 Exit; // we are in the midst of a begin update end update pair and the following will fail and cause gtk debug messages 1545 case AState of 1546 lisCut, 1547 lisDropTarget: 1548 begin 1549 //TODO: do something with the rowcolor ? 1550 end; 1551 1552 lisFocused: 1553 begin 1554 //gtk2 iter has no focus?? 1555 Path := gtk_tree_path_new_from_string(PChar(IntToStr(AIndex))); 1556 if GTK_IS_TREE_VIEW(MainView) then 1557 gtk_tree_view_set_cursor(PGtkTreeView(MainView), Path, nil, False) 1558 else 1559 if GTK_IS_ICON_VIEW(MainView) then 1560 gtk_icon_view_set_cursor(PGtkIconView(MainView), Path, nil, False); 1561 gtk_tree_path_free(Path); 1562 end; 1563 1564 lisSelected: 1565 begin 1566 Path := gtk_tree_path_new_from_string(PChar(IntToStr(AIndex))); 1567 if GTK_IS_TREE_VIEW(MainView) then 1568 begin 1569 if AIsSet and not gtk_tree_selection_path_is_selected(TreeSelection, Path) then 1570 begin 1571 gtk_tree_selection_select_path(TreeSelection, Path); 1572 BroadcastMsg := True; 1573 end else 1574 if not AIsSet and gtk_tree_selection_path_is_selected(TreeSelection, Path) then 1575 begin 1576 gtk_tree_selection_unselect_path(TreeSelection, Path); 1577 BroadcastMsg := True; 1578 end; 1579 end 1580 else 1581 if GTK_IS_ICON_VIEW(MainView) then 1582 begin 1583 if AIsSet and not gtk_icon_view_path_is_selected(PGtkIconView(MainView), Path) then 1584 begin 1585 gtk_icon_view_select_path(PGtkIconView(MainView), Path); 1586 BroadCastMsg := True; 1587 end else 1588 if not AIsSet and gtk_icon_view_path_is_selected(PGtkIconView(MainView), Path) then 1589 begin 1590 gtk_icon_view_unselect_path(PGtkIconView(MainView), Path); 1591 BroadCastMsg := True; 1592 end; 1593 end; 1594 gtk_tree_path_free(Path); 1595 if BroadcastMsg then 1596 BroadCastListSelection(ALV, {%H-}PtrUInt(MainView), AIndex, not AIsSet); 1597 end; 1598 end; 1599 end; 1600 finally 1601 Exclude(Widgets^.WidgetInfo^.Flags, wwiInvalidEvent); 1602 end; 1603end; 1604 1605class procedure TGtk2WSCustomListView.ItemSetText(const ALV: TCustomListView; 1606 const AIndex: Integer; const AItem: TListItem; const ASubIndex: Integer; 1607 const AText: String); 1608var 1609 Widgets: PTVWidgets; 1610 Path: PGtkTreePath; 1611 ItemRect: TGdkRectangle; 1612begin 1613 // ToDo: TGtk2WSCustomListView.ItemSetText: this function queues a draw. Is this correct? 1614 1615 if not WSCheckHandleAllocated(ALV, 'ItemSetText') 1616 then Exit; 1617 1618 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1619 with Widgets^ do 1620 begin 1621 if not gtk_widget_realized(MainView) then 1622 Exit; 1623 1624 if GTK_IS_TREE_VIEW(MainView) then 1625 begin 1626 Path := gtk_tree_path_new_from_indices(AIndex, -1); 1627 gtk_tree_view_get_cell_area(PGtkTreeView(MainView), Path, nil, @ItemRect); 1628 gtk_tree_path_free(Path); 1629 end 1630 else 1631 ItemRect.height := 1; // force redraw 1632 1633 if ItemRect.height <> 0 then // item is visible 1634 gtk_widget_queue_draw(MainView); 1635 end; 1636end; 1637 1638class procedure TGtk2WSCustomListView.ItemShow(const ALV: TCustomListView; 1639 const AIndex: Integer; const AItem: TListItem; const PartialOK: Boolean); 1640var 1641 Widgets: PTVWidgets; 1642 Path: PGtkTreePath; 1643begin 1644 if not WSCheckHandleAllocated(ALV, 'ItemShow') 1645 then Exit; 1646 1647 // TODO: TGtk2WSCustomListView.ItemShow check for partial visiblity. currently scrolls to the Item to make it fully visible 1648 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1649 1650 with Widgets^ do 1651 begin 1652 Path := gtk_tree_path_new_from_indices(AIndex, -1); 1653 if GTK_IS_TREE_VIEW(MainView) then 1654 gtk_tree_view_scroll_to_cell(PGtkTreeView(MainView), Path, nil, False, 0, 0) 1655 else 1656 if GTK_IS_ICON_VIEW(MainView) then 1657 gtk_icon_view_scroll_to_path(PGtkIconView(MainView), Path, False, 0, 0); 1658 gtk_tree_path_free(Path); 1659 end; 1660end; 1661 1662class function TGtk2WSCustomListView.ItemGetPosition(const ALV: TCustomListView; const AIndex: Integer): TPoint; 1663var 1664 Widgets: PTVWidgets; 1665 Path: PGtkTreePath; 1666 ARect: TGdkRectangle; 1667 Column: PGtkTreeViewColumn; 1668begin 1669 if not WSCheckHandleAllocated(ALV, 'ItemGetPosition') 1670 then Exit; 1671 1672 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1673 1674 Path := gtk_tree_path_new_from_indices(AIndex, -1); 1675 with Widgets^ do 1676 begin 1677 if GTK_IS_TREE_VIEW(MainView) then 1678 begin 1679 Column := gtk_tree_view_get_column(PGtkTreeView(MainView), 0); 1680 gtk_tree_view_get_cell_area(PGtkTreeView(MainView), Path, Column, @ARect); 1681 Result.X := ARect.x; 1682 Result.Y := Arect.y; 1683 end 1684 else 1685 if GTK_IS_ICON_VIEW(MainView) then 1686 begin 1687 // todo: gtk gives no way to get item rectangle, while internally it uses it 1688 Result.X := 0; 1689 Result.Y := 0; 1690 end; 1691 end; 1692 gtk_tree_path_free(Path); 1693end; 1694 1695class procedure TGtk2WSCustomListView.ItemUpdate(const ALV: TCustomListView; 1696 const AIndex: Integer; const AItem: TListItem); 1697{$IFDEF USEORIGTREEMODEL} 1698var 1699 Widgets: PTVWidgets; 1700 Iter: TGtkTreeIter; 1701 {$ENDIF} 1702begin 1703 if not WSCheckHandleAllocated(ALV, 'ItemUpdate') 1704 then Exit; 1705 {$IFDEF USEORIGTREEMODEL} 1706 GetCommonTreeViewWidgets(PGtkWidget(ALV.Handle), Widgets); 1707 1708 with Widgets^ do 1709 if gtk_tree_model_iter_nth_child(TreeModel, @Iter, nil, AIndex) then 1710 gtk_list_store_set(PGtkListStore(TreeModel), @Iter, [0, Pointer(AItem), -1]); 1711 {$ENDIF} 1712end; 1713 1714class function TGtk2WSCustomListView.CreateHandle(const AWinControl: TWinControl; 1715 const AParams: TCreateParams): HWND; 1716var 1717 Widgets: PTVWidgets; 1718 OrigScrollingData: PBaseScrollingWinControlData; 1719 //ListViewData: PCustomListViewData; 1720 //Allocation: TGTKAllocation; 1721 ScrollWidget: PGtkScrolledWindow; 1722 {$IFDEF USEORIGTREEMODEL} 1723 PtrType: GType; 1724 {$ENDIF} 1725 SS: TPoint; 1726begin 1727 Result := TGtk2WSBaseScrollingWinControl.CreateHandle(AWinControl, AParams); 1728 if Result = 0 then Exit; 1729 1730 ScrollWidget := {%H-}PGtkScrolledWindow(Result); 1731 1732 gtk_widget_unset_flags(ScrollWidget^.hscrollbar, GTK_CAN_FOCUS); 1733 gtk_widget_unset_flags(ScrollWidget^.vscrollbar, GTK_CAN_FOCUS); 1734 1735 SS := Gtk2TranslateScrollStyle(TListView(AWinControl).ScrollBars); 1736 gtk_scrolled_window_set_policy(ScrollWidget,SS.X, SS.Y); 1737 1738 gtk_scrolled_window_set_shadow_type(ScrollWidget, 1739 BorderStyleShadowMap[TCustomListView(AWinControl).BorderStyle]); 1740 1741 gtk_widget_show(PGtkWidget(ScrollWidget)); 1742 1743 Widgets := nil; 1744 1745 New(Widgets); 1746 with Widgets^ do 1747 begin 1748 ItemCache := TStringList.Create; 1749 Images := nil; 1750 OldTreeSelection := nil; 1751 1752 {$IFDEF USEORIGTREEMODEL} 1753 PtrType := G_TYPE_POINTER; 1754 TreeModel := gtk_list_store_newv(1, @PtrType); 1755 {$ELSE} 1756 TreeModel:= LCLListViewModelNew(TCustomListView(AWinControl)); 1757 {$ENDIF} 1758 1759 if TLVHack(AWinControl).ViewStyle in [vsIcon,vsSmallIcon] then 1760 begin 1761 MainView := gtk_icon_view_new_with_model(TreeModel); 1762 TreeSelection := nil; 1763 if TLVHack(AWinControl).IconOptions.Arrangement = iaTop then 1764 gtk_icon_view_set_columns(PGtkIconView(MainView), -1) 1765 else 1766 gtk_icon_view_set_columns(PGtkIconView(MainView), 1); 1767 end 1768 else 1769 begin 1770 if IsOldGtk2 then 1771 OldTreeSelection := g_list_alloc; 1772 MainView := gtk_tree_view_new_with_model(TreeModel); 1773 TreeSelection := PGtkTreeSelection(gtk_tree_view_get_selection(PGtkTreeView(MainView))); 1774 end; 1775 g_object_unref(G_OBJECT(TreeModel)); 1776 1777 // we added +1 because Ord(vsIcon) returns 0, so it's nil ptr 1778 g_object_set_data(PGObject(MainView),'lcllistviewstyle', {%H-}gpointer(PtrInt(Ord(TLVHack(AWinControl).ViewStyle) + 1))); 1779 1780 gtk_container_add(GTK_CONTAINER(ScrollWidget),PGtkWidget(MainView)); 1781 1782 // create widget info 1783 // already created in TGtkWSBaseScrollingWinControl 1784 // Replace the ScrollingInfo with our info 1785 WidgetInfo := GetWidgetInfo(ScrollWidget); 1786 OrigScrollingData := WidgetInfo^.UserData; 1787 Widgets^.ScrollingData := OrigScrollingData^; 1788 1789 WidgetInfo^.UserData := Widgets; 1790 1791 Dispose(OrigScrollingData); 1792 WidgetInfo^.CoreWidget := PGtkWidget(MainView); 1793 g_object_set_data(Pointer(MainView), 'widgetinfo', WidgetInfo); 1794 gtk_widget_show_all(PGtkWidget(MainView)); 1795 if not AWinControl.HandleObjectShouldBeVisible and not (csDesigning in AWinControl.ComponentState) then 1796 gtk_widget_hide(PGtkWidget(ScrollWidget)); 1797 SetListCallbacks(PGtkWidget(ScrollWidget), Widgets, Widgets^.WidgetInfo); 1798 end; 1799end; 1800 1801class procedure TGtk2WSCustomListView.DestroyHandle(const AWinControl: TWinControl); 1802var 1803 Widgets: PTVWidgets; 1804 i: Integer; 1805begin 1806 GetCommonTreeViewWidgets({%H-}PGtkWidget(AWinControl.Handle), Widgets); 1807 // on widget destroy we have no ItemDeleted notification and we must destroy ItemCache ourself 1808 // if things will change please remove this destroy 1809 if Widgets^.ItemCache <> nil then 1810 Widgets^.ItemCache.Free; 1811 Widgets^.ItemCache := nil; 1812 if Widgets^.OldTreeSelection <> nil then 1813 begin 1814 g_list_free(Widgets^.OldTreeSelection); 1815 Widgets^.OldTreeSelection := nil; 1816 end; 1817 if Widgets^.Images <> nil then 1818 begin 1819 for i := 0 to Widgets^.Images.Count-1 do 1820 if Widgets^.Images.Items[i] <> nil then 1821 gdk_pixbuf_unref(PGDKPixBuf(Widgets^.Images.Items[i])); 1822 FreeAndNil(Widgets^.Images); 1823 end; 1824 TWSWinControlClass(ClassParent).DestroyHandle(AWinControl); 1825end; 1826 1827class procedure TGtk2WSCustomListView.BeginUpdate(const ALV: TCustomListView); 1828begin 1829 if not WSCheckHandleAllocated(ALV, 'BeginUpdate') then 1830 exit; 1831 g_object_set_data({%H-}PGObject(ALV.Handle),'lcl_gtkwidget_in_update', ALV); 1832end; 1833 1834class procedure TGtk2WSCustomListView.EndUpdate(const ALV: TCustomListView); 1835begin 1836 if not WSCheckHandleAllocated(ALV, 'EndUpdate') then 1837 exit; 1838 g_object_set_data({%H-}PGObject(ALV.Handle),'lcl_gtkwidget_in_update', nil); 1839end; 1840 1841class function TGtk2WSCustomListView.GetBoundingRect(const ALV: TCustomListView): TRect; 1842begin 1843 Result:=Rect(0,0,0,0); 1844 1845 if not WSCheckHandleAllocated(ALV, 'GetBoundingRect') 1846 then Exit; 1847 1848 //DebugLn('TODO: TGtk2WSCustomListView.GetBoundingRect'); 1849end; 1850 1851class function TGtk2WSCustomListView.GetDropTarget(const ALV: TCustomListView): Integer; 1852var 1853 Widgets: PTVWidgets; 1854begin 1855 // TODO: implement 1856 Result := -1; 1857 1858 if not WSCheckHandleAllocated(ALV, 'GetDropTarget') 1859 then Exit; 1860 1861 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1862end; 1863 1864class function TGtk2WSCustomListView.GetFocused(const ALV: TCustomListView): Integer; 1865var 1866 Widgets: PTVWidgets; 1867 Path: PGtkTreePath; 1868 Column: PGtkTreeViewColumn; 1869 Cell: PGtkCellRenderer; 1870begin 1871 Result := -1; 1872 1873 if not WSCheckHandleAllocated(ALV, 'GetFocused') 1874 then Exit; 1875 1876 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1877 1878 with Widgets^ do 1879 begin 1880 if GTK_IS_TREE_VIEW(MainView) then begin 1881 Path:=nil; 1882 Column:=nil; 1883 gtk_tree_view_get_cursor(PGtkTreeView(MainView), Path, Column); 1884 end 1885 else begin 1886 if GTK_IS_ICON_VIEW(MainView) then begin 1887 Cell:=nil; 1888 gtk_icon_view_get_cursor(PGtkIconView(MainView), Path, Cell); 1889 end 1890 else 1891 Path := nil; 1892 end; 1893 if Path <> nil then 1894 begin 1895 Result := StrToInt(PChar(Path)); 1896 gtk_tree_path_free(Path); 1897 end; 1898 end; 1899end; 1900 1901class function TGtk2WSCustomListView.GetHoverTime(const ALV: TCustomListView): Integer; 1902var 1903 Widgets: PTVWidgets; 1904begin 1905 // TODO: implement 1906 Result := -1; // = default 1907 1908 if not WSCheckHandleAllocated(ALV, 'GetHoverTime') 1909 then Exit; 1910 1911 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1912 with Widgets^ do 1913 begin 1914 1915 end; 1916end; 1917 1918class function TGtk2WSCustomListView.GetItemAt(const ALV: TCustomListView; x, y: integer): Integer; 1919var 1920 Widgets: PTVWidgets; 1921 ItemPath: PGtkTreePath; 1922 Column: PGtkTreeViewColumn; 1923 cx, cy: gint; 1924begin 1925 Result := -1; 1926 if not WSCheckHandleAllocated(ALV, 'GetItemAt') 1927 then Exit; 1928 1929 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1930 1931 if GTK_IS_TREE_VIEW(Widgets^.MainView) then 1932 begin 1933 // gtk2 >= 2.19 changed treeview api 1934 if gtk_minor_version >= 19 then 1935 begin 1936 gdk_window_get_position(gtk_tree_view_get_bin_window(PGtkTreeView(Widgets^.MainView)), @cx, @cy); 1937 Dec(x, cx); 1938 Dec(y, cy); 1939 end else 1940 begin 1941 // convert X, Y to bin window coords 1942 x := x + Round(PGtkTreeView(Widgets^.MainView)^.priv^.hadjustment^.value); 1943 if GTK_TREE_VIEW_FLAG_SET(PGtkTreeView(Widgets^.MainView), GTK_TREE_VIEW_HEADERS_VISIBLE) then 1944 begin 1945 gdk_window_get_size(PGtkTreeView(Widgets^.MainView)^.priv^.header_window, @cx, @cy); 1946 y := y - cy; 1947 end; 1948 end; 1949 ItemPath:=nil; 1950 Column:=nil; 1951 if gtk_tree_view_get_path_at_pos(PGtkTreeView(Widgets^.MainView), x, y, ItemPath, Column, nil, nil) then 1952 begin 1953 if ItemPath <> nil then 1954 begin 1955 Result := gtk_tree_path_get_indices(ItemPath)^; 1956 gtk_tree_path_free(ItemPath); 1957 end; 1958 end; 1959 end 1960 else 1961 if GTK_IS_ICON_VIEW(Widgets^.MainView) then 1962 begin 1963 ItemPath := gtk_icon_view_get_path_at_pos(PGtkIconView(Widgets^.MainView), 1964 x + Widgets^.ScrollingData.HValue, y + Widgets^.ScrollingData.VValue); 1965 if ItemPath <> nil then 1966 begin 1967 Result := gtk_tree_path_get_indices(ItemPath)^; 1968 gtk_tree_path_free(ItemPath); 1969 end; 1970 end; 1971end; 1972 1973class function TGtk2WSCustomListView.GetSelCount(const ALV: TCustomListView): Integer; 1974var 1975 Widgets: PTVWidgets; 1976 AList: PGList; 1977begin 1978 Result := 0; 1979 1980 if not WSCheckHandleAllocated(ALV, 'GetSelCount') 1981 then Exit; 1982 1983 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 1984 with Widgets^ do 1985 begin 1986 if GTK_IS_TREE_VIEW(MainView) then 1987 AList := gtk_tree_selection_get_selected_rows(TreeSelection, nil) 1988 else 1989 if GTK_IS_ICON_VIEW(MainView) then 1990 AList := gtk_icon_view_get_selected_items(PGtkIconView(MainView)) 1991 else 1992 Exit; 1993 if AList <> nil then 1994 begin 1995 Result := g_list_length(AList); 1996 g_list_free(AList); 1997 end; 1998 end; 1999end; 2000 2001class function TGtk2WSCustomListView.GetSelection(const ALV: TCustomListView): Integer; 2002var 2003 Widgets: PTVWidgets; 2004 Iter: TGtkTreeIter; 2005 Path: PGtkTreePath; 2006 AList: PGList; 2007begin 2008 Result := -1; 2009 2010 if not WSCheckHandleAllocated(ALV, 'GetSelection') 2011 then Exit; 2012 2013 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 2014 2015 with Widgets^ do 2016 begin 2017 if GTK_IS_TREE_VIEW(MainView) then 2018 gtk_tree_selection_get_selected(TreeSelection, nil, @Iter) 2019 else 2020 if GTK_IS_ICON_VIEW(MainView) then 2021 begin 2022 AList := gtk_icon_view_get_selected_items(PGtkIconView(MainView)); 2023 if AList <> nil then 2024 begin 2025 Path := g_list_first(AList)^.data; 2026 g_list_free(AList); 2027 end else 2028 Path := nil; 2029 end; 2030 Path := gtk_tree_model_get_path(TreeModel, @Iter); 2031 Result := StrToInt(PChar(Path)); 2032 gtk_tree_path_free(Path); 2033 end; 2034end; 2035 2036class function TGtk2WSCustomListView.GetTopItem(const ALV: TCustomListView): Integer; 2037var 2038 Res: Boolean; 2039 s, e: PGtkTreePath; 2040 Widgets: PTVWidgets; 2041 Num: Pgint; 2042begin 2043 Result := -1; 2044 if not WSCheckHandleAllocated(ALV, 'GetTopItem') then 2045 exit; 2046 Res := false; 2047 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 2048 with Widgets^ do 2049 begin 2050 if GTK_IS_TREE_VIEW(MainView) then 2051 Res := gtk_tree_view_get_visible_range(PGtkTreeView(Widgets^.MainView), s, e) 2052 else 2053 if GTK_IS_ICON_VIEW(MainView) then 2054 Res := gtk_icon_view_get_visible_range(PGtkTreeView(Widgets^.MainView), s, e) 2055 else 2056 Exit; 2057 end; 2058 if Res then 2059 begin 2060 Num := gtk_tree_path_get_indices(s); 2061 if Num <> nil then Result := Num^; 2062 gtk_tree_path_free(s); 2063 gtk_tree_path_free(e); 2064 end; 2065end; 2066 2067class function TGtk2WSCustomListView.GetViewOrigin(const ALV: TCustomListView): TPoint; 2068var 2069 Widgets: PTVWidgets; 2070begin 2071 if not WSCheckHandleAllocated(ALV, 'GetViewOrigin') 2072 then begin 2073 Result := Point(0, 0); 2074 Exit; 2075 end; 2076 2077 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 2078 2079 // not really needed to retrieve the adjustments, since the TVWidgets has this info also based on events 2080 Result := Point(Widgets^.ScrollingData.HValue, Widgets^.ScrollingData.VValue); 2081end; 2082 2083class function TGtk2WSCustomListView.GetVisibleRowCount(const ALV: TCustomListView): Integer; 2084var 2085 Res: Boolean; 2086 s, e: PGtkTreePath; 2087 Widgets: PTVWidgets; 2088 Num1,Num2: Pgint; 2089begin 2090 Result := -1; 2091 2092 if not WSCheckHandleAllocated(ALV, 'GetVisibleRowCount') then 2093 exit; 2094 2095 Result := 0; 2096 Res := false; 2097 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 2098 with Widgets^ do 2099 begin 2100 if GTK_IS_TREE_VIEW(MainView) then 2101 Res := gtk_tree_view_get_visible_range(PGtkTreeView(Widgets^.MainView), s, e) 2102 else 2103 if GTK_IS_ICON_VIEW(MainView) then 2104 Res := gtk_icon_view_get_visible_range(PGtkTreeView(Widgets^.MainView), s, e) 2105 else 2106 Exit; 2107 end; 2108 if Res then 2109 begin 2110 Num1 := gtk_tree_path_get_indices(s); 2111 Num2 := gtk_tree_path_get_indices(e); 2112 if (Num1 <> nil) and (Num2 <> nil) then Result := Num2^-Num1^+1; 2113 gtk_tree_path_free(s); 2114 gtk_tree_path_free(e); 2115 end; 2116end; 2117 2118class procedure TGtk2WSCustomListView.SelectAll(const ALV: TCustomListView; 2119 const AIsSet: Boolean); 2120var 2121 Widgets: PTVWidgets; 2122begin 2123 if not WSCheckHandleAllocated(ALV, 'SelectAll') then 2124 exit; 2125 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 2126 Include(Widgets^.WidgetInfo^.Flags, wwiInvalidEvent); 2127 try 2128 with Widgets^ do 2129 begin 2130 if GTK_IS_TREE_VIEW(MainView) then 2131 begin 2132 if AIsSet then 2133 gtk_tree_selection_select_all(gtk_tree_view_get_selection(PGtkTreeView(MainView))) 2134 else 2135 gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(PGtkTreeView(MainView))); 2136 end else 2137 begin 2138 if GTK_IS_ICON_VIEW(MainView) then 2139 begin 2140 if AIsSet then 2141 gtk_icon_view_select_all(PGtkIconView(MainView)) 2142 else 2143 gtk_icon_view_unselect_all(PGtkIconView(MainView)); 2144 end; 2145 end; 2146 end; 2147 finally 2148 Exclude(Widgets^.WidgetInfo^.Flags, wwiInvalidEvent); 2149 end; 2150end; 2151 2152class procedure TGtk2WSCustomListView.SetAllocBy(const ALV: TCustomListView; 2153 const AValue: Integer); 2154begin 2155 if not WSCheckHandleAllocated(ALV, 'SetAllocBy') 2156 then Exit; 2157end; 2158 2159class procedure TGtk2WSCustomListView.SetColor(const AWinControl: TWinControl); 2160var 2161 AWidget: PGTKWidget; 2162begin 2163 if not WSCheckHandleAllocated(AWinControl, 'SetColor') then 2164 Exit; 2165 AWidget := {%H-}PGtkWidget(AWinControl.Handle); 2166 AWidget := GetWidgetInfo(AWidget, True)^.CoreWidget; 2167 Gtk2WidgetSet.SetWidgetColor(AWidget, 2168 AWinControl.Font.Color, 2169 AWinControl.Color, 2170 [GTK_STATE_NORMAL, GTK_STATE_ACTIVE, GTK_STATE_PRELIGHT, GTK_STYLE_BASE]); 2171end; 2172 2173class procedure TGtk2WSCustomListView.SetDefaultItemHeight( 2174 const ALV: TCustomListView; const AValue: Integer); 2175begin 2176 if not WSCheckHandleAllocated(ALV, 'SetDefaultItemHeight') 2177 then Exit; 2178end; 2179 2180class procedure TGtk2WSCustomListView.SetFont(const AWinControl: TWinControl; 2181 const AFont: TFont); 2182var 2183 Widget: PGtkWidget; 2184begin 2185 if not WSCheckHandleAllocated(AWinControl, 'SetFont') then 2186 Exit; 2187 Widget := {%H-}PGtkWidget(AWinControl.Handle); 2188 Widget := GetWidgetInfo(Widget, True)^.CoreWidget; 2189 Gtk2WidgetSet.SetWidgetFont(Widget, AFont); 2190 Gtk2WidgetSet.SetWidgetColor(Widget, AFont.Color, clNone, 2191 [GTK_STATE_NORMAL,GTK_STATE_ACTIVE, 2192 GTK_STATE_PRELIGHT,GTK_STATE_SELECTED, 2193 GTK_STYLE_TEXT]); 2194end; 2195 2196class procedure TGtk2WSCustomListView.SetHotTrackStyles(const ALV: TCustomListView; 2197 const AValue: TListHotTrackStyles); 2198begin 2199 if not WSCheckHandleAllocated(ALV, 'SetHotTrackStyles') 2200 then Exit; 2201end; 2202 2203class procedure TGtk2WSCustomListView.SetImageList(const ALV: TCustomListView; 2204 const AList: TListViewImageList; const AValue: TCustomImageListResolution); 2205var 2206 Widgets: PTVWidgets; 2207 BitImage: TBitmap; 2208 pixbuf: PGDKPixBuf; 2209 i: Integer; 2210 APGList: PGList; 2211 pixrenderer: PGtkCellRenderer; 2212begin 2213 if not WSCheckHandleAllocated(ALV, 'SetImageList') 2214 then Exit; 2215 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 2216 gtk_widget_queue_draw(Widgets^.MainView); 2217 if ((AList = lvilLarge) and (TLVHack(ALV).ViewStyle = vsIcon)) or 2218 ((AList = lvilSmall) and (TLVHack(ALV).ViewStyle <> vsIcon)) then 2219 begin 2220 if Widgets^.Images <> nil then 2221 begin 2222 for i := 0 to Widgets^.Images.Count-1 do 2223 gdk_pixbuf_unref(PGdkPixBuf(Widgets^.Images.Items[i])); 2224 Widgets^.Images.Clear; 2225 end; 2226 if AValue = nil then 2227 Exit; 2228 if Widgets^.Images = nil then 2229 Widgets^.Images := TList.Create; 2230 2231 if (AValue.Count = 0) and GTK_IS_TREE_VIEW(Widgets^.MainView) and (TLVHack(ALV).Columns.Count > 0) and 2232 not TLVHack(ALV).OwnerDraw then 2233 begin 2234 APGList := gtk_tree_view_column_get_cell_renderers(gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), 0)); 2235 pixrenderer := PGtkCellRenderer(g_list_last(APGList)^.prev^.data); 2236 gtk_cell_renderer_set_fixed_size(pixrenderer, AValue.Width + 2, AValue.Height + 2); 2237 g_list_free(APGList); 2238 gtk_tree_view_column_queue_resize(gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), 0)); 2239 end; 2240 2241 for i := 0 to AValue.Count-1 do 2242 begin 2243 pixbuf := nil; 2244 BitImage := TBitmap.Create; 2245 try 2246 AValue.GetBitmap(i, BitImage); 2247 Gtk2_PixBufFromBitmap(BitImage, pixbuf); 2248 if GTK_IS_TREE_VIEW(Widgets^.MainView) and (TLVHack(ALV).Columns.Count > 0) and 2249 not TLVHack(ALV).OwnerDraw then 2250 begin 2251 APGList := gtk_tree_view_column_get_cell_renderers(gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), 0)); 2252 pixrenderer := PGtkCellRenderer(g_list_last(APGList)^.prev^.data); 2253 gtk_cell_renderer_set_fixed_size(pixrenderer, AValue.Width + 2, AValue.Height + 2); 2254 g_list_free(APGList); 2255 gtk_tree_view_column_queue_resize(gtk_tree_view_get_column(PGtkTreeView(Widgets^.MainView), 0)); 2256 end; 2257 Widgets^.Images.Add(pixbuf); 2258 finally 2259 BitImage.Free; 2260 end; 2261 end; 2262 end; 2263end; 2264 2265class procedure TGtk2WSCustomListView.SetItemsCount(const ALV: TCustomListView; 2266 const Avalue: Integer); 2267var 2268 Widgets: PTVWidgets; 2269 {$IFDEF USEORIGTREEMODEL} 2270 Iter: TGtkTreeIter; 2271 Index: Integer; 2272 {$ENDIF} 2273begin 2274 if not WSCheckHandleAllocated(ALV, 'SetItemsCount') 2275 then Exit; 2276 2277 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 2278 2279 with Widgets^ do 2280 begin 2281 {$IFNDEF USEORIGTREEMODEL} 2282 g_object_ref(TreeModel); 2283 gtk_tree_view_set_model(PGtkTreeView(MainView), nil); 2284 gtk_tree_view_set_model(PGtkTreeView(MainView), TreeModel); 2285 g_object_unref(TreeModel); 2286 {$ELSE} 2287 gtk_list_store_clear(PGtkListStore(TreeModel)); 2288 for Index := 0 to AValue - 1 do 2289 gtk_list_store_insert_with_values(PGtkListStore(TreeModel), @Iter, Index, 0, nil, -1); 2290 {$ENDIF} 2291 end; 2292end; 2293 2294class procedure TGtk2WSCustomListView.SetProperty(const ALV: TCustomListView; 2295 const AProp: TListViewProperty; const AIsSet: Boolean); 2296var 2297 Widgets: PTVWidgets; 2298begin 2299 if not WSCheckHandleAllocated(ALV, 'SetProperty') 2300 then Exit; 2301 2302 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 2303 2304 SetPropertyInternal(ALV, Widgets, AProp, AIsSet); 2305end; 2306 2307class procedure TGtk2WSCustomListView.SetProperties(const ALV: TCustomListView; 2308 const AProps: TListViewProperties); 2309var 2310 Widgets: PTVWidgets; 2311 Prop: TListViewProperty; 2312begin 2313 if not WSCheckHandleAllocated(ALV, 'SetProperties') 2314 then Exit; 2315 2316 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 2317 2318 for Prop := Low(Prop) to High(Prop) do 2319 SetPropertyInternal(ALV, Widgets, Prop, Prop in AProps); 2320end; 2321 2322class procedure TGtk2WSCustomListView.SetScrollBars(const ALV: TCustomListView; 2323 const AValue: TScrollStyle); 2324var 2325 SS:TPoint; 2326 ScrollWidget: PGtkScrolledWindow; 2327begin 2328 if not WSCheckHandleAllocated(ALV, 'SetScrollBars') then 2329 exit; 2330 2331 ScrollWidget := {%H-}PGtkScrolledWindow(ALV.Handle); 2332 SS := Gtk2TranslateScrollStyle(AValue); 2333 gtk_scrolled_window_set_policy(ScrollWidget ,SS.X, SS.Y); 2334end; 2335 2336class procedure TGtk2WSCustomListView.SetSort(const ALV: TCustomListView; 2337 const AType: TSortType; const AColumn: Integer; 2338 const ASortDirection: TSortDirection); 2339var 2340 Widgets: PTVWidgets; 2341begin 2342 if not WSCheckHandleAllocated(ALV, 'SetSort') 2343 then Exit; 2344 // gtk2 needs only update 2345 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets); 2346 if GetViewModel(Widgets^.MainView) = nil then 2347 exit; 2348 2349 if not gtk_widget_realized(Widgets^.MainView) then 2350 exit; 2351 2352 if GTK_IS_TREE_VIEW(Widgets^.MainView) then 2353 gtk_widget_queue_draw(Widgets^.MainView); 2354end; 2355 2356class procedure TGtk2WSCustomListView.SetViewOrigin(const ALV: TCustomListView; 2357 const AValue: TPoint); 2358var 2359 Widgets: PTVWidgets; 2360begin 2361 if not WSCheckHandleAllocated(ALV, 'SetViewOrigin') 2362 then Exit; 2363 2364 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets{%H-}); 2365 //DebugLn(['TGtk2WSCustomListView.SetViewOrigin ',GetWidgetDebugReport(Widgets^.MainView)]); 2366 if not GTK_WIDGET_REALIZED(Widgets^.MainView) then exit; 2367 if GTK_IS_TREE_VIEW(Widgets^.MainView) then 2368 gtk_tree_view_scroll_to_point(PGtkTreeView(Widgets^.MainView), AValue.X, AValue.Y) 2369 else 2370 if GTK_IS_ICON_VIEW(Widgets^.MainView) then 2371 begin 2372 // TODO: iconview 2373 end; 2374end; 2375 2376class procedure TGtk2WSCustomListView.SetViewStyle(const ALV: TCustomListView; 2377 const AValue: TViewStyle); 2378 2379var 2380 APtrIntData: PtrInt; 2381 2382 procedure ShowColumns(const Widgets: PTVWidgets; const Show: Boolean); 2383 var 2384 List: PGList; 2385 GtkColumn: PGtkTreeViewColumn; 2386 i: Integer; 2387 begin 2388 if not GTK_IS_TREE_VIEW(Widgets^.MainView) then 2389 Exit; 2390 List := gtk_tree_view_get_columns(PGtkTreeView(Widgets^.MainView)); 2391 for i := 0 to g_list_length(List) - 1 do 2392 begin 2393 GtkColumn := g_list_nth_data(List, i); 2394 if GtkColumn = nil then 2395 Continue; 2396 2397 if not Show or 2398 (Show and ({%H-}PtrUInt(g_object_get_data(G_OBJECT(GtkColumn), 2399 PChar('Visible'))) <> 0)) then 2400 gtk_tree_view_column_set_visible(GtkColumn, Show); 2401 end; 2402 g_list_free(List) 2403 end; 2404 2405var 2406 Widgets: PTVWidgets; 2407begin 2408 if not WSCheckHandleAllocated(ALV, 'SetViewStyle') 2409 then Exit; 2410 2411 GetCommonTreeViewWidgets({%H-}PGtkWidget(ALV.Handle), Widgets{%H-}); 2412 if g_object_get_data(PGObject(Widgets^.MainView),'lcllistviewstyle') <> nil then 2413 APtrIntData := {%H-}PtrInt(g_object_get_data(PGObject(Widgets^.MainView),'lcllistviewstyle')) 2414 else 2415 APtrIntData := -1; 2416 if (APtrIntData <> -1) and (APtrIntData - 1 <> Ord(AValue)) then 2417 begin 2418 // we have to free the GtkTreeView and Create GtkIconView etc depending on the new style 2419 //RecreateMainView(ALV); 2420 // we actually need to recreate our ListView since not only the widget changes but also columns 2421 RecreateWnd(ALV); 2422 Exit; 2423 end; 2424 2425 ShowColumns(Widgets, AValue = vsReport); 2426 with Widgets^ do 2427 begin 2428 case AValue of 2429 vsIcon, 2430 vsSmallIcon: 2431 begin 2432 SetNeedDefaultColumn(ALV, True); 2433 end; 2434 vsList: 2435 begin 2436 SetNeedDefaultColumn(ALV, True); 2437 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW (MainView), False); 2438 end; 2439 vsReport: 2440 begin 2441 SetNeedDefaultColumn(ALV, False); 2442 if TLVHack(ALV).ShowColumnHeaders = True then 2443 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW (MainView), True); 2444 end; 2445 end; 2446 end; 2447// inherited SetViewStyle(ALV, Avalue); 2448end; 2449