1{%MainUnit gtkwscomctrls.pp} 2{ $Id: gtkwscustomlistview.inc 57164 2018-01-27 18:12:35Z ondrej $ 3 4 ***************************************************************************** 5 This file is part of the Lazarus Component Library (LCL) 6 7 See the file COPYING.modifiedLGPL.txt, included in this distribution, 8 for details about the license. 9 ***************************************************************************** 10} 11 12 13{ TGtkWSCustomListView } 14 15type 16 TLVHack = class(TCustomListView) 17 end; 18 19 PCustomListViewData = ^TCustomListViewData; 20 TCustomListViewData = record 21 ScrollingData: TBaseScrollingWinControlData; 22 ViewStyle: TViewStyle; 23 end; 24 25//////////////////////////////////////////////////////////////////////////////// 26// Event code 27//////////////////////////////////////////////////////////////////////////////// 28 29 30 31//---------------------- 32//HDN_ENDTRACK 33//HDN_TRACK 34function GtkWSCustomListView_AbortColumnResize(AList: PGTKCList; AInfo: PWidgetInfo): GBoolean; cdecl; 35begin 36 //TODO: implement 37 Result := False; 38end; 39 40//---------------------- 41//HDN_ENDTRACK 42//HDN_TRACK 43//HDN_ITEMCHANGED 44//HDN_ITEMCHANGING 45function GtkWSCustomListView_ResizeColumn(AList: PGTKCList; AColumn, AWidth: Integer; AInfo: PWidgetInfo): GBoolean; cdecl; 46begin 47 //TODO: implement 48 Result := False; 49end; 50 51//---------------------- 52//HDN_ITEMCLICK 53//LVN_COLUMNCLICK 54function GtkWSCustomListView_ClickColumn(AList: PGTKCList; AColumn: Integer; AInfo: PWidgetInfo): GBoolean; cdecl; 55var 56 msg: TLMNotify; 57 NM: TNMListView; 58 ALV: TListView; 59begin 60 // this can happen when no columns are added which crashes the program 61 ALV := TListView(AInfo^.LCLObject); 62 if AColumn > ALV.Columns.Count-1 then 63 Exit; 64 65 msg.Msg := CN_NOTIFY; 66 67 FillChar(NM, SizeOf(NM), 0); 68 NM.hdr.hwndfrom := PtrUInt(AList); 69 NM.hdr.code := LVN_COLUMNCLICK; 70 NM.iItem := -1; 71 NM.iSubItem := AColumn; 72 msg.NMHdr := @NM.hdr; 73 Result := DeliverMessage(AInfo^.LCLObject, msg) = 0; 74end; 75 76//---------------------- 77//LVN_DELETEITEM 78//LVN_INSERTITEM 79function GtkWSCustomListView_RowMove(AList: PGTKCList; AnOldIdx, ANewIdx: Integer; AInfo: PWidgetInfo): GBoolean; cdecl; 80var 81 msg: TLMNotify; 82 NM: TNMListView; 83 r: Boolean; 84begin 85 // Simulate move by remove and insert 86 msg.Msg := CN_NOTIFY; 87 88 FillChar(NM, SizeOf(NM), 0); 89 NM.hdr.hwndfrom := PtrUInt(AList); 90 NM.hdr.code := LVN_DELETEITEM; 91 NM.iItem := AnOldIdx; 92 msg.NMHdr := @NM.hdr; 93 r := DeliverMessage(AInfo^.LCLObject, msg) = 0; 94 95 NM.hdr.code := LVN_INSERTITEM; 96 NM.iItem := ANewIdx; 97 Result := (DeliverMessage(AInfo^.LCLObject, msg) = 0) and r; 98end; 99 100//---------------------- 101//LVN_ITEMCHANGED 102//LVN_ITEMCHANGING 103function GtkWSCustomListView_SelectRow(AList: PGTKCList; ARow, AColumn: Integer; AEvent: PGDKEventButton; AInfo: PWidgetInfo): GBoolean; cdecl; 104var 105 msg: TLMNotify; 106 NM: TNMListView; 107begin 108 msg.Msg := CN_NOTIFY; 109 110 FillChar(NM, SizeOf(NM), 0); 111 NM.hdr.hwndfrom := PtrUInt(AList); 112 NM.hdr.code := LVN_ITEMCHANGED; 113 NM.iItem := ARow; 114 NM.iSubItem := AColumn; 115 NM.uNewState := LVIS_SELECTED; 116 NM.uChanged := LVIF_STATE; 117 msg.NMHdr := @NM.hdr; 118 Result := DeliverMessage(AInfo^.LCLObject, msg) = 0; 119end; 120 121function GtkWSCustomListView_UnSelectRow(AList: PGTKCList; ARow, AColumn: Integer; AEvent: PGDKEventButton; AInfo: PWidgetInfo): GBoolean; cdecl; 122var 123 msg: TLMNotify; 124 NM: TNMListView; 125begin 126 msg.Msg := CN_NOTIFY; 127 128 FillChar(NM, SizeOf(NM), 0); 129 NM.hdr.hwndfrom := PtrUInt(AList); 130 NM.hdr.code := LVN_ITEMCHANGED; 131 NM.iItem := ARow; 132 NM.iSubItem := AColumn; 133 NM.uOldState := LVIS_SELECTED; 134 NM.uChanged := LVIF_STATE; 135 msg.NMHdr := @NM.hdr; 136 Result := DeliverMessage(AInfo^.LCLObject, msg) = 0; 137end; 138 139function GtkWSCustomListView_ToggleFocusRow(AList: PGTKCList; AInfo: PWidgetInfo): GBoolean; cdecl; 140var 141 msg: TLMNotify; 142 NM: TNMListView; 143begin 144 // the defocus of the oldrow isn't send 145 146 msg.Msg := CN_NOTIFY; 147 148 FillChar(NM, SizeOf(NM), 0); 149 NM.hdr.hwndfrom := PtrUInt(AList); 150 NM.hdr.code := LVN_ITEMCHANGED; 151 NM.iItem := AList^.focus_row; 152 NM.iSubItem := 0; 153 NM.uNewState := LVIS_FOCUSED; 154 NM.uChanged := LVIF_STATE; 155 msg.NMHdr := @NM.hdr; 156 Result := DeliverMessage(AInfo^.LCLObject, msg) = 0; 157end; 158 159function GtkWSCustomListView_SelectAll(AList: PGTKCList; AInfo: PWidgetInfo): GBoolean; cdecl; 160var 161 msg: TLMNotify; 162 NM: TNMListView; 163 ListView: TListView; 164 n: Integer; 165begin 166 msg.Msg := CN_NOTIFY; 167 168 ListView := AInfo^.LCLObject as TListView; 169 170 FillChar(NM, SizeOf(NM), 0); 171 NM.hdr.hwndfrom := PtrUInt(AList); 172 NM.hdr.code := LVN_ITEMCHANGED; 173 for n := 0 to Listview.Items.Count - 1 do 174 begin 175 if ListView.Items[n].Selected 176 then Continue; 177 NM.iItem := n; 178 NM.iSubItem := -1; 179 NM.uNewState := LVIS_SELECTED; 180 NM.uChanged := LVIF_STATE; 181 msg.NMHdr := @NM.hdr; 182 Result := DeliverMessage(AInfo^.LCLObject, msg) = 0; 183 end; 184end; 185 186function GtkWSCustomListView_UnSelectAll(AList: PGTKCList; AInfo: PWidgetInfo): GBoolean; cdecl; 187var 188 msg: TLMNotify; 189 NM: TNMListView; 190 ListView: TListView; 191 n: Integer; 192begin 193 msg.Msg := CN_NOTIFY; 194 195 ListView := AInfo^.LCLObject as TListView; 196 197 FillChar(NM, SizeOf(NM), 0); 198 NM.hdr.hwndfrom := PtrUInt(AList); 199 NM.hdr.code := LVN_ITEMCHANGED; 200 for n := 0 to Listview.Items.Count - 1 do 201 begin 202 if not ListView.Items[n].Selected 203 then Continue; 204 NM.iItem := n; 205 NM.iSubItem := -1; 206 NM.uOldState := LVIS_SELECTED; 207 NM.uChanged := LVIF_STATE; 208 msg.NMHdr := @NM.hdr; 209 Result := DeliverMessage(AInfo^.LCLObject, msg) = 0; 210 end; 211end; 212 213function GtkWSCustomListView_EndSelection(AList: PGTKCList; AInfo: PWidgetInfo): GBoolean; cdecl; 214begin 215 Result:=true; 216end; 217 218//////////////////////////////////////////////////////////////////////////////// 219// Column code 220//////////////////////////////////////////////////////////////////////////////// 221 222class procedure TGtkWSCustomListView.ColumnDelete(const ALV: TCustomListView; const AIndex: Integer); 223var 224 WidgetInfo: PWidgetInfo; 225 CListWidget: PGtkCList; 226begin 227 if not WSCheckHandleAllocated(ALV, 'ColumnDelete') then Exit; 228 229 // allow only column modifications when in report mode 230 if TLVHack(ALV).ViewStyle <> vsReport then Exit; 231 232 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 233 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 234 if CListWidget^.columns = TLVHack(ALV).Columns.Count then Exit; // possible delayed update 235 if AIndex >= CListWidget^.columns then Exit; // ??? 236 237 RecreateWnd(ALV); 238end; 239 240class function TGtkWSCustomListView.ColumnGetWidth(const ALV: TCustomListView; const AIndex: Integer; const AColumn: TListColumn): Integer; 241var 242 WidgetInfo: PWidgetInfo; 243 CListWidget: PGtkCList; 244 CListColumn: PGtkCListColumn; 245begin 246 Result := -1; 247 if not WSCheckHandleAllocated(ALV, 'ColumnGetSize') then Exit; 248 249 // allow only column modifications when in report mode 250 if TLVHack(ALV).ViewStyle <> vsReport then Exit; 251 252 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 253 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 254 255 // there is no get width function, so we need some internal hacking 256 if AIndex >= CListWidget^.columns then Exit; 257 CListColumn := CListWidget^.Column; 258 Inc(CListColumn, AIndex); 259 Result := CListColumn^.width; 260end; 261 262class procedure TGtkWSCustomListView.ColumnInsert(const ALV: TCustomListView; const AIndex: Integer; const AColumn: TListColumn); 263var 264 WidgetInfo: PWidgetInfo; 265 CListWidget: PGtkCList; 266begin 267 if not WSCheckHandleAllocated(ALV, 'ColumnInsert') then Exit; 268 269 // allow only column modifications when in report mode 270 if TLVHack(ALV).ViewStyle <> vsReport then Exit; 271 272 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 273 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 274 if CListWidget^.columns = TLVHack(ALV).Columns.Count then Exit; // possible delayed update 275 276 RecreateWnd(ALV); 277end; 278 279class procedure TGtkWSCustomListView.ColumnMove(const ALV: TCustomListView; const AOldIndex, ANewIndex: Integer; const AColumn: TListColumn); 280 procedure CopyColumn(const AList: PGtkCList; const AIndex: Integer; const ASrc: PGtkCListColumn); 281 begin 282 gtk_clist_set_column_title(AList, AIndex, ASrc^.title); 283 gtk_clist_set_column_min_width(AList, AIndex, ASrc^.min_width); 284 gtk_clist_set_column_max_width(AList, AIndex, ASrc^.max_width); 285 gtk_clist_set_column_width(AList, AIndex, ASrc^.width); 286 gtk_clist_set_column_justification(AList, AIndex, ASrc^.justification); 287 gtk_clist_set_column_visibility(AList, AIndex, (ASrc^.flag0 and bm_TGtkCListColumn_visible) <> 0); 288 gtk_clist_set_column_resizeable(AList, AIndex, (ASrc^.flag0 and bm_TGtkCListColumn_resizeable) <> 0); 289 gtk_clist_set_column_auto_resize(AList, AIndex, (ASrc^.flag0 and bm_TGtkCListColumn_auto_resize) <> 0); 290 if (ASrc^.flag0 and bm_TGtkCListColumn_button_passive) <> 0 291 then gtk_clist_column_title_passive(AList, AIndex) 292 else gtk_clist_column_title_active(AList, AIndex); 293 end; 294var 295 WidgetInfo: PWidgetInfo; 296 CListWidget: PGtkCList; 297 CListColumn: PGtkCListColumn; 298 OldCListColumn: TGtkCListColumn; 299 Count: Integer; 300 301begin 302 if not WSCheckHandleAllocated(ALV, 'ColumnMove') then Exit; 303 304 // allow only column modifications when in report mode 305 if TLVHack(ALV).ViewStyle <> vsReport then Exit; 306 307 if AOldIndex = ANewIndex then Exit; 308 if AOldIndex < 0 then Exit; 309 if ANewIndex < 0 then Exit; 310 311 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 312 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 313 314 if AOldIndex >= CListWidget^.columns then Exit; 315 if ANewIndex >= CListWidget^.columns then Exit; 316 317 Count := AOldIndex - ANewIndex; 318 319 // Fetch old column values 320 CListColumn := CListWidget^.Column; 321 Inc(CListColumn, AOldIndex); 322 OldCListColumn := CListColumn^; 323 // Create copy of the title 324 OldCListColumn.title := StrNew(OldCListColumn.title); 325 326 while Count <> 0 do 327 begin 328 // move to next source 329 if Count < 0 330 then Inc(CListColumn) 331 else Dec(CListColumn); 332 333 CopyColumn(CListWidget, ANewIndex + Count, CListColumn); 334 335 if Count < 0 336 then Inc(Count) 337 else Dec(Count); 338 end; 339 // finally copy original data to new column 340 CopyColumn(CListWidget, ANewIndex, @OldCListColumn); 341 // dispose copy of the title 342 StrDispose(OldCListColumn.title); 343end; 344 345class procedure TGtkWSCustomListView.ColumnSetAlignment(const ALV: TCustomListView; const AIndex: Integer; const AColumn: TListColumn; const AAlignment: TAlignment); 346const 347 JUSTIFICATION: array[TAlignment] of TGtkJustification = ( 348 GTK_JUSTIFY_LEFT, 349 GTK_JUSTIFY_RIGHT, 350 GTK_JUSTIFY_CENTER 351 ); 352var 353 WidgetInfo: PWidgetInfo; 354 CListWidget: PGtkCList; 355begin 356 if not WSCheckHandleAllocated(ALV, 'ColumnSetAlignment') then Exit; 357 358 // allow only column modifications when in report mode 359 if TLVHack(ALV).ViewStyle <> vsReport then Exit; 360 361 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 362 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 363 364 gtk_clist_set_column_justification(CListWidget, AIndex, JUSTIFICATION[AAlignment]); 365end; 366 367class procedure TGtkWSCustomListView.ColumnSetAutoSize(const ALV: TCustomListView; const AIndex: Integer; const AColumn: TListColumn; const AAutoSize: Boolean); 368var 369 WidgetInfo: PWidgetInfo; 370 CListWidget: PGtkCList; 371begin 372 if not WSCheckHandleAllocated(ALV, 'ColumnSetAutoSize') then Exit; 373 374 // allow only column modifications when in report mode 375 if TLVHack(ALV).ViewStyle <> vsReport then Exit; 376 377 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 378 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 379 380 gtk_clist_set_column_auto_resize(CListWidget, AIndex, AAutoSize); 381end; 382 383class procedure TGtkWSCustomListView.ColumnSetCaption(const ALV: TCustomListView; const AIndex: Integer; const AColumn: TListColumn; const ACaption: String); 384var 385 WidgetInfo: PWidgetInfo; 386 CListWidget: PGtkCList; 387begin 388 if not WSCheckHandleAllocated(ALV, 'ColumnSetCaption') then Exit; 389 390 // allow only column modifications when in report mode 391 if TLVHack(ALV).ViewStyle <> vsReport then Exit; 392 393 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 394 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 395 396 gtk_clist_set_column_title(CListWidget, AIndex, PChar(ACaption)); 397end; 398 399class procedure TGtkWSCustomListView.ColumnSetImage(const ALV: TCustomListView; const AIndex: Integer; const AColumn: TListColumn; const AImageIndex: Integer); 400var 401 WidgetInfo: PWidgetInfo; 402 CListWidget: PGtkCList; 403begin 404 if not WSCheckHandleAllocated(ALV, 'ColumnSetImage') then Exit; 405 406 // allow only column modifications when in report mode 407 if TLVHack(ALV).ViewStyle <> vsReport then Exit; 408 409 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 410 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 411 412 //TODO 413 if CListWidget=nil then exit; 414end; 415 416class procedure TGtkWSCustomListView.ColumnSetMaxWidth(const ALV: TCustomListView; const AIndex: Integer; const AColumn: TListColumn; const AMaxWidth: Integer); 417var 418 WidgetInfo: PWidgetInfo; 419 CListWidget: PGtkCList; 420begin 421 if not WSCheckHandleAllocated(ALV, 'ColumnSetMaxWidth') then Exit; 422 423 // allow only column modifications when in report mode 424 if TLVHack(ALV).ViewStyle <> vsReport then Exit; 425 426 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 427 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 428 429 430 // TODO: ? -1 -2 431 //LVSCW_AUTOSIZE = -1; 432 //LVSCW_AUTOSIZE_USEHEADER = -2; 433 434 if AMaxWidth <= 0 // unlimited 435 then gtk_clist_set_column_max_width(CListWidget, AIndex, -1) 436 else gtk_clist_set_column_max_width(CListWidget, AIndex, AMaxWidth); 437end; 438 439class procedure TGtkWSCustomListView.ColumnSetMinWidth(const ALV: TCustomListView; const AIndex: Integer; const AColumn: TListColumn; const AMinWidth: integer); 440var 441 WidgetInfo: PWidgetInfo; 442 CListWidget: PGtkCList; 443begin 444 if not WSCheckHandleAllocated(ALV, 'ColumnSetMinWidth') then Exit; 445 446 // allow only column modifications when in report mode 447 if TLVHack(ALV).ViewStyle <> vsReport then Exit; 448 449 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 450 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 451 452 gtk_clist_set_column_min_width(CListWidget, AIndex, AMinWidth); 453end; 454 455class procedure TGtkWSCustomListView.ColumnSetWidth(const ALV: TCustomListView; const AIndex: Integer; const AColumn: TListColumn; const AWidth: Integer); 456var 457 WidgetInfo: PWidgetInfo; 458 CListWidget: PGtkCList; 459begin 460 if not WSCheckHandleAllocated(ALV, 'ColumnSetWidth') then Exit; 461 462 // allow only column modifications when in report mode 463 if TLVHack(ALV).ViewStyle <> vsReport then Exit; 464 465 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 466 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 467 468 gtk_clist_set_column_width(CListWidget, AIndex, AWidth); 469end; 470 471class procedure TGtkWSCustomListView.ColumnSetVisible(const ALV: TCustomListView; const AIndex: Integer; const AColumn: TListColumn; const AVisible: Boolean); 472var 473 WidgetInfo: PWidgetInfo; 474 CListWidget: PGtkCList; 475begin 476 if not WSCheckHandleAllocated(ALV, 'ColumnSetVisible') then Exit; 477 478 // allow only column modifications when in report mode 479 if TLVHack(ALV).ViewStyle <> vsReport then Exit; 480 481 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 482 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 483 484 gtk_clist_set_column_visibility(CListWidget, AIndex, AVisible); 485end; 486 487//////////////////////////////////////////////////////////////////////////////// 488// Item code 489//////////////////////////////////////////////////////////////////////////////// 490 491class procedure TGtkWSCustomListView.ItemChangeInternal(const ACListWidget: PGtkCList; const ALV: TCustomListView; const AIndex: Integer; const AItem: TListItem); 492var 493 ImageBitmap: TBitmap; 494 GDIObject: PGDIObject; 495 Pixmap: PGdkPixmap; 496 Mask: PGdkBitmap; 497 n, Count: integer; 498begin 499 if (TLVHack(ALV).SmallImages <> nil) 500 and (AItem.ImageIndex >= 0) 501 and (AItem.ImageIndex < TLVHack(ALV).SmallImages.Count) 502 then begin 503 // set image & caption 504 ImageBitmap := TBitmap.Create; 505 Mask := nil; 506 try 507 TLVHack(ALV).SmallImages.GetBitmap(AItem.ImageIndex, ImageBitmap); 508 GDIObject := PGDIObject(ImageBitmap.Handle); 509 case GDIObject^.GDIBitmapType of 510 gbBitmap: 511 begin 512 Pixmap := GDIObject^.GDIBitmapObject; 513 Mask := nil; 514 end; 515 gbPixmap: 516 begin 517 Pixmap := GDIObject^.GDIPixmapObject.Image; 518 Mask := CreateGdkMaskBitmap(ImageBitmap.Handle, ImageBitmap.MaskHandle); 519 end; 520 gbPixbuf: 521 begin 522 Pixmap := nil; 523 Mask := nil; 524 gdk_pixbuf_render_pixmap_and_mask(GDIObject^.GDIPixbufObject, Pixmap, Mask, $80); 525 end; 526 end; 527 gtk_clist_set_pixtext(ACListWidget, AIndex, 0, PChar(AItem.Caption), 3, Pixmap, Mask); 528 finally 529 if Mask <> nil then 530 gdk_bitmap_unref(Mask); 531 if Pixmap <> GDIObject^.GDIPixmapObject.Image then 532 gdk_pixmap_unref(Pixmap); 533 ImageBitmap.Free; 534 end; 535 end 536 else begin 537 // set caption alone 538 gtk_clist_set_text(ACListWidget, AIndex, 0, PChar(AItem.Caption)); 539 end; 540 541 // set the other column texts 542 Count := AItem.SubItems.Count + 1; 543 if Count > ACListWidget^.Columns 544 then Count := ACListWidget^.Columns; 545 // set the existing subitems 546 for n := 1 to Count - 1 do 547 gtk_clist_set_text(ACListWidget, AIndex, n, PChar(AItem.SubItems[n - 1])); 548 // fill remaining 549 for n := Count to ACListWidget^.Columns - 1 do 550 gtk_clist_set_text(ACListWidget, AIndex, n, #0); 551end; 552 553class procedure TGtkWSCustomListView.ItemDelete(const ALV: TCustomListView; 554 const AIndex: Integer); 555var 556 WidgetInfo: PWidgetInfo; 557 CListWidget: PGtkCList; 558begin 559 if not WSCheckHandleAllocated(ALV, 'ItemDelete') 560 then Exit; 561 562 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 563 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 564 565 gtk_clist_remove(CListWidget, AIndex); 566end; 567 568class procedure TGtkWSCustomListView.ItemExchange(const ALV: TCustomListView; 569 AItem: TListItem; const AIndex1, AIndex2: Integer); 570begin 571 if not WSCheckHandleAllocated(ALV, 'ItemExchange') then 572 exit; 573 ItemMove(ALV, AItem, AIndex1, AIndex2); 574 if AIndex1 > AIndex2 then 575 ItemMove(ALV, AItem, AIndex2 + 1, AIndex1) 576 else 577 ItemMove(ALV, AItem, AIndex2 - 1, AIndex1); 578end; 579 580class procedure TGtkWSCustomListView.ItemMove(const ALV: TCustomListView; 581 AItem: TListItem; const AFromIndex, AToIndex: Integer); 582var 583 WidgetInfo: PWidgetInfo; 584 CListWidget: PGtkCList; 585begin 586 if not WSCheckHandleAllocated(ALV, 'ItemMove') then 587 exit; 588 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 589 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 590 gtk_clist_row_move(CListWidget, AFromIndex, AToIndex); 591end; 592 593class function TGtkWSCustomListView.ItemGetState(const ALV: TCustomListView; 594 const AIndex: Integer; const AItem: TListItem; const AState: TListItemState; 595 out AIsSet: Boolean): Boolean; 596var 597 WidgetInfo: PWidgetInfo; 598 CListWidget: PGtkCList; 599begin 600 Result := False; 601 602 if not WSCheckHandleAllocated(ALV, 'ItemGetState') 603 then Exit; 604 605 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 606 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 607 if (AIndex < 0) or (AIndex >= CListWidget^.rows) 608 then begin 609 DebugLN('[TGtkWSCustomListView.ItemGetState] Invalid row index: %d', [Aindex]); 610 Exit; 611 end; 612 613 case AState of 614 lisCut, 615 lisDropTarget: begin 616 //TODO: do something with the rowcolor ? 617 end; 618 619 lisFocused: begin 620 AIsSet := CListWidget^.focus_row = AIndex; 621 Result := True; 622 end; 623 624 lisSelected: begin 625 AIsSet := (CListWidget^.selection <> nil) 626 and (g_list_find(CListWidget^.selection, Pointer(PtrInt(Aindex))) <> nil); 627 Result := True; 628 end; 629 end; 630 631end; 632 633class procedure TGtkWSCustomListView.ItemInsert(const ALV: TCustomListView; const AIndex: Integer; const AItem: TListItem); 634var 635 WidgetInfo: PWidgetInfo; 636 CListWidget: PGtkCList; 637 Titles: PPGChar; 638 idx, Count: Integer; 639begin 640 if not WSCheckHandleAllocated(ALV, 'ItemInsert') 641 then Exit; 642 643 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 644 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 645 646 Count := CListWidget^.columns; 647 648 if Count = 0 649 then begin 650 DebugLn('WARNING: TGtkWSCustomListView.ItemInsert CListWidget^.columns = 0'); 651 Exit; 652 end; 653 654 GetMem(Titles, SizeOf(PGChar) * Count); 655 FillChar(Titles^, SizeOf(PGChar) * Count, 0); 656 Titles[0] := #0; 657 658 idx := AIndex; 659 if idx = -1 660 then idx := gtk_clist_append(CListWidget, Titles) 661 else gtk_clist_insert(CListWidget, idx, Titles); 662 FreeMem(Titles); 663 664 ItemChangeInternal(CListWidget, ALV, idx, AItem); 665end; 666 667class procedure TGtkWSCustomListView.ItemSetImage(const ALV: TCustomListView; const AIndex: Integer; const AItem: TListItem; const ASubIndex, AImageIndex: Integer); 668var 669 WidgetInfo: PWidgetInfo; 670 CListWidget: PGtkCList; 671 ImageBitmap: TBitmap; 672 Pixmap: PGdkPixmap; 673 Mask: PGdkBitmap; 674 Spacing: guint8; 675 Text: PChar; 676 Dummy1, Dummy2: PGdkBitmap; 677 CellType: TGtkCellType; 678begin 679 if not WSCheckHandleAllocated(ALV, 'ItemSetImage') 680 then Exit; 681 682 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 683 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 684 685 Pixmap := nil; 686 Mask := nil; 687 688 if (TLVHack(ALV).SmallImages <> nil) 689 and (AImageIndex >= 0) 690 and (AImageIndex < TLVHack(ALV).SmallImages.Count) 691 then begin 692 // set image & caption 693 ImageBitmap := TBitmap.Create; 694 try 695 TLVHack(ALV).SmallImages.GetBitmap(AImageIndex, ImageBitmap); 696 case PGDIObject(ImageBitmap.Handle)^.GDIBitmapType of 697 gbBitmap: 698 begin 699 Pixmap := PGDIObject(ImageBitmap.Handle)^.GDIBitmapObject; 700 gdk_pixmap_ref(Pixmap); 701 Mask := nil; 702 end; 703 gbPixmap: 704 begin 705 Pixmap := PGDIObject(ImageBitmap.Handle)^.GDIPixmapObject.Image; 706 Mask := CreateGdkMaskBitmap(ImageBitmap.Handle, ImageBitmap.MaskHandle); 707 gdk_pixmap_ref(Pixmap); 708 end; 709 gbPixbuf: 710 begin 711 Pixmap := nil; 712 Mask := nil; 713 gdk_pixbuf_render_pixmap_and_mask(PGDIObject(ImageBitmap.Handle)^.GDIPixbufObject, pixmap, mask, $80); 714 end; 715 end; 716 finally 717 ImageBitmap.Free; 718 end; 719 end; 720 721 CellType := gtk_clist_get_cell_type(CListWidget, AIndex, ASubIndex); 722 // Sigh. 723 // gtk returns -1 for an invalid cell (which is not part of the enum) 724 // so to handle it, we need a case based on integer 725 case Ord(CellType) of 726 Ord(GTK_CELL_TEXT), 727 Ord(GTK_CELL_PIXTEXT), 728 Ord(GTK_CELL_EMPTY), 729 Ord(GTK_CELL_PIXMAP): begin 730 if pixmap <> nil 731 then begin 732 case CellType of 733 GTK_CELL_TEXT: begin 734 // convert the cell 735 Text := nil; 736 gtk_clist_get_text(CListWidget, AIndex, ASubIndex, @Text); 737 gtk_clist_set_pixtext(CListWidget, AIndex, ASubIndex, Text, DEFAULT_IMAGE_SPACING, Pixmap, Mask); 738 end; 739 GTK_CELL_PIXTEXT: begin 740 if gtk_clist_get_pixtext(CListWidget, AIndex, ASubIndex, @Text, @Spacing, @Dummy2, @Dummy1) <> 0 741 then gtk_clist_set_pixtext(CListWidget, AIndex, ASubIndex, Text, Spacing, Pixmap, Mask) 742 else gtk_clist_set_pixmap(CListWidget, AIndex, ASubIndex, Pixmap, Mask); 743 end; 744 GTK_CELL_EMPTY, 745 GTK_CELL_PIXMAP: begin 746 gtk_clist_set_pixtext(CListWidget, AIndex, ASubIndex, '', DEFAULT_IMAGE_SPACING, Pixmap, Mask); 747 end; 748 end; 749 end 750 else begin 751 case CellType of 752 GTK_CELL_EMPTY, 753 GTK_CELL_TEXT:; // nothing to do 754 GTK_CELL_PIXTEXT: begin 755 Text := nil; 756 if gtk_clist_get_pixtext(CListWidget, AIndex, ASubIndex, @Text, @Spacing, @Dummy2, @Dummy1) <> 0 757 then gtk_clist_set_text(CListWidget, AIndex, ASubIndex, Text) 758 else gtk_clist_set_text(CListWidget, AIndex, ASubIndex, ''); 759 end; 760 GTK_CELL_PIXMAP: begin 761 gtk_clist_set_text(CListWidget, AIndex, ASubIndex, ''); 762 end; 763 end; 764 end; 765 end; 766 Ord(GTK_CELL_WIDGET): DebugLN('[TGtkWSCustomListView.ItemSetImage] Setting text of widget cell'); 767 -1: DebugLN('[TGtkWSCustomListView.ItemSetText] Cell (%d,%d) not created', [AIndex, ASubIndex]); 768 else 769 DebugLN('[TGtkWSCustomListView.ItemSetImage] Unknown celltype %d', [Ord(CellType)]); 770 end; 771 if Pixmap <> nil then 772 gdk_pixmap_unref(Pixmap); 773 if Mask <> nil then 774 gdk_bitmap_unref(Mask); 775end; 776 777class procedure TGtkWSCustomListView.ItemSetState(const ALV: TCustomListView; const AIndex: Integer; const AItem: TListItem; const AState: TListItemState; const AIsSet: Boolean); 778var 779 WidgetInfo: PWidgetInfo; 780 CListWidget: PGtkCList; 781begin 782 if not WSCheckHandleAllocated(ALV, 'ItemSetState') 783 then Exit; 784 785 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 786 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 787 if (AIndex < 0) or (AIndex >= CListWidget^.rows) 788 then begin 789 DebugLN('[TGtkWSCustomListView.ItemSetState] Invalid row index: %d', [Aindex]); 790 Exit; 791 end; 792 793 case AState of 794 lisCut, 795 lisDropTarget: begin 796 //TODO: do something with the rowcolor ? 797 end; 798 799 lisFocused: begin 800 if AIsSet = (CListWidget^.focus_row = AIndex) then Exit; 801 // reset old focus 802 if (CListWidget^.focus_row <> -1) 803 and (gtk_widget_has_focus(PGtkWidget(CListWidget))) 804 then gtk_widget_draw_focus(PGtkWidget(CListWidget)); 805 806 if AIsSet 807 then begin 808 CListWidget^.focus_row := AIndex; 809 if gtk_widget_has_focus(PGtkWidget(CListWidget)) 810 then gtk_widget_draw_focus(PGtkWidget(CListWidget)); 811 end 812 else CListWidget^.focus_row := -1; 813 end; 814 815 lisSelected: begin 816 if AIsSet 817 then begin 818 if (CListWidget^.selection_mode = GTK_SELECTION_SINGLE) 819 or (CListWidget^.selection_mode = GTK_SELECTION_BROWSE) 820 then begin 821 // check if the row is are already selected 822 // since we are in singleselect, the first item is checked 823 if (CListWidget^.selection <> nil) 824 and (PtrInt(PtrUInt(CListWidget^.selection^.Data)) = AIndex) 825 then Exit; 826 gtk_clist_unselect_all(CListWidget); 827 end; 828 gtk_clist_select_row(CListWidget, AIndex, 0); 829 end 830 else gtk_clist_unselect_row(CListWidget, AIndex, 0); 831 end; 832 end; 833end; 834 835class procedure TGtkWSCustomListView.ItemSetText(const ALV: TCustomListView; const AIndex: Integer; const AItem: TListItem; const ASubIndex: Integer; const AText: String); 836var 837 WidgetInfo: PWidgetInfo; 838 CListWidget: PGtkCList; 839 Pixmap: PGdkPixmap; 840 Mask: PGdkBitmap; 841 Spacing: guint8; 842 Dummy: pgchar; 843 CellType: TGtkCellType; 844begin 845 if not WSCheckHandleAllocated(ALV, 'ItemSetText') 846 then Exit; 847 848 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 849 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 850 851 CellType := gtk_clist_get_cell_type(CListWidget, AIndex, ASubIndex); 852 // Sigh. 853 // gtk returns -1 for an invalid cell (which is not part of the enum) 854 // so to handle it, we need a case based on integer 855 case Ord(CellType) of 856 Ord(GTK_CELL_EMPTY), 857 Ord(GTK_CELL_TEXT): begin 858 // simply set the text 859 gtk_clist_set_text(CListWidget, AIndex, ASubIndex, PChar(AText)); 860 end; 861 Ord(GTK_CELL_PIXTEXT): begin 862 if gtk_clist_get_pixtext(CListWidget, AIndex, ASubIndex, @Dummy, @Spacing, @Pixmap, @Mask) <> 0 863 then gtk_clist_set_pixtext(CListWidget, AIndex, ASubIndex, PChar(AText), Spacing, Pixmap, Mask) 864 else gtk_clist_set_text(CListWidget, AIndex, ASubIndex, PChar(AText)); 865 end; 866 Ord(GTK_CELL_PIXMAP): begin 867 if gtk_clist_get_pixmap(CListWidget, AIndex, ASubIndex, @Pixmap, @Mask) <> 0 868 then gtk_clist_set_pixtext(CListWidget, AIndex, ASubIndex, PChar(AText), DEFAULT_IMAGE_SPACING, Pixmap, Mask) 869 else gtk_clist_set_text(CListWidget, AIndex, ASubIndex, PChar(AText)); 870 end; 871 Ord(GTK_CELL_WIDGET): DebugLN('[TGtkWSCustomListView.ItemSetText] Setting text of widget cell'); 872 -1: DebugLN('[TGtkWSCustomListView.ItemSetText] Cell (%d,%d) not created', [AIndex, ASubIndex]); 873 else 874 DebugLN('[TGtkWSCustomListView.ItemSetText] Unknown celltype %d', [Ord(CellType)]); 875 end; 876end; 877 878class procedure TGtkWSCustomListView.ItemShow(const ALV: TCustomListView; const AIndex: Integer; const AItem: TListItem; const PartialOK: Boolean); 879var 880 WidgetInfo: PWidgetInfo; 881 CListWidget: PGtkCList; 882 RowTopY: Integer; 883begin 884 if not WSCheckHandleAllocated(ALV, 'ItemShow') 885 then Exit; 886 887 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 888 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 889 890 RowTopY := (CListWidget^.row_height * AIndex) + ((AIndex +1) * 891 {CELL} 1 {SPACING} + CListWidget^.voffset); 892 893 // 0=NotVisible 894 // 1=PartiallyVisible 895 // 2=Fully Visible 896 // | 897 if gtk_clist_row_is_visible(CListWidget, AIndex) < (2 - Ord(PartialOK)) then begin 898 if (RowTopY + CListWidget^.row_height > CListWidget^.clist_window_height) then begin 899 gtk_clist_moveto (CListWidget, AIndex, -1, 1, 0); 900 // | | | | 901 // The Row | | | 902 // The Column | | 903 // Row Align | 904 end // Column Align 905 else if (RowTopY < 0) then begin 906 gtk_clist_moveto (CListWidget, AIndex, -1, 0, 0); 907 end;// | 908 end; // | 909 // | 910 // 0 = your row will be at the top. 911 // 1 = it will be at the bottom. 912end; 913 914//////////////////////////////////////////////////////////////////////////////// 915// LV code 916//////////////////////////////////////////////////////////////////////////////// 917 918class function TGtkWSCustomListView.CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): HWND; 919var 920 ListView: TLVHack; //TCustomListView 921 WidgetInfo: PWidgetInfo; 922 ScrollingData: PBaseScrollingWinControlData; 923 ListViewData: PCustomListViewData; 924 925 ScrollWidget: PGtkScrolledWindow; 926 CListWidget: PGtkCList; 927begin 928 ListView := TLVHack(AWinControl as TCustomListView); 929 930 Result := TGtkWSBaseScrollingWinControl.CreateHandle(AWinControl, AParams); 931 if Result = 0 then Exit; 932 ScrollWidget := PGtkScrolledWindow(Result); 933 934 if ListView.ViewStyle = vsReport 935 then begin 936 // precreate colums since they cannot be added or removed 937 CListWidget := PGtkCList(gtk_clist_new(Max(1, ListView.Columns.Count))); 938 gtk_clist_column_titles_passive(CListWidget); 939 end 940 else begin 941 CListWidget := PGtkCList(gtk_clist_new(1)); 942 gtk_clist_column_titles_hide(CListWidget); 943 gtk_clist_set_column_auto_resize(CListWidget, 0, True); 944 end; 945 gtk_clist_set_shadow_type(CListWidget, GTK_SHADOW_IN); 946 947 gtk_container_add(PGtkContainer(ScrollWidget), PGtkWidget(CListWidget)); 948 949 gtk_widget_unset_flags(ScrollWidget^.hscrollbar, GTK_CAN_FOCUS); 950 gtk_widget_unset_flags(ScrollWidget^.vscrollbar, GTK_CAN_FOCUS); 951 gtk_scrolled_window_set_policy(ScrollWidget, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 952 // the next is not really needed since the container has only one child 953 gtk_container_set_focus_vadjustment(PGtkContainer(CListWidget), gtk_scrolled_window_get_vadjustment(ScrollWidget)); 954 gtk_container_set_focus_hadjustment(PGtkContainer(CListWidget), gtk_scrolled_window_get_hadjustment(ScrollWidget)); 955 gtk_widget_show_all(PGtkWidget(CListWidget)); 956 957 // create widget info 958 // already created in TGtkWSBaseScrollingWinControl 959 // Replace the ScrollingInfo with our info 960 WidgetInfo := GetWidgetInfo(ScrollWidget); 961 WidgetInfo^.CoreWidget := PGtkWidget(CListWidget); 962 ScrollingData := WidgetInfo^.UserData; 963 New(ListViewData); 964 ListViewData^.ScrollingData := ScrollingData^; 965 ListViewData^.ViewStyle := ListView.ViewStyle; 966 Dispose(ScrollingData); 967 WidgetInfo^.UserData := ListViewData; 968 //todo: obsolete 969 // SetMainWidget(ScrollWidget, CListWidget); 970 971 // set allocation 972 // already created in TGtkWSBaseScrollingWinControl 973 974 Set_RC_Name(AWinControl, PGtkWidget(ScrollWidget)); 975 SetListCallbacks(PGtkWidget(ScrollWidget), PGtkWidget(CListWidget), WidgetInfo); 976end; 977 978class procedure TGtkWSCustomListView.SetListCallbacks(const AScrollWidget, AListWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); 979begin 980 TGtkWSBaseScrollingWinControl.SetCallbacks(AScrollWidget, AWidgetInfo); 981 982 SignalConnect(AListWidget, 'click-column', @GtkWSCustomListView_ClickColumn, AWidgetInfo); 983 SignalConnect(AListWidget, 'resize-column', @GtkWSCustomListView_ResizeColumn, AWidgetInfo); 984 SignalConnect(AListWidget, 'abort-column-resize', @GtkWSCustomListView_AbortColumnResize, AWidgetInfo); 985 // SignalConnect(AListWidget, 'row-move', @GtkWSCustomListView_RowMove, AWidgetInfo); 986 SignalConnect(AListWidget, 'select-row', @GtkWSCustomListView_SelectRow, AWidgetInfo); 987 SignalConnect(AListWidget, 'unselect-row', @GtkWSCustomListView_UnSelectRow, AWidgetInfo); 988 SignalConnect(AListWidget, 'toggle-focus-row', @GtkWSCustomListView_ToggleFocusRow, AWidgetInfo); 989 SignalConnect(AListWidget, 'select-all', @GtkWSCustomListView_SelectAll, AWidgetInfo); 990 SignalConnect(AListWidget, 'unselect-all', @GtkWSCustomListView_UnSelectAll, AWidgetInfo); 991 SignalConnect(AListWidget, 'end-selection', @GtkWSCustomListView_EndSelection, AWidgetInfo); 992end; 993 994class procedure TGtkWSCustomListView.BeginUpdate(const ALV: TCustomListView); 995var 996 WidgetInfo: PWidgetInfo; 997 CListWidget: PGtkCList; 998begin 999 if not WSCheckHandleAllocated(ALV, 'BeginUpdate') 1000 then Exit; 1001 1002 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1003 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1004 1005 gtk_clist_freeze(CListWidget); 1006end; 1007 1008class procedure TGtkWSCustomListView.EndUpdate(const ALV: TCustomListView); 1009var 1010 WidgetInfo: PWidgetInfo; 1011 CListWidget: PGtkCList; 1012begin 1013 if not WSCheckHandleAllocated(ALV, 'EndUpdate') 1014 then Exit; 1015 1016 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1017 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1018 1019 gtk_clist_thaw(CListWidget); 1020end; 1021 1022class function TGtkWSCustomListView.GetBoundingRect(const ALV: TCustomListView): TRect; 1023var 1024 WidgetInfo: PWidgetInfo; 1025 CListWidget: PGtkCList; 1026begin 1027 Result:=Rect(0,0,0,0); 1028 if not WSCheckHandleAllocated(ALV, 'GetBoundingRect') 1029 then Exit; 1030 1031 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1032 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1033 if CListWidget=nil then exit; 1034 1035 1036 if TLVHack(ALV).ViewStyle in [vsIcon, vsSmallIcon] 1037 then begin 1038 // TODO: implement 1039 end 1040 else begin 1041 Result := Rect(0,0,0,0); 1042 end; 1043end; 1044 1045class function TGtkWSCustomListView.GetDropTarget(const ALV: TCustomListView): Integer; 1046var 1047 WidgetInfo: PWidgetInfo; 1048 CListWidget: PGtkCList; 1049begin 1050 Result:=0; 1051 if not WSCheckHandleAllocated(ALV, 'GetDropTarget') 1052 then Exit; 1053 1054 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1055 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1056 if CListWidget=nil then exit; 1057 1058 // TODO: implement 1059 Result := -1; 1060end; 1061 1062class function TGtkWSCustomListView.GetFocused(const ALV: TCustomListView): Integer; 1063var 1064 WidgetInfo: PWidgetInfo; 1065 CListWidget: PGtkCList; 1066begin 1067 if not WSCheckHandleAllocated(ALV, 'GetFocused') 1068 then Exit; 1069 1070 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1071 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1072 1073 Result := CListWidget^.focus_row; 1074end; 1075 1076class function TGtkWSCustomListView.GetHoverTime(const ALV: TCustomListView): Integer; 1077var 1078 WidgetInfo: PWidgetInfo; 1079 CListWidget: PGtkCList; 1080begin 1081 Result := -1; // = default 1082 if not WSCheckHandleAllocated(ALV, 'GetHoverTime') 1083 then Exit; 1084 1085 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1086 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1087 if CListWidget=nil then exit; 1088 1089 // TODO: implement 1090 Result := -1; // = default 1091end; 1092 1093class function TGtkWSCustomListView.GetItemAt(const ALV: TCustomListView; x, 1094 y: integer): Integer; 1095var 1096 WidgetInfo: PWidgetInfo; 1097 CListWidget: PGtkCList; 1098 I, FirstRowY, LastRowY: Integer; 1099 ScrolledTop: Integer; 1100 RowHeight: Integer; 1101 1102begin 1103 if not WSCheckHandleAllocated(ALV, 'GetItemAt') 1104 then Exit(-1); 1105 1106 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1107 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1108 1109 ScrolledTop := Trunc(CListWidget^.vadjustment^.value); 1110 1111 FirstRowY := ScrolledTop; 1112 1113 // For some reason the actual row height is one pixel more than the size it says 1114 RowHeight := CListWidget^.row_height+1; 1115 1116 Dec(y, CListWidget^.column_title_area.height); 1117 1118 LastRowY := FirstRowY + CListWidget^.clist_window_height; 1119 1120 Inc(y, ScrolledTop); 1121 1122 for I := FirstRowY div RowHeight to LastRowY div RowHeight do 1123 begin 1124 if I > CListWidget^.rows-1 then 1125 Exit; 1126 if (I * RowHeight < y) and ((I+1) * RowHeight >= y-1) then 1127 Exit(I); 1128 end; 1129end; 1130 1131class function TGtkWSCustomListView.GetSelCount(const ALV: TCustomListView): Integer; 1132var 1133 WidgetInfo: PWidgetInfo; 1134 CListWidget: PGtkCList; 1135begin 1136 if not WSCheckHandleAllocated(ALV, 'GetSelCount') 1137 then Exit; 1138 1139 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1140 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1141 1142 if CListWidget^.selection = nil 1143 then Result := 0 1144 else Result := g_list_length(CListWidget^.selection); 1145end; 1146 1147class function TGtkWSCustomListView.GetSelection(const ALV: TCustomListView): Integer; 1148var 1149 WidgetInfo: PWidgetInfo; 1150 CListWidget: PGtkCList; 1151begin 1152 if not WSCheckHandleAllocated(ALV, 'GetSelection') 1153 then Exit; 1154 1155 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1156 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1157 1158 if CListWidget^.selection = nil 1159 then Result := -1 1160 else Result := PtrUInt(CListWidget^.selection^.data) 1161end; 1162 1163class function TGtkWSCustomListView.GetTopItem(const ALV: TCustomListView): Integer; 1164var 1165 WidgetInfo: PWidgetInfo; 1166 CListWidget: PGtkCList; 1167begin 1168 if not WSCheckHandleAllocated(ALV, 'GetTopItem') 1169 then Exit; 1170 1171 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1172 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1173 1174 // Result := ROW_FROM_YPIXEL(0) 1175 // #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \ 1176 // ((clist)->row_height + CELL_SPACING)) 1177 1178 Result := -CListWidget^.voffset div (CListWidget^.row_height + 1); 1179end; 1180 1181class function TGtkWSCustomListView.GetViewOrigin(const ALV: TCustomListView): TPoint; 1182var 1183 WidgetInfo: PWidgetInfo; 1184 CListWidget: PGtkCList; 1185begin 1186 if not WSCheckHandleAllocated(ALV, 'GetViewOrigin') 1187 then Exit; 1188 1189 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1190 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1191 if CListWidget=nil then exit; 1192 1193 Result.X := Round(CListWidget^.hAdjustment^.value); 1194 Result.Y := Round(CListWidget^.vAdjustment^.value); 1195end; 1196 1197class function TGtkWSCustomListView.GetVisibleRowCount(const ALV: TCustomListView): Integer; 1198var 1199 WidgetInfo: PWidgetInfo; 1200 CListWidget: PGtkCList; 1201begin 1202 if not WSCheckHandleAllocated(ALV, 'GetVisibleRowCount') 1203 then Exit; 1204 1205 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1206 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1207 1208 Result := CListWidget^.clist_window_height div (CListWidget^.row_height + 1); 1209end; 1210 1211class procedure TGtkWSCustomListView.SetAllocBy(const ALV: TCustomListView; 1212 const AValue: Integer); 1213var 1214 WidgetInfo: PWidgetInfo; 1215 CListWidget: PGtkCList; 1216begin 1217 if not WSCheckHandleAllocated(ALV, 'SetAllocBy') 1218 then Exit; 1219 1220 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1221 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1222 if CListWidget=nil then exit; 1223 // TODO: implement ? 1224end; 1225 1226class procedure TGtkWSCustomListView.SetDefaultItemHeight(const ALV: TCustomListView; 1227 const AValue: Integer); 1228var 1229 WidgetInfo: PWidgetInfo; 1230 CListWidget: PGtkCList; 1231const 1232 GTK_CLIST_ROW_HEIGHT_SET = 1 shl 1; 1233begin 1234 if not WSCheckHandleAllocated(ALV, 'SetDefaultItemHeight') 1235 then Exit; 1236 1237 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1238 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1239 1240 if (AValue = 0) and (CListWidget^.flags and GTK_CLIST_ROW_HEIGHT_SET = 0) then 1241 exit; 1242 gtk_clist_set_row_height(CListWidget, AValue); 1243end; 1244 1245class procedure TGtkWSCustomListView.SetHotTrackStyles(const ALV: TCustomListView; 1246 const AValue: TListHotTrackStyles); 1247var 1248 WidgetInfo: PWidgetInfo; 1249 CListWidget: PGtkCList; 1250begin 1251 if not WSCheckHandleAllocated(ALV, 'SetHotTrackStyles') 1252 then Exit; 1253 1254 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1255 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1256 1257 if CListWidget=nil then exit; 1258 // TODO: implement ? 1259end; 1260 1261class procedure TGtkWSCustomListView.SetHoverTime(const ALV: TCustomListView; 1262 const AValue: Integer); 1263var 1264 WidgetInfo: PWidgetInfo; 1265 CListWidget: PGtkCList; 1266begin 1267 if not WSCheckHandleAllocated(ALV, 'SetHoverTime') 1268 then Exit; 1269 1270 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1271 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1272 1273 if CListWidget=nil then exit; 1274 // TODO: implement ? 1275end; 1276 1277class procedure TGtkWSCustomListView.SetImageList(const ALV: TCustomListView; 1278 const AList: TListViewImageList; const AValue: TCustomImageListResolution); 1279var 1280 WidgetInfo: PWidgetInfo; 1281 CListWidget: PGtkCList; 1282begin 1283 if not WSCheckHandleAllocated(ALV, 'SetImageList') 1284 then Exit; 1285 1286 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1287 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1288 1289 if CListWidget=nil then exit; 1290 // TODO: implement 1291end; 1292 1293class procedure TGtkWSCustomListView.SetPropertyInternal( 1294 const ACListWidget: PGtkCList; const AInfo: PWidgetInfo; 1295 const AProp: TListViewProperty; const AIsSet: Boolean); 1296var 1297 ListViewData: PCustomListViewData; 1298begin 1299 case AProp of 1300 lvpAutoArrange: begin 1301 // TODO: implement ?? 1302 end; 1303 lvpCheckboxes: begin 1304 // TODO: implement 1305 end; 1306 lvpColumnClick: begin 1307 // allow only column modifications when in report mode 1308 ListViewData := AInfo^.UserData; 1309 if ListViewData^.ViewStyle <> vsReport then Exit; 1310 1311 if AIsSet 1312 then gtk_clist_column_titles_active(ACListWidget) 1313 else gtk_clist_column_titles_passive(ACListWidget); 1314 end; 1315 lvpFlatScrollBars: begin 1316 // TODO: implement ?? 1317 end; 1318 lvpFullDrag: begin 1319 // TODO: implement ?? 1320 end; 1321 lvpGridLines: begin 1322 // TODO: implement 1323 // maybe possible with some cellwidget hacking 1324 end; 1325 lvpHideSelection: begin 1326 // TODO: implement 1327 // should be possible with some focus in/out events 1328 end; 1329 lvpHotTrack: begin 1330 // TODO: implement 1331 // should be possible with some mouse tracking 1332 end; 1333 lvpMultiSelect: begin 1334 if AIsSet 1335 then gtk_clist_set_selection_mode(ACListWidget, GTK_SELECTION_EXTENDED) 1336 else gtk_clist_set_selection_mode(ACListWidget, GTK_SELECTION_BROWSE); 1337 end; 1338 lvpOwnerDraw: begin 1339 // TODO: implement 1340 // use custom images/widgets ? 1341 end; 1342 lvpReadOnly: begin 1343 // TODO: implement inline editor ? 1344 end; 1345 lvpRowSelect: begin 1346 // TODO: implement ??? 1347 // how to do cell select 1348 end; 1349 lvpShowColumnHeaders: begin 1350 // allow only column modifications when in report mode 1351 ListViewData := AInfo^.UserData; 1352 if ListViewData^.ViewStyle <> vsReport then Exit; 1353 1354 if AIsSet 1355 then gtk_clist_column_titles_show(ACListWidget) 1356 else gtk_clist_column_titles_hide(ACListWidget); 1357 end; 1358 lvpShowWorkAreas: begin 1359 // TODO: implement ??? 1360 end; 1361 lvpWrapText: begin 1362 // TODO: implement ??? 1363 end; 1364 end; 1365end; 1366 1367class procedure TGtkWSCustomListView.SetProperty(const ALV: TCustomListView; 1368 const AProp: TListViewProperty; const AIsSet: Boolean); 1369var 1370 WidgetInfo: PWidgetInfo; 1371 CListWidget: PGtkCList; 1372begin 1373 if not WSCheckHandleAllocated(ALV, 'SetProperty') 1374 then Exit; 1375 1376 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1377 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1378 1379 SetPropertyInternal(CListWidget, WidgetInfo, AProp, AIsSet); 1380end; 1381 1382class procedure TGtkWSCustomListView.SetProperties(const ALV: TCustomListView; const AProps: TListViewProperties); 1383var 1384 WidgetInfo: PWidgetInfo; 1385 CListWidget: PGtkCList; 1386 Prop: TListViewProperty; 1387begin 1388 if not WSCheckHandleAllocated(ALV, 'SetProperties') 1389 then Exit; 1390 1391 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1392 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1393 1394 for Prop := Low(TListViewProperty) to High(TListViewProperty) do 1395 SetPropertyInternal(CListWidget, WidgetInfo, Prop, Prop in AProps); 1396end; 1397 1398class procedure TGtkWSCustomListView.SetScrollBars(const ALV: TCustomListView; const AValue: TScrollStyle); 1399var 1400 ScrollWidget: PGtkScrolledWindow; 1401 hPolicy, vPolicy: TGtkPolicyType; 1402begin 1403 if not WSCheckHandleAllocated(ALV, 'SetScrollBars') 1404 then Exit; 1405 1406 ScrollWidget := PGtkScrolledWindow(ALV.Handle); 1407 1408 case AValue of 1409 ssHorizontal, ssBoth: hPolicy := GTK_POLICY_ALWAYS; 1410 ssAutoHorizontal, ssAutoBoth: hPolicy := GTK_POLICY_AUTOMATIC; 1411 else 1412 hPolicy := GTK_POLICY_NEVER; 1413 end; 1414 1415 case AValue of 1416 ssVertical, ssBoth: vPolicy := GTK_POLICY_ALWAYS; 1417 ssAutoVertical, ssAutoBoth: vPolicy := GTK_POLICY_AUTOMATIC; 1418 else 1419 vPolicy := GTK_POLICY_NEVER; 1420 end; 1421 1422 gtk_scrolled_window_set_policy(ScrollWidget, hPolicy, vPolicy); 1423end; 1424 1425class procedure TGtkWSCustomListView.SetSort(const ALV: TCustomListView; 1426 const AType: TSortType; const AColumn: Integer; 1427 const ASortDirection: TSortDirection); 1428var 1429 WidgetInfo: PWidgetInfo; 1430 CListWidget: PGtkCList; 1431begin 1432 if not WSCheckHandleAllocated(ALV, 'SetSort') 1433 then Exit; 1434 1435 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1436 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1437 1438 if CListWidget=nil then exit; 1439 // TODO implement 1440end; 1441 1442class procedure TGtkWSCustomListView.SetViewOrigin(const ALV: TCustomListView; const AValue: TPoint); 1443var 1444 WidgetInfo: PWidgetInfo; 1445 CListWidget: PGtkCList; 1446begin 1447 if not WSCheckHandleAllocated(ALV, 'SetViewOrigin') 1448 then Exit; 1449 1450 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1451 CListWidget := PGtkCList(WidgetInfo^.CoreWidget); 1452 if CListWidget=nil then exit; 1453 1454 gtk_adjustment_set_value(CListWidget^.hAdjustment, AValue.X); 1455 gtk_adjustment_set_value(CListWidget^.vAdjustment, AValue.Y); 1456end; 1457 1458class procedure TGtkWSCustomListView.SetViewStyle(const ALV: TCustomListView; const Avalue: TViewStyle); 1459var 1460 WidgetInfo: PWidgetInfo; 1461 ListViewData: PCustomListViewData; 1462begin 1463 if not WSCheckHandleAllocated(ALV, 'SetViewStyle') 1464 then Exit; 1465 1466 1467 WidgetInfo := GetWidgetInfo(Pointer(ALV.Handle)); 1468 ListViewData := WidgetInfo^.UserData; 1469 if ListViewData^.ViewStyle = AValue then Exit; // nothing to do 1470 1471 // We cannot change columns or viewstyle so we need to recreate 1472 RecreateWnd(ALV); 1473end; 1474 1475