7

I'm trying to make a convenient function to convert a System.Classes.TShiftState into a user-readable string. To make it easier, I've made a subroutine to perform common code, to make the function more compact.

The problem is, I cannot figure out how to pass one of the TShiftState enum types into this subroutine. I tried Byte, Integer, and Cardinal but I keep getting Incompatible types: 'Byte' and 'Enumeration' (or whichever type I was trying). Hovering over one of them only shows $1 where the type would usually be.

function ShiftStateStr(const Shift: TShiftState): String;
  procedure A(const Sh: Byte; const Str: String);
  begin
    if Sh in Shift then
      Result:= Result + StrLen(Str, Length(Str)+1)
    else
      Result:= Result + StrLen('', Length(Str)+1);
  end;
begin
  Result:= '';
  A(ssShift, 'Shift');
  A(ssAlt, 'Alt');
  A(ssCtrl, 'Ctrl');
  A(ssLeft, 'Left');
  A(ssRight, 'Right');
  A(ssMiddle, 'Middle');
  A(ssDouble, 'Double');
  A(ssTouch, 'Touch');
  A(ssPen, 'Pen');
  A(ssCommand, 'Cmd');
  A(System.Classes.ssHorizontal, 'Horz');
end;

NOTE: StrLen is a separate function which pads a string with spaces of a given length.

TShiftState is defined in System.Classes like so:

type
  TShiftState = set of (ssShift, ssAlt, ssCtrl,
    ssLeft, ssRight, ssMiddle, ssDouble, ssTouch, ssPen, ssCommand, ssHorizontal);

How can I properly pass this into the A subroutine?

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Jerry Dodge
  • 26,858
  • 31
  • 155
  • 327
  • 2
    You have been caught out by the pool decision of Emba not to name the enumerated type. This is a perfect example of why enumerated types should always be named. – David Heffernan Nov 19 '16 at 06:50
  • 1
    Also `StrLen` is a name used for a function that returns the length of a null terminated character array. Use `str.PadLeft(n)` instead. – David Heffernan Nov 19 '16 at 07:34
  • Why not use built in functions to do this? https://community.embarcadero.com/blogs/entry/using-generics-rtti-to-get-enum-string-name-or-enum-value – John Easley Nov 19 '16 at 16:57
  • @John Because I want the strings to be shortened, and not have `ss` in front of them. Like I said, more human-readable :P – Jerry Dodge Nov 19 '16 at 18:03
  • @David Thanks for pointing that out, actually this function can pad left, right, or center, and can use desired character instead of a space. – Jerry Dodge Nov 19 '16 at 18:06
  • 1
    All the same StrLen is a weak name – David Heffernan Nov 19 '16 at 19:35
  • 1
    @JerryDodge you can copy the string minus the first two characters. The problem with your approach is if you change your set, you need to change your function later on. – John Easley Nov 19 '16 at 21:05
  • @John Well if *Emba* wants to change the set. If it were my own, I wouldn't have a problem :D But `Command` is shortened to `Cmd`, and `Horizontal` to `Horz`, etc. – Jerry Dodge Nov 19 '16 at 22:51
  • @John What would you pass to `TypeInfo()`? There is no named type for the values that make up the `TShiftState` set. The enumeration is anonymous. – Tom Brunberg Nov 20 '16 at 00:38

1 Answers1

7

Change first parameter of A to const Sh: TShiftState. Then change each call to A into the form

A([ssShift], 'Shift');

and finally the condition test into

if Sh <= Shift then

Ref. Expressions

X <= Y is True just in case every member of X is a member of Y

Tom Brunberg
  • 20,312
  • 8
  • 37
  • 54