Jump to content
shineworld

DelphiVCL TreeView OnCustomDrawItem

Recommended Posts

I found an oddity in the "state" field of the OnCustomDrawItem event.
Basically instead of reporting the states of the VCL control passed by the related event all possible states are passed there:

function CustomDrawStateToPython(const ACustomDrawState: TCustomDrawState): PPyObject;

  procedure Append(const AList: PPyObject; const AString: string);
  var
    LItem: PPyObject;
  begin
    with GetPythonEngine do begin
      LItem := PyUnicodeFromString(AString);
      PyList_Append(AList, LItem);
      Py_XDecRef(LItem);
    end;
  end;

var
  LCompType: PTypeInfo;
  LMin: integer;
  LMax: integer;
  LState: integer;
begin
  Result := GetPythonEngine().PyList_New(0);
  LCompType := GetTypeData(TypeInfo(TCustomDrawState)).CompType^;
  LMin := LCompType^.TypeData^.MinValue;
  LMax := LCompType^.TypeData^.MaxValue;
  for LState := LMin to LMax do
    Append(Result, GetEnumName(LCompType, LState)); // <-- all enums are always set to state python attribute
end;

In my TreeView, when a node is selected, I've to change to white the font color otherwise text is hard to be sight:
image.thumb.png.4f623249eb2b007299f31bc261d8c9fe.png

 

Either I completely misunderstood the functionality of that function or there was an oversight.

Unfortunately Vcl.ComCtrls TCustomDrawItem is defined as a set with direct enumerators in the set so I didn't find

a direct method to do:

if CAST_TO_ENUM(LState) in TCustomDrawState then

but with a forcing and a pointer you still get something working:

function CustomDrawStateToPython(const ACustomDrawState: TCustomDrawState): PPyObject;

  procedure Append(const AList: PPyObject; const AString: string);
  var
    LItem: PPyObject;
  begin
    with GetPythonEngine do begin
      LItem := PyUnicodeFromString(AString);
      PyList_Append(AList, LItem);
      Py_XDecRef(LItem);
    end;
  end;

  function IsBitSet(Index: Integer; State: TCustomDrawState): Boolean;
  var
    P: PByte;
  begin
    if (Index < 0) or (Index >= SizeOf(TCustomDrawState) * 8) then Exit(False);
    P := @State;
    Result := (P^ and (1 shl Index)) <> 0;
  end;

var
  LCompType: PTypeInfo;
  LMin: integer;
  LMax: integer;
  LState: integer;
begin
  Result := GetPythonEngine().PyList_New(0);
  LCompType := GetTypeData(TypeInfo(TCustomDrawState)).CompType^;
  LMin := LCompType^.TypeData^.MinValue;
  LMax := LCompType^.TypeData^.MaxValue;
  for LState := LMin to LMax do
  begin
    if IsBitSet(LState, ACustomDrawState) then
      Append(Result, GetEnumName(LCompType, LState));
  end;
end;

I'm not so smart in these things so if some Delphi guru has a better solution I'm ready to fix the code.

Best regards.

Share this post


Link to post
4 hours ago, shineworld said:

Unfortunately Vcl.ComCtrls TCustomDrawItem is defined as a set with direct enumerators in the set so I didn't find

a direct method to do:


if CAST_TO_ENUM(LState) in TCustomDrawState then

 

FYI, in Delphi 12 Athens, TCustomDrawState now uses a new enum type TCustomDrawStateItem, so you can cast the values to that type, eg:

for LState := LMin to LMax do
begin
  if TCustomDrawStateItem(LState) in ACustomDrawState then
    Append(Result, GetEnumName(TypeInfo(TCustomDrawStateItem), LState));
end;

 

Share this post


Link to post
Posted (edited)
14 hours ago, pyscripter said:

A fix has been applied to P4D.  Please check.

New commit fixes the issue and works perfectly.
 

Edited by shineworld

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×