lazarus/lcl/interfaces/gtk3/gtk3cellrenderer.pas
2013-10-11 08:17:51 +00:00

768 lines
29 KiB
ObjectPascal

{
*****************************************************************************
* Gtk3CellRenderer.pas *
* -------------------- *
* *
* *
*****************************************************************************
*****************************************************************************
This file is part of the Lazarus Component Library (LCL)
See the file COPYING.modifiedLGPL.txt, included in this distribution,
for details about the license.
*****************************************************************************
An extended gtk_cell_renderer, to provide hooks for the LCL.
For example for custom drawing.
}
unit Gtk3CellRenderer;
{$mode objfpc}{$H+}
{$i gtk3defines.inc}
interface
uses
Classes, SysUtils, LCLType, LCLProc, Controls, StdCtrls, ComCtrls, LMessages,
LazGObject2, LazGtk3, LazGdk3, LazGLib2, Gtk3Procs, LazCairo1;
type
PLCLIntfCellRenderer = ^TLCLIntfCellRenderer;
TLCLIntfCellRenderer = record
// ! the TextRenderer must be the first attribute of this record !
TextRenderer: TGtkCellRendererText;
Index: integer;
ColumnIndex: Integer; // for TListView
end;
PLCLIntfCellRendererClass = ^TLCLIntfCellRendererClass;
TLCLIntfCellRendererClass = object
// ParentClass: TGInitiallyUnowned;
ParentClass: TGtkCellRendererTextClass;
DefaultGetRequestMode: function(cell: PGtkCellRenderer): TGtkSizeRequestMode; cdecl;
DefaultGetPreferredWidth: procedure (cell: PGtkCellRenderer; widget: PGtkWidget; minimum_size: Pgint; natural_size: Pgint); cdecl;
DefaultGetPreferredHeightForWidth: procedure(cell: PGtkCellRenderer; widget: PGtkWidget; width: gint; minimum_height: Pgint; natural_height: Pgint); cdecl;
DefaultGetPreferredHeight: procedure (cell: PGtkCellRenderer; widget: PGtkWidget; minimum_size: Pgint; natural_size: Pgint); cdecl;
DefaultGetPreferredWidthForHeight: procedure(cell: PGtkCellRenderer; widget: PGtkWidget; height: gint; minimum_width: Pgint; natural_width: Pgint); cdecl;
DefaultGetAlignedArea: procedure(cell: PGtkCellRenderer; widget: PGtkWidget; flags: TGtkCellRendererState; cell_area: PGdkRectangle; aligned_area: PGdkRectangle); cdecl;
DefaultGtkGetSize: procedure(cell: PGtkCellRenderer;
widget: PGtkWidget;
cell_area: PGdkRectangle;
x_offset: pgint;
y_offset: pgint;
width: pgint;
height: pgint); cdecl;
DefaultGtkRender: procedure(cell: PGtkCellRenderer;
cr: Pcairo_t;
widget: PGtkWidget;
background_area: PGdkRectangle;
cell_area: PGdkRectangle;
flags: TGtkCellRendererState); cdecl;
activate: function (cell: PGtkCellRenderer; event: PGdkEvent; widget: PGtkWidget;
path: PgChar; bg_area: PGdkRectangle; cell_area: PGdkRectangle;
flags: TGtkCellRendererState): GBoolean; cdecl;
start_editing: function(cell: PGtkCellRenderer; event: PGdkEvent; widget: PGtkWidget;
path: PgChar; bg_area: PGdkRectangle; cell_area: PGdkRectangle; flags: TGtkCellRendererState): PGtkCellEditable; cdecl;
editing_canceled: procedure(cell: PGtkCellRenderer); cdecl;
editing_started: procedure(cell: PGtkCellRenderer; editable: PGtkCellEditable; path: pgChar); cdecl;
priv: PGtkCellRendererClassPrivate;
_gtk_reserved2: procedure(); cdecl;
_gtk_reserved3: procedure(); cdecl;
_gtk_reserved4: procedure(); cdecl;
end;
function LCLIntfCellRenderer_GetType: TGType;
function LCLIntfCellRenderer_New: PGtkCellRenderer;
procedure LCLIntfCellRenderer_CellDataFunc(cell_layout:PGtkCellLayout;
cell: PGtkCellRenderer;
tree_model: PGtkTreeModel;
iter: PGtkTreeIter;
data: gpointer); cdecl;
procedure LCLIntfRenderer_ColumnCellDataFunc(tree_column: PGtkTreeViewColumn;
cell: PGtkCellRenderer;
tree_model: PGtkTreeModel;
iter: PGtkTreeIter;
data: gpointer); cdecl;
procedure LCLIntfRenderer_GtkCellLayoutDataFunc(cell_layout: PGtkCellLayout; cell: PGtkCellRenderer; tree_model: PGtkTreeModel; iter: PGtkTreeIter; data: gpointer); cdecl;
implementation
uses gtk3widgets, gtk3int;
type
TCustomListViewAccess = class(TCustomListView);
function GetControl(cell: PGtkCellRenderer; Widget: PGtkWidget): TWinControl;
var
AHWND: HWND;
AWidget: PGtkWidget;
begin
Result := nil;
AHWND := HwndFromGtkWidget(Widget);
if AHWND = 0 then
begin
AWidget := Widget^.get_parent;
while (AWidget <> nil) do
begin
AHWND := HwndFromGtkWidget(AWidget);
if AHWND <> 0 then
break;
AWidget := AWidget^.get_parent;
end;
end;
if AHWND <> 0 then
Result := TGtk3Widget(AHWND).LCLObject;
end;
function GetItemIndex(cell: PLCLIntfCellRenderer; {%H-}widget: PGtkWidget): Integer;
begin
Result := cell^.Index;
end;
function LCLIntfCellRenderer_GetRequestMode(cell: PGtkCellRenderer): TGtkSizeRequestMode; cdecl;
var
CellClass: PLCLIntfCellRendererClass;
begin
{$IFDEF GTK3DEBUGCELLRENDERER}
DebugLn('*** LCLIntfCellRenderer_GetRequestMode ***');
{$ENDIF}
CellClass := PLCLIntfCellRendererClass(cell^.g_type_instance.g_class);
// CellClass := PLCLIntfCellRendererClass(gtk_object_get_class(cell));
Result := CellClass^.DefaultGetRequestMode(cell);
end;
procedure LCLIntfCellRenderer_GetAlignedArea(cell: PGtkCellRenderer; widget: PGtkWidget;
flags: TGtkCellRendererState; cell_area: PGdkRectangle; aligned_area: PGdkRectangle); cdecl;
var
CellClass: PLCLIntfCellRendererClass;
AWinControl: TWinControl;
ItemIndex: Integer;
Msg: TLMMeasureItem;
MeasureItemStruct: TMeasureItemStruct;
Requisition, NaturalSize: TGtkRequisition;
AMinHeight, ANaturalHeight: gint;
Value: TGValue;
R1, R2: TGdkRectangle;
begin
{$IFDEF GTK3DEBUGCELLRENDERER}
// DebugLn('*** LCLIntfCellRenderer_GetAlignedArea ***');
{$ENDIF}
CellClass := PLCLIntfCellRendererClass(cell^.g_type_instance.g_class);
CellClass^.DefaultGetAlignedArea(cell, widget, flags, cell_area, aligned_area);
// this does not work too....
exit;
R1 := cell_area^;
R2 := aligned_area^;
CellClass^.DefaultGetAlignedArea(cell, widget, flags, @R1, @R2);
cell_area^ := R1;
aligned_area^ := R2;
// DebugLn('Cell_Area ',dbgs(RectFromGdkRect(cell_area^)),' Aligned_Area ',dbgs(RectFromGdkRect(aligned_area^)));
// cell^.get_preferred_size(Widget, @AMinSize, @ANatSize);
AWinControl := GetControl(cell, widget);
if [csDestroying,csLoading]*AWinControl.ComponentState<>[] then exit;
if AWinControl is TCustomListbox then
if TCustomListbox(AWinControl).Style < lbOwnerDrawFixed then
exit;
if AWinControl is TCustomCombobox then
if TCustomCombobox(AWinControl).Style < csOwnerDrawVariable then
exit;
ItemIndex := GetItemIndex(PLCLIntfCellRenderer(cell), Widget);
if ItemIndex < 0 then
ItemIndex := 0;
MeasureItemStruct.itemID := UINT(ItemIndex);
MeasureItemStruct.itemWidth := UINT(aligned_area^.width);
MeasureItemStruct.itemHeight := UINT(aligned_area^.height);
Msg.Msg := LM_MEASUREITEM;
Msg.MeasureItemStruct := @MeasureItemStruct;
TGtk3Widget(AWinControl.Handle).DeliverMessage(Msg);
{here we cheat cell renderer to paint eg. height 1 }
aligned_area^.height := gint(MeasureItemStruct.itemHeight);
cell_area^.height := gint(MeasureItemStruct.itemHeight);
DebugLn('**** Cell_Area ',dbgs(RectFromGdkRect(cell_area^)),' Aligned_Area ',dbgs(RectFromGdkRect(aligned_area^)));
end;
// get_preferred_width: procedure(cell: PGtkCellRenderer; widget: PGtkWidget; minimum_size: Pgint; natural_size: Pgint); cdecl;
procedure LCLIntfCellRenderer_GetPreferredWidth(cell: PGtkCellRenderer; widget: PGtkWidget; minimum_size: Pgint; natural_size: Pgint); cdecl;
var
CellClass: PLCLIntfCellRendererClass;
begin
{$IFDEF GTK3DEBUGCELLRENDERER}
DebugLn('*** LCLIntfCellRenderer_GetPreferredWidth ***');
{$ENDIF}
CellClass := PLCLIntfCellRendererClass(cell^.g_type_instance.g_class);
CellClass^.DefaultGetPreferredWidth(cell, widget, minimum_size, natural_size);
{$IFDEF GTK3DEBUGCELLRENDERER}
// DebugLn('*** LCLIntfCellRenderer_GetPreferredWidth MIN=',dbgs(minimum_size^),' naturalw=',dbgs(natural_size^));
{$ENDIF}
end;
procedure LCLIntfCellRenderer_GetPreferredHeight(cell: PGtkCellRenderer; widget: PGtkWidget; minimum_size: Pgint; natural_size: Pgint); cdecl;
var
CellClass: PLCLIntfCellRendererClass;
begin
// it's never called ?!?
{$IFDEF GTK3DEBUGCELLRENDERER}
DebugLn('*** LCLIntfCellRenderer_GetPreferredHeight ***');
{$ENDIF}
CellClass := PLCLIntfCellRendererClass(cell^.g_type_instance.g_class);
CellClass^.DefaultGetPreferredHeight(cell, widget, minimum_size, natural_size);
end;
procedure LCLIntfCellRenderer_GetPreferredWidthForHeight(cell: PGtkCellRenderer; widget: PGtkWidget;
height: gint; minimum_width: Pgint; natural_width: Pgint); cdecl;
var
CellClass: PLCLIntfCellRendererClass;
begin
{$IFDEF GTK3DEBUGCELLRENDERER}
DebugLn('*** LCLIntfCellRenderer_GetPreferredWidthForHeight ***');
{$ENDIF}
CellClass := PLCLIntfCellRendererClass(cell^.g_type_instance.g_class);
CellClass^.DefaultGetPreferredWidthForHeight(cell, widget, height, minimum_width, natural_width);
end;
procedure LCLIntfCellRenderer_GetPreferredHeightForWidth(cell: PGtkCellRenderer; widget: PGtkWidget;
width: gint; minimum_height: Pgint; natural_height: Pgint); cdecl;
var
CellClass: PLCLIntfCellRendererClass;
AWinControl: TWinControl;
ItemIndex: Integer;
Msg: TLMMeasureItem;
MeasureItemStruct: TMeasureItemStruct;
//Requisition, NaturalSize: TGtkRequisition;
AMinHeight, ANaturalHeight: gint;
Value: TGValue;
begin
{$IFDEF GTK3DEBUGCELLRENDERER}
DebugLn('*** LCLIntfCellRenderer_GetPreferredHeightForWidth *** width=',dbgs(Width));
// ,' min ',dbgs(minimum_height^),' natural ',dbgs(natural_height^));
{$ENDIF}
CellClass := PLCLIntfCellRendererClass(cell^.g_type_instance.g_class);
if (minimum_height = nil) or (natural_height = nil) then
begin
// CellClass^.DefaultGetPreferredHeightForWidth(cell, widget, width, @AMinHeight, @ANaturalHeight);
// exit;
end;
CellClass^.DefaultGetPreferredHeightForWidth(cell, widget, width, minimum_height, natural_height);
if minimum_height <> nil then
AMinHeight := minimum_height^
else
AMinHeight := 0;
if natural_height <> nil then
ANaturalHeight := natural_height^
else
ANaturalHeight := 0;
// writeln('1.minimumheight ',AMinHeight,' naturalheight ',ANaturalHeight,' min ',dbgs(minimum_height <> nil),' nat ',dbgs(natural_height <> nil));
AWinControl := GetControl(cell, widget);
if [csDestroying,csLoading]*AWinControl.ComponentState<>[] then exit;
if AWinControl is TCustomListbox then
if TCustomListbox(AWinControl).Style < lbOwnerDrawFixed then
exit;
if AWinControl is TCustomCombobox then
if TCustomCombobox(AWinControl).Style < csOwnerDrawVariable then
exit;
ItemIndex := GetItemIndex(PLCLIntfCellRenderer(cell), Widget);
if ItemIndex < 0 then
ItemIndex := 0;
MeasureItemStruct.itemID := UINT(ItemIndex);
MeasureItemStruct.itemWidth := UINT(width);
MeasureItemStruct.itemHeight := UINT(AMinHeight);
Msg.Msg := LM_MEASUREITEM;
Msg.MeasureItemStruct := @MeasureItemStruct;
TGtk3Widget(AWinControl.Handle).DeliverMessage(Msg);
if minimum_height <> nil then
minimum_height^ := gint(MeasureItemStruct.itemHeight);
if natural_height <> nil then
natural_height^ := gint(MeasureItemStruct.itemHeight);
// writeln('Final cell height ',MeasureItemStruct.itemHeight);
end;
procedure LCLIntfCellRenderer_GetSize(cell: PGtkCellRenderer; widget: PGtkWidget;
cell_area: PGdkRectangle; x_offset: Pgint;
y_offset: Pgint; width: Pgint; height: Pgint); cdecl;
var
CellClass: PLCLIntfCellRendererClass;
AWinControl: TWinControl;
ItemIndex: Integer;
Msg: TLMMeasureItem;
MeasureItemStruct: TMeasureItemStruct;
begin
// THIS DOES NOT WORK IN Gtk3 ANYMORE.
{$IFDEF GTK3DEBUGCELLRENDERER}
DebugLn('******* LCLIntfCellRenderer_GetSize ********');
{$ENDIF}
CellClass := PLCLIntfCellRendererClass(cell^.g_type_instance.g_class);
// CellClass := PLCLIntfCellRendererClass(gtk_object_get_class(cell));
CellClass^.DefaultGtkGetSize(cell, Widget, cell_area, x_offset, y_offset,
width, height);
//DebugLn(['LCLIntfCellRenderer_GetSize ',GetWidgetDebugReport(Widget)]);
AWinControl := GetControl(cell, widget);
if [csDestroying,csLoading]*AWinControl.ComponentState<>[] then exit;
if AWinControl is TCustomListbox then
if TCustomListbox(AWinControl).Style < lbOwnerDrawFixed then
exit;
if AWinControl is TCustomCombobox then
if TCustomCombobox(AWinControl).Style < csOwnerDrawVariable then
exit;
ItemIndex := GetItemIndex(PLCLIntfCellRenderer(cell), Widget);
if ItemIndex < 0 then
ItemIndex := 0;
MeasureItemStruct.itemID := UINT(ItemIndex);
MeasureItemStruct.itemWidth := UINT(width^);
MeasureItemStruct.itemHeight := UINT(height^);
Msg.Msg := LM_MEASUREITEM;
Msg.MeasureItemStruct := @MeasureItemStruct;
TGtk3Widget(AWinControl.Handle).DeliverMessage(Msg);
width^ := gint(MeasureItemStruct.itemWidth);
height^ := gint(MeasureItemStruct.itemHeight);
end;
function GtkCellRendererStateToListViewDrawState(CellState: TGtkCellRendererState): TCustomDrawState;
begin
Result := [];
if CellState and GTK_CELL_RENDERER_SELECTED > 0 then Result := Result + [cdsSelected];
if CellState and GTK_CELL_RENDERER_PRELIT > 0 then Result := Result + [cdsHot];
if CellState and GTK_CELL_RENDERER_INSENSITIVE > 0 then Result := Result + [cdsDisabled, cdsGrayed];
if CellState and GTK_CELL_RENDERER_FOCUSED > 0 then Result := Result + [cdsFocused];
end;
procedure LCLIntfCellRenderer_Render(cell: PGtkCellRenderer; cr: Pcairo_t;
Widget: PGtkWidget; background_area: PGdkRectangle; cell_area: PGdkRectangle;
flags: TGtkCellRendererState); cdecl;
var
CellClass: PLCLIntfCellRendererClass;
AWinControl: TWinControl;
ItemIndex: Integer;
ColumnIndex: Integer;
AreaRect: TRect;
State: TOwnerDrawState;
Msg: TLMDrawListItem;
DCWidget: PGtkWidget;
LVTarget: TCustomDrawTarget;
LVStage: TCustomDrawStage;
LVState: TCustomDrawState;
LVSubItem: Integer;
TmpDC1,
TmpDC2: HDC;
SkipDefaultPaint: Boolean;
begin
// DebugLn('*** LCLIntfCellRenderer_Render widget=',dbgHex(PtrUInt(Widget)), ' HWND=',dbgs(HwndFromGtkWidget(Widget)));
{DebugLn(['LCLIntfCellRenderer_Render cell=',dbgs(cell),
' ',GetWidgetDebugReport(Widget),' ',
' background_area=',dbgGRect(background_area),
' cell_area=',dbgGRect(cell_area),
' expose_area=',dbgGRect(expose_area)]);}
ColumnIndex := PLCLIntfCellRenderer(cell)^.ColumnIndex;
AWinControl := GetControl(cell, widget);
if (ColumnIndex = -1) and (AWinControl <> nil) and
(AWinControl.FCompStyle = csListView) then
ColumnIndex := 0;
(* debugging
if Assigned(AWinControl) then
begin
DebugLn('*** LCLIntfCellRenderer_Render ',dbgsName(AWinControl),' ColIndex ',dbgs(ColumnIndex));
if Widget = TGtk3Widget(AWinControl.Handle).Widget then
DebugLn(' MAIN WIDGET ...')
else
if Widget = TGtk3Widget(AWinControl.Handle).GetContainerWidget then
begin
DebugLn(' CONTAINER WIDGET ... OK ');
if wtListBox in TGtk3Widget(AWinControl.Handle).WidgetType then
ColumnIndex := -1;
if TGtk3Widget(AWinControl.Handle).Context <> 0 then
DebugLn(' CONTAINER WIDGET ... HAVE CONTEXT !!!!! ');
end
else
begin
DebugLn(' FATAL ERROR DONT KNOW WHAT WIDGET IS THIS !');
if Widget^.parent = TGtk3Widget(AWinControl.Handle).Widget then
DebugLn(' BUT PARENT IS MAIN WIDGET !')
else
if Widget^.parent = TGtk3Widget(AWinControl.Handle).GetContainerWidget then
begin
DebugLn(' BUT PARENT IS CONTAINER WIDGET ! CellView=',dbgs(Gtk3IsCellView(Widget)),' w=',dbgHex(PtrUInt(Widget)));
if Gtk3IsCellView(Widget) then
begin
DebugLn(' *** check=', dbgHex(PtrUInt(g_object_get_data(Widget, 'lclwidget'))));
end;
end;
end;
end;
*)
if ColumnIndex > -1 then // listview
begin
// DebugLn('Paint 1 ', dbgsName(AWinControl));
AreaRect := Bounds(background_area^.x, background_area^.y,
background_area^.Width, background_area^.Height);
ItemIndex := GetItemIndex(PLCLIntfCellRenderer(cell), Widget);
if ItemIndex < 0 then
ItemIndex := 0;
if ColumnIndex > 0 then
LVTarget := dtSubItem
else
LVTarget := dtItem;
if AWinControl.FCompStyle = csListView then
LVSubItem := ColumnIndex
else
LVSubItem := ColumnIndex - 1;
LVStage := cdPrePaint;
LVState := GtkCellRendererStateToListViewDrawState(flags);
DCWidget := Widget;
TmpDC1 := Gtk3WidgetSet.CreateDCForWidget(DCWidget, nil, cr);
TmpDC2 := TCustomListViewAccess(AWinControl).Canvas.Handle;
TCustomListViewAccess(AWinControl).Canvas.Handle := TmpDC1;
// paint
SkipDefaultPaint := cdrSkipDefault in TCustomListViewAccess(AWinControl).IntfCustomDraw(LVTarget, LVStage, ItemIndex, LVSubItem, LVState, @AreaRect);
if SkipDefaultPaint then
begin
Gtk3WidgetSet.ReleaseDC(TCustomListViewAccess(AWinControl).Handle,TmpDC1);
TCustomListViewAccess(AWinControl).Canvas.Handle := TmpDC2;
Exit;
end;
end;
// draw default
// CellClass := PLCLIntfCellRendererClass(gtk_object_get_class(cell));
CellClass := PLCLIntfCellRendererClass(cell^.g_type_instance.g_class);
// do not call DefaultGtkRender when we are custom drawn listbox.issue #23093
if (ColumnIndex < 0) and Assigned(AWinControl) then
begin
if ([csDestroying,csLoading,csDesigning]*AWinControl.ComponentState<>[]) then
AWinControl := nil;
if AWinControl is TCustomListbox then
if TCustomListbox(AWinControl).Style = lbStandard then
AWinControl := nil;
if AWinControl is TCustomCombobox then
AWinControl := nil;
end;
// do default draw only if we are not customdrawn.
if (ColumnIndex > -1) or ((ColumnIndex < 0) and (AWinControl = nil)) then
begin
CellClass^.DefaultGtkRender(cell, cr, Widget, background_area, cell_area,
flags);
end;
if ColumnIndex < 0 then // is a listbox or combobox
begin
// send LM_DrawListItem message
AWinControl := GetControl(cell, widget);
// DebugLn('Paint 2 ** ', dbgsName(AWinControl));
if not Assigned(AWinControl) then
begin
// DebugLn('Paint 2 ** EXIT ! NO WINCONTROL .... ',dbgHex(PtrUInt(Widget)));
exit;
end;
if [csDestroying,csLoading]*AWinControl.ComponentState<>[] then exit;
// check if the LCL object wants item paint messages
if AWinControl is TCustomListbox then
if TCustomListbox(AWinControl).Style = lbStandard then
exit;
if AWinControl is TCustomCombobox then
if TCustomCombobox(AWinControl).Style < csOwnerDrawFixed then
exit;
// get itemindex and area
AreaRect := Bounds(background_area^.x, background_area^.y,
background_area^.Width, background_area^.Height);
ItemIndex := GetItemIndex(PLCLIntfCellRenderer(cell), Widget);
if ItemIndex < 0 then
ItemIndex := 0;
// collect state flags
State:=[odPainted];
if (flags and GTK_CELL_RENDERER_SELECTED)>0 then
Include(State, odSelected);
if not Widget^.is_sensitive then
Include(State, odInactive);
if Widget^.has_default then
Include(State, odDefault);
if (flags and GTK_CELL_RENDERER_FOCUSED) <> 0 then
Include(State, odFocused);
if AWinControl is TCustomCombobox then
begin
if TCustomComboBox(AWinControl).DroppedDown and ((flags and GTK_CELL_RENDERER_PRELIT)>0) then
Include(State,odSelected);
end;
end else // is a listview
begin
LVStage := cdPostPaint;
// paint
TCustomListViewAccess(AWinControl).IntfCustomDraw(LVTarget, LVStage, ItemIndex, LVSubItem, LVState, @AreaRect);
TCustomListViewAccess(AWinControl).Canvas.Handle := TmpDC2;
Gtk3WidgetSet.ReleaseDC(TCustomListViewAccess(AWinControl).Handle,TmpDC1);
Exit;
end;
// ListBox and ComboBox
// create message and deliverFillChar(Msg,SizeOf(Msg),0);
// DebugLn('Paint 4 listbox or combobox ** ', dbgsName(AWinControl));
Msg.Msg:=LM_DrawListItem;
New(Msg.DrawListItemStruct);
try
FillChar(Msg.DrawListItemStruct^,SizeOf(TDrawListItemStruct),0);
with Msg.DrawListItemStruct^ do
begin
ItemID := UINT(ItemIndex);
Area := AreaRect;
(*
DebugLn('LCLIntfCellRenderer_Render Widget is: TGtk3Widget.Widget ? ',dbgs(Widget = TGtk3Widget(AWinControl.Handle).Widget),
' ContainerWidget ? ',dbgs(Widget = TGtk3Widget(AWinControl.Handle).GetContainerWidget),
' CAIRO ?!? ',dbgHex(PtrUInt(cr)),' AreaR ',dbgs(Area),' AreaH ',dbgs(Area.Bottom - Area.Top));
*)
DCWidget := Widget;
if (DCWidget^.parent<>nil) and
Gtk3IsMenuItem(DCWidget^.parent) then
begin
// the Widget is a sub widget of a menu item
// -> allow the LCL to paint over the whole menu item
DCWidget := DCWidget^.parent;
Area := Rect(0,0,DCWidget^.get_allocated_width,DCWidget^.get_allocated_height);
end;
DC := GTK3WidgetSet.CreateDCForWidget(DCWidget, nil, cr);
ItemState:=State;
end;
TGtk3Widget(AWinControl.Handle).DeliverMessage(Msg);
GTK3WidgetSet.ReleaseDC(AWinControl.Handle,Msg.DrawListItemStruct^.DC);
finally
Dispose(Msg.DrawListItemStruct);
end;
//DebugLn(['LCLIntfCellRenderer_Render END ',DbgSName(LCLObject)]);
end;
procedure LCLIntfCellRenderer_ClassInit(aClass: gpointer; class_data: gpointer); cdecl;
//aClass: PLCLIntfCellRendererClass
var
LCLClass: PLCLIntfCellRendererClass;
RendererClass: PGtkCellRendererClass;
begin
//DebugLn(['LCLIntfCellRenderer_ClassInit ']);
LCLClass := PLCLIntfCellRendererClass(aClass);
// check ok
// PLCLIntfCellRendererClass(g_type_check_class_cast(aClass, LCLIntfCellRenderer_GetType));
// PLCLIntfCellRendererClass(aClass);
RendererClass := PGtkCellRendererClass(aClass);
// check ok
// RendererClass := PGtkCellRendererClass(g_type_check_class_cast(aClass, gtk_cell_renderer_text_get_type));
// GTK_CELL_RENDERER_CLASS(aClass);
LCLClass^.DefaultGetAlignedArea := RendererClass^.get_aligned_area;
LCLClass^.DefaultGtkGetSize := RendererClass^.get_size;
LCLClass^.DefaultGtkRender := RendererClass^.render;
LCLClass^.DefaultGetRequestMode := RendererClass^.get_request_mode;
LCLClass^.DefaultGetPreferredWidth := RendererClass^.get_preferred_width;
LCLClass^.DefaultGetPreferredHeight := RendererClass^.get_preferred_height;
LCLClass^.DefaultGetPreferredHeightForWidth := RendererClass^.get_preferred_height_for_width;
LCLClass^.DefaultGetPreferredWidthForHeight := RendererClass^.get_preferred_width_for_height;
RendererClass^.get_request_mode := @LCLIntfCellRenderer_GetRequestMode;
RendererClass^.get_preferred_width := @LCLIntfCellRenderer_GetPreferredWidth;
RendererClass^.get_preferred_height := @LCLIntfCellRenderer_GetPreferredHeight;
RendererClass^.get_preferred_height_for_width := @LCLIntfCellRenderer_GetPreferredHeightForWidth;
RendererClass^.get_preferred_width_for_height := @LCLIntfCellRenderer_GetPreferredWidthForHeight;
// this is deprecated so mark in null since GtkCellRenderer checks if get_size is assigned and
// then it uses old api.
RendererClass^.get_size := nil; // @LCLIntfCellRenderer_GetSize;
RendererClass^.get_aligned_area := @LCLIntfCellRenderer_GetAlignedArea;
RendererClass^.render := @LCLIntfCellRenderer_Render;
end;
procedure LCLIntfCellRenderer_ClassFinalize(g_class: gpointer; class_data: gpointer); cdecl;
begin
// DebugLn('LCLIntfCellRenderer_ClassFinalize: finalization');
end;
procedure LCLIntfCellRenderer_Init({%H-}Instance:PGTypeInstance;
{%H-}theClass: Pointer); cdecl;
// Instance: PLCLIntfCellRenderer;
// theClass: PLCLIntfCellRendererClass
begin
//DebugLn(['LCLIntfCellRenderer_Init ']);
end;
function LCLIntfCellRenderer_GetType: TGType;
const
CR_NAME = 'LCLIntfCellRenderer';
crType: TGType = 0;
crInfo: TGTypeInfo = (
class_size: SizeOf(TLCLIntfCellRenderer) + 1024;
base_init: nil; // TGBaseInitFunc;
base_finalize: nil; // TGBaseFinalizeFunc;
class_init: @LCLIntfCellRenderer_ClassInit;
class_finalize: nil; // @LCLIntfCellRenderer_ClassFinalize; // nil; // TGClassFinalizeFunc;
class_data: nil;
instance_size: SizeOf(TLCLIntfCellRenderer) + 1024;
n_preallocs: SizeOf(TLCLIntfCellRenderer) + 1024;
instance_init: nil; // TGInstanceInitFunc;
value_table: nil;
);
begin
if (crType = 0) then
begin
crType := g_type_from_name(CR_NAME);
if crType = 0 then
crType := g_type_register_static(gtk_cell_renderer_text_get_type,'LCLIntfCellRenderer',@crInfo, 0);
end;
Result := crType;
end;
function LCLIntfCellRenderer_New: PGtkCellRenderer;
begin
// PGtkCellRenderer(g_type_class_ref(LCLIntfCellRenderer_GetType));
Result := g_object_new(LCLIntfCellRenderer_GetType, nil,[]);
end;
procedure LCLIntfCellRenderer_CellDataFunc(cell_layout:PGtkCellLayout;
cell: PGtkCellRenderer; tree_model: PGtkTreeModel; iter: PGtkTreeIter;
data: gpointer); cdecl;
var
LCLCellRenderer: PLCLIntfCellRenderer absolute cell;
APath: PGtkTreePath;
S: String;
// Str: PgChar;
ListColumn: TListColumn;
ListItem: TListItem;
Value: TGValue;
AMinH: gint;
ANatH: gint;
begin
if not Gtk3IsObject(cell) then
exit;
ListItem := nil;
APath := gtk_tree_model_get_path(tree_model,iter);
LCLCellRenderer^.Index := gtk_tree_path_get_indices(APath)^;
LCLCellRenderer^.ColumnIndex := -1;
gtk_tree_path_free(APath);
// DebugLn('LCLCellRenderer^.Index=',dbgs(LCLCellRenderer^.Index));
// WidgetInfo := PWidgetInfo(data);
// DebugLn(['LCLIntfCellRenderer_CellDataFunc stamp=',iter^.stamp,' tree_model=',dbgs(tree_model),' cell=',dbgs(cell),' WidgetInfo=',WidgetInfo <> nil,' Time=',TimeToStr(Now)]);
if (wtComboBox in TGtk3Widget(Data).WidgetType) and
(TCustomComboBox(TGtk3Widget(Data).LCLObject).Style = csDropDownList) and
not (TCustomComboBox(TGtk3Widget(Data).LCLObject).DroppedDown) then
begin
Value.g_type := G_TYPE_UINT;
Value.data[0].v_uint := 0;
g_object_get_property(PgObject(cell),'ypad',@Value);
Value.data[0].v_int := 0;
g_object_set_property(PGObject(cell), 'ypad', @Value);
end else
if wtListView in TGtk3Widget(Data).WidgetType then
begin
// DebugLn(['LCLIntfCellRenderer_CellDataFunc stamp=',iter^.stamp,' tree_model=',dbgs(tree_model),' cell=',dbgs(cell),' WidgetInfo=',WidgetInfo <> nil,' Time=',TimeToStr(Now)]);
Value.g_type := G_TYPE_STRING;
gtk_tree_model_get(tree_model, iter, [0, @ListItem, -1]);
if (ListItem = nil) and TCustomListView(TGtk3Widget(Data).LCLObject).OwnerData then
ListItem := TCustomListView(TGtk3Widget(Data).LCLObject).Items[LCLCellRenderer^.Index];
if ListItem = nil then
Exit;
ListColumn := TListColumn(g_object_get_data(PGObject(cell_layout), 'TListColumn'));
if ListColumn = nil then
LCLCellRenderer^.ColumnIndex := -1
else
LCLCellRenderer^.ColumnIndex := ListColumn.Index;
S := '';
if LCLCellRenderer^.ColumnIndex <= 0 then
S := ListItem.Caption
else
if ListColumn.Index-1 <= ListItem.SubItems.Count-1 then
S := ListItem.SubItems.Strings[LCLCellRenderer^.ColumnIndex-1];
Value.data[0].v_pointer := PgChar(S);
cell^.set_property('text', @Value);
end else
if (wtListBox in TGtk3Widget(Data).WidgetType) then
begin
if TGtk3ListBox(Data).ListBoxStyle < lbOwnerDrawFixed then
begin
Value.g_type := G_TYPE_STRING;
Value.data[0].v_pointer := nil;
cell^.get_property('text', @Value);
// DebugLn('PropertyType=',dbgs(Value.g_type),' IsString=',dbgs(Value.g_type = G_TYPE_STRING),' getString=',Value.get_string);
S := TCustomListBox(TGtk3Widget(Data).LCLObject).Items.Strings[LCLCellRenderer^.Index];
// DebugLn('LCLCellRenderer^.Index=',dbgs(LCLCellRenderer^.Index),' text=',Str);
Value.data[0].v_pointer := PgChar(S);
// Value.set_string(Str);
// set text only if we are not ownerdrawn !
cell^.set_property('text', @Value);
// DebugLn('IsFixedCellSize ',dbgs(PGtkTreeView(TGtk3Widget(Data).GetContainerWidget)^.get_fixed_height_mode));
end else
begin
//
end;
end;
//DebugLn(['LCLIntfCellRenderer_CellDataFunc ItemIndex=',LCLCellRenderer^.Index]);
end;
procedure LCLIntfRenderer_ColumnCellDataFunc(tree_column: PGtkTreeViewColumn;
cell: PGtkCellRenderer; tree_model: PGtkTreeModel; iter: PGtkTreeIter;
data: gpointer); cdecl;
begin
{$IFDEF GTK3DEBUGCELLRENDERER}
DebugLn('******* LCLIntfRenderer_ColumnCellDataFunc ********');
{$ENDIF}
LCLIntfCellRenderer_CellDataFunc(PGtkCellLayout(tree_column), cell, tree_model, iter, data);
end;
procedure LCLIntfRenderer_GtkCellLayoutDataFunc(cell_layout: PGtkCellLayout;
cell: PGtkCellRenderer; tree_model: PGtkTreeModel; iter: PGtkTreeIter;
data: gpointer); cdecl;
begin
DebugLn('******* LCLIntfRenderer_GtkCellLayoutDataFunc ********');
end;
end.