pyscripter/python4delphi

CustomDrawStateToPython return always all TCustomDrawState

shineworld opened this issue · 4 comments

The function CustomDrawStateToPython, in WrapVCLComCtrls.pas, instead to place the actual ACustomDrawState in the python object places all possible TCustomDrawStates.

To solve it I had to do a "cobbler" since the TCustomDrawState set is built directly with enumerators and I don't know how else to do it.

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;
type
  TCustomDrawStateEnums = (
    cdsSelected, cdsGrayed, cdsDisabled, cdsChecked,
    cdsFocused, cdsDefault, cdsHot, cdsMarked, cdsIndeterminate,
    cdsShowKeyboardCues, cdsNearHot, cdsOtherSideHot, cdsDropHilited
  );
  TCustomDrawStateSet = set of TCustomDrawStateEnums;
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 TCustomDrawStateEnums(LState) in TCustomDrawStateSet(ACustomDrawState) then
      Append(Result, GetEnumName(LCompType, LState));
  end;
end;

I ask help to Delphi guru...

Another, I think, very "bad" solution which does not require a re-definition of enum and set could be:

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;

Unfortunately in Vcl.ComCtrls TCustomDrawItem is defined as:

  TCustomDrawState = set of (cdsSelected, cdsGrayed, cdsDisabled, cdsChecked,
    cdsFocused, cdsDefault, cdsHot, cdsMarked, cdsIndeterminate,
    cdsShowKeyboardCues, cdsNearHot, cdsOtherSideHot, cdsDropHilited);

and not as:

  TCustomDrawStateEnum = set of (cdsSelected, cdsGrayed, cdsDisabled, cdsChecked,
    cdsFocused, cdsDefault, cdsHot, cdsMarked, cdsIndeterminate,
    cdsShowKeyboardCues, cdsNearHot, cdsOtherSideHot, cdsDropHilited);    

  TCustomDrawState = set TCustomDrawStateEnum,

which do not permits a simple:

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

Can you check with the latest commit?

New commit solve the issue and WORKS perfectly !!!!