unit PlugServ;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses
	Windows, ActiveX, Classes, ComObj, Graphics, SysUtils,
		CM2VISInterface, CM2AutoUpdateInterface, CM2EditorSupportInterface;

type                         
  pRGBTripleArray = ^TRGBTripleArray;
  TRGBTripleArray = ARRAY[WORD] OF TRGBTriple;
	TCM2VFText = class(TComObject, ICM2VisPlug, ICM2AutoUpdate, ICM2EditorSupportVis20)
	private
		fDC: HDC;
		LastErrorMsg: PChar;
		fBMP: TBitmap;
		FontStyle, fStyle: TFontStyles;
		Borders, Shadow, Gradient, TopToBottom: Boolean;
		fLeft, fTop, fWidth, fHeight, BorderWidth, FontSize, fSize, LineSpacer, RC, Angle, SX, SY: Integer;
		FontName, fName, Align, vAlign, fString, rStr: String;
		FontColor, fColor, BorderColor, Background1, Background2, ShadowColor, Mask: TColor;
		procedure DrawBitmap;
    procedure SetFont(S: String);
    procedure Rotate;       
		procedure GradientFill;
		function GetGradient(StartColor, EndColor: TColor; PointValue, Min, Max: Single): TColor;
	public
		Function Name(OUT Name: Pchar): HResult; stdcall;
		Function Version(OUT Version: Word): HResult; stdcall;
		Function RequiredCoreVersion(OUT RCV: Word): HResult; stdcall;
		Function GetLastErrorMsg(OUT Msg: PChar): HResult; stdcall;
		Function GetInfoCount(OUT InfoCount: Integer): HResult; stdcall;
		Function GetInfo(Index: Integer; OUT InfoName: PChar; OUT InfoVar: PChar): HResult; stdcall;
		Function SetDC(CONST NewDC: THandle): HResult; stdcall;
		Function SetDimensions(Left, Top, Width, Height : Integer): HResult; stdcall;
		Function SetConfigString(NewConfigString: PChar): HResult; stdcall;
		Function Redraw: HResult; stdcall;
		Function Update(SensorStyle: Byte; NewString: PChar; NewValue: Double): HResult; stdcall;
		Function Init(PaintDC: THandle): HResult; stdcall;
		Function Terminating: HResult; stdcall;
		Function Setup: HResult; stdcall;
		Function GetDefaultCount(OUT DefaultCount: Integer): HResult; stdcall;
		Function GetDefault(Index: Integer; OUT Name: PChar; OUT Value: PChar; OUT Description: PChar): HResult; stdcall;
		Function GetOptionalCount(OUT OptionalCount: Integer): HResult; stdcall;
		Function GetOptional(Index: Integer; OUT Name: PChar; OUT Value: PChar; OUT Description: PChar): HResult; stdcall;
		Function UpdateFileURL(OUT URL: PChar): HResult; stdcall;
		Function ObjIns(ParameterName: PChar; OUT ValueType: Byte; OUT ValueRange: PChar): HResult; stdcall;
		Function OnEditor(ParameterName: PChar; FullParameterValues: PChar; OUT Value: PChar): HResult; stdcall;
		Function GetMenuCount(OUT MenuCount: Byte): HResult; stdcall;
		Function GetMenuItem(Index: Byte; OUT MenuTitle: PChar; OUT MenuHint: PChar): HResult; stdcall;
		Function OnMenu(Index: Byte; OUT ResultString: PChar): HResult; stdcall;
	end;

const
	Class_CM2VFText: TGUID = '{FACD4224-442C-48BD-8A39-81850F61DE06}';
  fmt: Array[0..27] of String = ('b', 'bold', '/b', '/bold', 'i', 'italic', '/i', '/italic', 'u', 'underline', '/u', '/underline',
    'o', 'so', 'strikeout', '/o', '/so', '/strikeout', 'n', 'nostyle', '/n', '/nostyle', '/s', '/size', '/c', '/color', '/f', '/font');

implementation

uses
	ComServ, Filter, PluginTools, FormatDialog;

{ TCM2VFText }

function TCM2VFText.Name(out Name: Pchar): HResult;
begin
	Name := 'VFText';
	Result := S_OK;
end;

function TCM2VFText.Version(out Version: word): HResult;
begin
	Version := 0310;
	Result := S_OK;
end;

function TCM2VFText.UpdateFileURL(out URL: Pchar): HResult;
begin
	URL := 'http://coolmon.blackstar.solar/update/plugins/visual/CM2Vis_VFText.upd';
	Result := S_OK;
end;
        
function TCM2VFText.RequiredCoreVersion(out RCV: Word): HResult;
begin
	RCV := 0500;
	Result := S_OK;
end;      

function TCM2VFText.GetInfo(Index: Integer; out InfoName, InfoVar: PChar): HResult;
begin
	Result := S_OK;
	Case Index of
		0: Begin
			InfoName := 'Programmed By';
			InfoVar := 'Alch';
		End;
		1: Begin
			InfoName := 'Created';
			InfoVar := 'April 3, 2006';
		End;
		2: Begin
			InfoName := 'Last Update';
			InfoVar := 'April 23, 2007';
		End;
		3: Begin
			InfoName := 'Copyright';
			InfoVar := '(c) Alch - 2007';
		End;
		else begin
			Result := E_FAIL;
			LastErrorMsg := 'Info Index Out of Bounds';
		End;
	End;
end;   

function TCM2VFText.GetInfoCount(out InfoCount: Integer): HResult;
begin
	InfoCount := 4;
	Result := S_OK;
end;
     
function TCM2VFText.Redraw: HResult;
var
	Canvas: TCanvas;
begin
	Result := S_OK;
	Try
		Canvas := TCanvas.Create;
		Canvas.Handle := fDC;   
		DrawBitmap;
		Canvas.Draw(fLeft, fTop, fBMP);
	except
		LastErrorMsg := 'Unable to Create Canvas';
		Result := E_FAIL;
		Exit;
	end;

  Canvas.Free;
end;

Procedure TCM2VFText.DrawBitmap;
var
  sLine, sub, tmp, N, V: String;
	i, j, z, h, w, l, t, endS, Lines, ft, dif, CW, CH: Integer;
  lw, lh: Array of Integer;
begin
  if (Angle = 90) or (Angle = 270) then
  begin          
    CW := fHeight;
    CH := fWidth;
  end
    else
  begin  
    CW := fWidth;
    CH := fHeight;
  end;

  fBMP.Width := CW;
  fBMP.Height := CH;
	if Borders and (RC > 0) then
	begin
		fBMP.Transparent := True;
		fBMP.TransparentColor := clFuchsia;
		fBMP.Canvas.Brush.Color := clFuchsia;
		fBMP.Canvas.FillRect(fBMP.Canvas.ClipRect);
	end;
	with fBMP.Canvas do
	begin
    if Gradient then
      Brush.Color := Mask
    else
		  Brush.Color := Background1;
		Pen.Color := BorderColor;
		Pen.Width := BorderWidth;
		Pen.Style := psInsideFrame;
		If Not Borders then
		begin
			Pen.Color := Brush.Color;
			BorderWidth := 0;
			RC := 0;
		end;
		RoundRect(0, 0, CW, CH, RC, RC);
		Brush.Style := bsClear;
	end;

  If Gradient then
    GradientFill;

	if fString = '' then
		exit;

  Lines := CountFilt(fString, '[nl]', false);
  SetLength(lw, Lines);
  SetLength(lh, Lines);
    
  ft := 0;
  for z := 0 to 1 do
	begin
    fName := FontName;
    fColor := FontColor;
    fStyle := FontStyle;
    fSize := FontSize;
    dif := 0;
		t := 0;
		for i := 1 to Lines do
		begin
			sLine := GetFilt(fString, i, '[nl]', false);
      w := 0;

      if AnsiPos('LEFT', Align) > 0 then
        l :=  BorderWidth
      else if AnsiPos('RIGHT', Align) > 0 then
        l := CW -lw[i-1]  -BorderWidth
      else
        l := (CW - lw[i-1]) div 2;

			for j := 1 to CountFilt(sLine, '[') do
			begin        
        sub := GetFilt(sLine, j, '[');
        endS := AnsiPos(']', sub);
        if endS > 0 then
        begin
          tmp := Copy(LowerCase(sub), 1, endS-1);
          N := GetFilt(tmp, 1, '=');
          if CountFilt(tmp, '=') = 2 then
            V := GetFilt(tmp, 2, '=')
          else
          begin
            if N = 'space' then
              V := '10'
            else
              V := '25';
          end;
          if z = 1 then
          begin
            if N = 'start' then
            try
              w := StrToInt(V);
              l := 0;
            except
            end
              else if N = 'left' then
            begin
              w := 0;
              l := 0;
            end
              else if N = 'right' then
            begin
              w := CW - lw[i-1];
              l := 0;
            end;
          end;
          if N = 'space' then
          try
            w := w + StrToInt(V);
          except
          end
            else
              SetFont(tmp);
          Delete(sub, 1, endS);
        end;

        with fBMP.Canvas.Font do
        begin
          Name := fName;
          Style := fStyle;
          Size := fSize;
        end;
        
        h := fBMP.Canvas.TextHeight(sub);
        if z = 1 then
        begin
          if vAlign = 'CENTER' then
            dif := (lh[i-1] - h) div 2
          else if vAlign = 'BOTTOM' then
            dif := lh[i-1] - h;

          if Shadow then
          begin
            fBMP.Canvas.Font.Color := ShadowColor;
            fBMP.Canvas.TextOut(l + w + SX, ft + t + dif + SY, sub);
          end;

          fBMP.Canvas.Font.Color := fColor;
          fBMP.Canvas.TextOut(l + w, ft + t + dif, sub);
        end;

        w := w + fBMP.Canvas.TextWidth(sub);
        if z = 0 then
          if h > lh[i-1] then
             lh[i-1] := h;
			end; //j
      if z = 0 then
        lw[i-1] := w;
      if i < Lines then
        t := t + lh[i-1] + LineSpacer
      else
        t := t + lh[i-1];
		end;  //i
    if z = 0 then
      if AnsiPos('TOP', Align) > 0 then
        ft :=  BorderWidth
      else if AnsiPos('BOTTOM', Align) > 0 then
        ft := CH -t -BorderWidth
      else
        ft := (CH -t) div 2;
	end; //z

  if Angle <> 0 then
    Rotate;
end;

Procedure TCM2VFText.GradientFill;
  function ColorToRGBTriple(Clr: TColor): TRGBTriple;
  begin
    with Result do
    begin
      rgbtRed   := GetRValue(Clr);
      rgbtGreen := GetGValue(Clr);
      rgbtBlue  := GetBValue(Clr);
    end;
  end;
  function RGBTripleToColor(Clr: TRGBTriple): TColor;
  begin
    Result := RGB(Clr.rgbtRed, Clr.rgbtGreen, Clr.rgbtBlue);
  end;
{type
	pRGBTripleArray = ^TRGBTripleArray;
	TRGBTripleArray = Array[Word] of TRGBTriple;  }
var
	x, y: Integer;
	Row: pRGBTripleArray;
	Grad: TRGBTriple;
	tmp: TColor;
begin
  if TopToBottom then
  begin
    for y := 0 to fHeight-1 do
    begin
      Row := fBMP.ScanLine[y];
      Grad := ColorToRGBTriple(GetGradient(Background1, Background2, y, 0, fHeight-1));
      for x := 0 to fWidth-1 do
      begin
        tmp := RGBTripleToColor(Row[x]);
        if tmp = Mask then
          Row[x] := Grad;
      end;
    end;
  end
    else
  begin
    for x := 0 to fWidth-1 do
    begin     
      Grad := ColorToRGBTriple(GetGradient(Background1, Background2, x, 0, fWidth-1));
      for y := 0 to fHeight-1 do
      begin
        Row := fBMP.ScanLine[y];
        tmp := RGBTripleToColor(Row[x]);
        if tmp = Mask then
          Row[x] := Grad;
      end;
    end;
  end;
end;       

function TCM2VFText.GetGradient(StartColor, EndColor: TColor; PointValue, Min, Max: Single): TColor;
var
	F: Single;
	r1, r2, r3, g1, g2, g3, b1, b2, b3: Byte;
	function CalcColorBytes(fb1, fb2: Byte): Byte;
	begin
		result := fb1;
		if fb1 < fb2 then
			Result := FB1 + Trunc(F * (fb2 - fb1));
		if fb1 > fb2 then
			Result := FB1 - Trunc(F * (fb1 - fb2));
	end;
begin
	if PointValue <= Min then
  begin
		result := StartColor;
		exit;
	end;
	if PointValue >= Max then
  begin
		result := EndColor;
		exit;
	end;
	F := (PointValue - Min) / (Max - Min);
	asm
		mov EAX, Startcolor
		cmp EAX, EndColor
		je @@exit
		mov r1, AL
		shr EAX,8
		mov g1, AL
		shr Eax,8
		mov b1, AL
		mov Eax, EndColor
		mov r2, AL
		shr EAX,8
		mov g2, AL
		shr EAX,8
		mov b2, AL
		push ebp
		mov al, r1
		mov dl, r2
		call CalcColorBytes
		pop ecx
		push ebp
		Mov r3, al
		mov dL, g2
		mov al, g1
		call CalcColorBytes
		pop ecx
		push ebp
		mov g3, Al
		mov dL, B2
		mov Al, B1
		call CalcColorBytes
		pop ecx
		mov b3, al
		XOR EAX,EAX
		mov AL, B3
		SHL EAX,8
		mov AL, G3
		SHL EAX,8
		mov AL, R3
	@@Exit:
		mov @result, eax
	end;
end;

procedure TCM2VFText.Rotate;
var
  x, y: Integer;
  tmp: TBitmap;
  New, Old: pRGBTripleArray;
begin         
  tmp := TBitmap.Create;
  try
    tmp.PixelFormat := pf24bit;
    tmp.Width := fWidth;
    tmp.Height := fHeight;

    Case Angle of
      90: for y := 0 to fHeight -1 do //Down
          begin
            New := tmp.ScanLine[y];
            for x := 0 to fWidth -1 do
            begin
              Old := fBMP.ScanLine[fWidth -1 -x];
              New[x] := Old[y];
            end;
          end;
      180: for y := 0 to fHeight -1 do //UpsideDown
          begin
            New := tmp.ScanLine[y];
            Old := fBMP.ScanLine[fHeight -1 -y];
            for x := 0 to fWidth -1 do
              New[x] := Old[fWidth -1 -x];
          end;
      270: for y := 0 to fHeight -1 do //Up
          begin
            new := tmp.ScanLine[fHeight -1 -y];
            for x := 0 to fWidth -1 do
            begin
              Old := fBMP.ScanLine[x];
              New[x] := Old[y];
            end;
          end;
    end;

    fBMP.Width := fWidth;
    fBMP.Height := fHeight;
    fBMP.Canvas.CopyRect(fBMP.Canvas.ClipRect, tmp.Canvas, tmp.Canvas.ClipRect);
  finally
    tmp.Free;
  end;
end;

procedure TCM2VFText.SetFont(S: String);
var
  i, sPos: Integer;
  N, V: String;
begin      
  N := GetFilt(S, 1, '=');

  if (S = '') or (N = 'start') or (N = 'right') or (N = 'left') then
    Exit;

  sPos := 100;
  for i := 0 to 27 do
    if S = fmt[i] then
    begin
      sPos := i;
      break;
    end;

  Case sPos of
    0, 1: fStyle := fStyle + [fsBold];
    2, 3: fStyle := fStyle - [fsBold];
    4, 5: fStyle := fStyle + [fsItalic];
    6, 7: fStyle := fStyle - [fsItalic];
    8, 9: fStyle := fStyle + [fsUnderline];
    10, 11: fStyle := fStyle - [fsUnderline];
    12..14: fStyle := fStyle + [fsStrikeOut];
    15..17: fStyle := fStyle - [fsStrikeOut];
    18, 19: fStyle := [];
    20, 21: fStyle := FontStyle;
    22, 23: fSize := FontSize;
    24, 25: fColor := FontColor;
    26, 27: fName := FontName;
  else
    V := GetFilt(S, 2, '=');
    if (N = 'c') or (N = 'color') then
    try
      fColor := StringToTColor(V);
    except
      fColor := FontColor;
    end;
    if (N = 's') or (N = 'size') then
    try
      fSize := StrToInt(V);
    except
      fSize := FontSize;
    end;
    if (N = 'f') or (N = 'font') then
    try
      fName := V;
    except
      fName := FontName;
    end;
  end;
end;

Function TCM2VFText.OnEditor(ParameterName: PChar; FullParameterValues: PChar; OUT Value: PChar): HResult;
begin
	Value := '';
	Result := S_OK;
end;

Function TCM2VFText.GetMenuCount(OUT MenuCount: Byte): HResult;
begin
	MenuCount := 1;
	Result := S_OK;
end;

Function TCM2VFText.GetMenuItem(Index: Byte; OUT MenuTitle: PChar; OUT MenuHint: PChar): HResult;
begin
  MenuTitle := 'Format Text Dialog';
  MenuHint := 'Show a Dialog to Help with Text Formatting';
	Result := S_OK;
end;

Function TCM2VFText.OnMenu(Index: Byte; OUT ResultString: PChar): HResult;
var
	FD: TFormatDialog;
begin
	Result := S_OK;
	rStr := '';

  FD := TFormatDialog.Create(nil);
  try
    if FD.Execute(rStr) then
      ResultString := PChar('<text>' + rStr + '</text>');
  finally
    FreeAndNil(FD);
  end;
end;

function TCM2VFText.Init(PaintDC: THandle): HResult;
begin
	Result := S_OK;   
	try
		fBMP := TBitmap.Create;
    fBMP.PixelFormat := pf24bit;
		fDC := PaintDC;
	except
		LastErrorMsg := 'Unable to Create Bitmap';
		Result := E_FAIL;
		Exit;
	end;
	FontColor := clBlack;
	Background1 := clWhite;
  Background2 := clBlue;
	BorderColor := clMaroon;
	BorderWidth := 1;
	Align := 'CENTERTOP';
	vAlign := 'CENTER';
	LineSpacer := 1;
	Angle := 0;
	RC := 0;
  SX := 1;
  SY := 1;
	ShadowColor := clGray;
  Gradient := False; 
  TopToBottom := True;
  Mask := $00101012;
end;

function TCM2VFText.GetLastErrorMsg(OUT Msg: PChar): HResult;
begin
	If LastErrorMsg = '' then
		LastErrorMsg := 'No Errors';
	Msg := LastErrorMsg;
	Result := S_OK;
end;

function TCM2VFText.GetDefault(Index: Integer; out Name, Value, Description: PChar): HResult;
begin
	Result := S_OK;
	Case Index of
		0: begin Name := 'Font'; Value := 'Arial,8,0000'; Description := 'Font settings'; end;
		1: begin Name := 'FontColor'; Value := 'Black'; Description := 'Font color'; end;
		2: begin Name := 'BackgroundColor'; Value := 'White'; Description := 'Background Color'; end;
		3: Begin Name := 'Align'; Value := 'CenterTop'; Description := 'Align Text LeftTop, LeftCenter, LeftBottom, CenterTop, Center, CenterBottom, RightTop, RightCenter, or RightBottom'; end;
  else
    LastErrorMsg := 'Default Index of Out of Bounds';
    Result := E_FAIL;
	end;
end;

function TCM2VFText.GetDefaultCount(out DefaultCount: Integer): HResult;
begin
	Result := S_OK;
	DefaultCount := 4;
end;              

function TCM2VFText.GetOptional(Index: Integer; out Name, Value, Description: PChar): HResult;
begin
	Result := S_OK;
	Case Index of
		0: Begin Name := 'Borders'; Value := 'No'; Description := 'Show Borders'; end;
		1: Begin Name := 'BorderColor'; Value := 'Maroon'; Description := 'Border Color'; End;
		2: Begin Name := 'BorderWidth'; Value := '1'; Description := 'Border Width'; End;
		3: Begin Name := 'vAlign'; Value := 'Center'; Description := 'Vertical Text Alignment Top, Center or Bottom'; end;
		4: Begin Name := 'RoundCorners'; Value := '0'; Description := 'Number of Pixels to Round the Corners'; end;
		5: Begin Name := 'Orientation'; Value := 'Normal'; Description := 'Text Orientation'; end;
		6: Begin Name := 'Shadow'; Value := 'No'; Description := 'Text Shadow'; end;
		7: Begin Name := 'ShadowColor'; Value := 'Gray'; Description := 'Text Shadow Color'; end;
		8: Begin Name := 'ShadowOffsetX'; Value := '1'; Description := 'Text Shadow X Offset'; end;
		9: Begin Name := 'ShadowOffsetY'; Value := '1'; Description := 'Text Shadow Y Offset'; end;
		10: Begin Name := 'LineSpacer'; Value := '1'; Description := 'Spacing between Lines'; end;
		11: Begin Name := 'Gradient'; Value := 'None'; Description := 'Draw a Gradient Background'; end;
		12: Begin Name := 'BackgroundColor2'; Value := 'Blue'; Description := 'Second Gradient Color'; end;
  else
    Result := E_FAIL;
    LastErrorMsg := 'Optional Index Out of Bounds';
	end;
end;

function TCM2VFText.GetOptionalCount(out OptionalCount: Integer): HResult;
begin
	OptionalCount := 13;
	Result := S_OK;
end;

function TCM2VFText.SetConfigString(NewConfigString: PChar): HResult;
var
	i: Integer;
	S, N, V, FStyle: String;
begin
	Result := S_OK;
	S := NewConfigString;
	For i := 1 to CountFilt(NewConfigString, '|') do
	begin
		S := Uppercase(GetFilt(NewConfigString, i, '|'));
		N := GetFilt(S, 1, '=');
		V := GetFilT(S, 2, '=');

		if V = '' then
			Continue;

		If N = 'FONT' Then
		Begin
			If CountFilt(V, ',') = 3 then
			begin
				try
					FontName := GetFilt(V, 1, ',');
				except
					FontName := 'Arial';
				End;
				try
					FontSize := StrToInt(GetFilt(V, 2, ','));
				except
					FontSize := 8;
				end;
				FStyle := GetFilt(V, 3, ',');
				If Length(FStyle) <> 4 then
					FontStyle := []
				else
				begin
					FontStyle := [];
					If FStyle[1] = '1' then
						FontStyle := [fsBold];
					If FStyle[2] = '1' then
						FontStyle := FontStyle + [fsItalic];
					If FStyle[3] = '1' then
						FontStyle := FontStyle + [fsUnderline];
					If FStyle[4] = '1' then
						FontStyle := FontStyle + [fsStrikeOut];
				end;
			end;
			Continue;
		End;
		If (N = 'COLOR') or (N = 'FONTCOLOR') Then
		Begin
			Try
				FontColor := StringToTColor(V);
			except
				FontColor := clBlack;
			end;
			Continue;
		End;
		If (N = 'BACKGROUND') or (N = 'BACKGROUNDCOLOR') or (N = 'BACKGROUND1') Then
		begin
			Try
				Background1 := StringToTColor(V);
			except
				Background1 := clWhite;
			end;
			Continue;
		end;       
		If (N = 'BACKGROUND2') or (N = 'BACKGROUNDCOLOR2') Then
		begin
			Try
				Background2 := StringToTColor(V);
			except
				Background2 := clBlue;
			end;
			Continue;
		end;
		If (N = 'BORDERS') or (N = 'BORDER') or (N = 'EDGE') Then
		Begin
			If (V = 'YES') or (V = 'TRUE') Then
				Borders := True
			else
				Borders := False; 
			Continue;
		End;
		If N = 'BORDERCOLOR' Then
		begin
			Try
				BorderColor := StringToTColor(V);
			except
				BorderColor := clBlack;
			end;  
			Continue;
		end;
		If N = 'BORDERWIDTH' Then
		Begin
			try
				BorderWidth := StrToInt(V);
			except
				BorderWidth := 1;
			end;   
			Continue;
		End;
		If N = 'ROUNDCORNERS' Then
		Begin
			try
				RC := StrToInt(V);
			except
				RC := 0;
			end;
			Continue;
		End;
		If N = 'VALIGN' Then
		Begin
			If (V = 'TOP') or (V = 'CENTER') or (V = 'BOTTOM') Then
				vAlign := V
			else
				vAlign := 'CENTER';
			Continue;
		End;
		If N = 'ORIENTATION' Then
		Begin
			if (V = 'DOWN') or (V = 'TOPTOBOTTOM') or (V = '90') then
				Angle := 90
			else if (V = 'UPSIDEDOWN') or (V = '180') then
				Angle := 180
			else if (V = 'UP') or (V = 'BOTTOMTOTOP') or (V = '270') then
				Angle := 270
			else
				Angle := 0;
			Continue;
		End;
		If N = 'SHADOW' Then
		begin
			If (V = 'YES') or (V = 'TRUE') Then
				Shadow := True
			else
				Shadow := False;
			Continue;
		end;
		If N = 'SHADOWCOLOR' Then
		Begin
			Try
				ShadowColor := StringToTColor(V);
			except
				ShadowColor := clBlack;
			end;  
			Continue;
		End;     
		If (N = 'SHADOWOFFSETX') or (N = 'X') Then
		Begin
			try
				SX := StrToInt(V);
			except
				SX := 1;
			end;
			Continue;
		End;
		If (N = 'SHADOWOFFSETY') or (N = 'Y') Then
		Begin
			try
				SY := StrToInt(V);
			except
				SY := 1;
			end;
			Continue;
		End;
		If N = 'LINESPACER' Then
		Begin
			try
				LineSpacer := StrToInt(V);
			except
				LineSpacer := 1;
			end;
			Continue;
		End; 
		If N = 'GRADIENT' Then
		Begin
      Gradient := True;
			if (V = 'TOPTOBOTTOM') or (V = 'T2B') or (V = 'TRUE')then
        TopToBottom := True
      else if (V = 'LEFTTORIGHT') or (V = 'L2R') then
        TopToBottom := False
      else
        Gradient := False;
			Continue;
		End;
		If N = 'ALIGN' Then
			Align := V;
	End;
end;

function TCM2VFText.SetDC(const NewDC: THandle): HResult;
begin
	fDC := NewDC;
	Result := S_OK;
end;

function TCM2VFText.SetDimensions(Left, Top, Width, Height: Integer): HResult;
begin
	fLeft := Left;
	fTop := Top;
	fWidth := Width;
	fHeight := Height;
	Result := S_OK;
end;

function TCM2VFText.Setup: HResult;
begin
	Result := E_NOTIMPL;
end;

function TCM2VFText.Terminating: HResult;
begin
  fBMP.Free;
	Result := S_OK;
end;

function TCM2VFText.Update(SensorStyle: Byte; NewString: PChar; NewValue: Double): HResult;
begin
	Result := S_OK;
	Case SensorStyle of
		0: fString := FloatToStr(NewValue);
		1: fString := NewString;
  else
    result := E_Fail;
    fString := 'Invalid SensorStyle #' + IntToStr(SensorStyle);
	end;
end;

function TCM2VFText.ObjIns(ParameterName: PChar; out ValueType: Byte; out ValueRange: PChar): HResult;
var
	N: String;
begin
	Result := S_OK;
	N := UpperCase(ParameterName);
	ValueType := vtUnknown;
	ValueRange := '';
	If N = 'FONT' then
	begin
		ValueType := vtFontEx;
		exit;
	end;
	If (N = 'COLOR') or (N = 'FONTCOLOR') then
	begin
		ValueType := vtColor;     
		exit;
	end;
	If (N = 'BACKGROUND1') or (N = 'BACKGROUND') or (N = 'BACKGROUNDCOLOR') then
	begin
		ValueType := vtColor;     
		exit;
	end;          
	If (N = 'BACKGROUND2') or (N = 'BACKGROUNDCOLOR2') then
	begin
		ValueType := vtColor;     
		exit;
	end;
	If N = 'BORDERCOLOR' then
	begin
		ValueType := vtColor;     
		exit;
	end;
	If (N = 'BORDERS') or (N = 'BORDER') or (N = 'EDGE') then
	begin
		ValueType := vtFixed;
		ValueRange := 'Yes|No';
		exit;
	end;
	If N = 'ALIGN' then
	begin
		ValueType := vtFixed;
		ValueRange := 'LeftTop|LeftCenter|LeftBottom|CenterTop|Center|CenterBottom|RightTop|RightCenter|RightBottom';
		exit;
	end;
	If N = 'VALIGN' then
	begin
		ValueType := vtFixed;
		ValueRange := 'Top|Center|Bottom';
		exit;
	end;
	If N = 'ORIENTATION' then
	begin
		ValueType := vtFixed;
		ValueRange := 'Normal|Up|Down|UpsideDown';
		exit;
	end;     
	If N = 'GRADIENT' then
	begin
		ValueType := vtFixed;
		ValueRange := 'None|TopToBottom|LeftToRight';
		exit;
	end;
	If N = 'SHADOW' then
	begin
		ValueType := vtFixed;
		ValueRange := 'Yes|No';
		exit;
	end;
	If N = 'SHADOWCOLOR' then
		ValueType := vtColor;
end;

initialization
	TComObjectFactory.Create(ComServer, TCM2VFText, Class_CM2VFText,
		'CM2Vis_VFText', 'CoolMon 2 VFText Plugin', ciMultiInstance, tmApartment);
end.
