unit uSysCol;
{
}
interface
uses Windows, SysUtils
  , CalcAnsiScript
  , uAnsiCharTools
  ;


{(*} //以下が設定　h:の先頭文字が!なら色反転対象でない
type   TColNmTbl = record c: integer;n, h: Ansistring; end;
const ColorNameM = 20;
const ColNmTbls: array [0..ColorNameM] of TColNmTbl =
  {00}((c: COLOR_WINDOW{                }; n: 'COLOR_WINDOW'{               }; h: ' 5ウィンドウの背景 関連付けられている前景色はCOLOR_WINDOWTEXTされ、COLOR_HOTLITE')
  {01}, (c: COLOR_WINDOWTEXT{           }; n: 'COLOR_WINDOWTEXT'{           }; h: ' 8ウィンドウ内のテキスト 関連付けられている背景色がCOLOR_WINDOW')
  {02}, (c: COLOR_HIGHLIGHT{            }; n: 'COLOR_HIGHLIGHT'{            }; h: '13コントロールで選択されている項目 関連付けられている前景色がCOLOR_HIGHLIGHTTEXT')
  {03}, (c: COLOR_HIGHLIGHTTEXT{        }; n: 'COLOR_HIGHLIGHTTEXT'{        }; h: '14コントロールで選択されている項目のテキスト 関連付けられている背景色がCOLOR_HIGHLIGHT')
  {04}, (c: COLOR_3DFACE{               }; n: 'COLOR_3DFACE'{               }; h: '153 Dとダイアログ ボックスの背景の面の色')
  {05}, (c: COLOR_GRAYTEXT{             }; n: 'COLOR_GRAYTEXT'{             }; h: '17灰色:無効のテキスト 現在のディスプレイ ドライバーが単色の灰色をサポートしていない場合、この色は 0 に設定')
  {06}, (c: COLOR_BTNTEXT{              }; n: 'COLOR_BTNTEXT'{              }; h: '18プッシュ ボタン上のテキスト 関連付けられている背景色がCOLOR_BTNFACE')
  {07}, (c: COLOR_HOTLIGHT{             }; n: 'COLOR_HOTLIGHT'{             }; h: '26ハイパーリンクまたはホット トラックアイテムの色 関連付けられている背景色がCOLOR_WINDOW')
  {08}, (c: COLOR_CAPTIONTEXT{          }; n: 'COLOR_CAPTIONTEXT'{          }; h: ' 9キャプション、サイズ ボックス、スクロール バーの矢印ボックス内のテキスト 関連付けられている背景色がCOLOR_ACTIVECAPTION')
  {09}, (c: COLOR_ACTIVEBORDER{         }; n: 'COLOR_ACTIVEBORDER'{         }; h: '!10    アクティブなウィンドウの境界線')
  {10}, (c: COLOR_INACTIVEBORDER{       }; n: 'COLOR_INACTIVEBORDER'{       }; h: '!11    非アクティブなウィンドウの境界線')
  {11}, (c: COLOR_APPWORKSPACE{         }; n: 'COLOR_APPWORKSPACE'{         }; h: '!12    複数のドキュメント インターフェイスMDI) アプリケーションの背景色')
  {12}, (c: COLOR_BTNFACE{              }; n: 'COLOR_BTNFACE'{              }; h: '!15  ')
  {13}, (c: COLOR_INACTIVECAPTIONTEXT{  }; n: 'COLOR_INACTIVECAPTIONTEXT'{  }; h: '!19    非アクティブなキャプションのテキストの色 関連付けられている背景色がCOLOR_INACTIVECAPTION')
  {14}, (c: COLOR_INFOTEXT{             }; n: 'COLOR_INFOTEXT'{             }; h: '!23    ヒント コントロールのテキストの色 関連付けられている背景色がCOLOR_INFOBK')
  {15}, (c: COLOR_INFOBK{               }; n: 'COLOR_INFOBK'{               }; h: '!24    ヒント コントロールの背景色 関連付けられている前景色がCOLOR_INFOTEXT')
  {16}, (c: COLOR_3DSHADOW{             }; n: 'COLOR_3DSHADOW'{             }; h: '!16    3Dの影の色 光源から離れたエッジの場合')
  {17}, (c: COLOR_3DHILIGHT{            }; n: 'COLOR_3DHILIGHT'{            }; h: '!20    3Dの強調表示の色 光源に面するエッジの場合')
  {18}, (c: COLOR_3DDKSHADOW{           }; n: 'COLOR_3DDKSHADOW'{           }; h: '!21    3Dの濃い影')
  {19}, (c: COLOR_3DLIGHT{              }; n: 'COLOR_3DLIGHT'{              }; h: '!22    3Dの明るい色 光源に面するエッジの場合')
  {20}, (c: COLOR_DESKTOP{              }; n: 'COLOR_DESKTOP'{              }; h: '! 1 デスクトップ')
  {21});
const ColTbls: array [0..21] of record c: integer;n: Ansistring; end  =
  {00}((c:$000000;n:'clBlack')
  {01},(c:$000080;n:'clMaroon')
  {02},(c:$008000;n:'clGreen')
  {03},(c:$008080;n:'clOlive')
  {04},(c:$800000;n:'clNavy')
  {05},(c:$800080;n:'clPurple')
  {06},(c:$808000;n:'clTeal')
  {07},(c:$808080;n:'clGray')
  {08},(c:$C0C0C0;n:'clSilver')
  {09},(c:$0000FF;n:'clRed')
  {10},(c:$00FF00;n:'clLime')
  {11},(c:$00FFFF;n:'clYellow')
  {12},(c:$FF0000;n:'clBlue')
  {13},(c:$FF00FF;n:'clFuchsia')
  {14},(c:$FFFF00;n:'clAqua')
  {15},(c:$C0C0C0;n:'clLtGray')//clSilveralias
  {16},(c:$808080;n:'clDkGray')//clGrayalias
  {17},(c:$FFFFFF;n:'clWhite')
  {18},(c:$C0DCC0;n:'clMoneyGreen')
  {19},(c:$F0CAA6;n:'clSkyBlue')
  {20},(c:$F0FBFF;n:'clCream')
  {21},(c:$A4A0A0;n:'clMedGray')
  );
  {*)}
type
{
TAnsiCalculateにシステムカラーの入出力を追加する
#scol という行コマンドを追加する
    # scolのみなら　現在の設定値が読まれ
    # scol name で SysColorにname.scolを設定する
    # scol + name で name.scolに現在の設定値を書き出す
    # scol - name で name.scolを削除する
    COLOR_xxxに代入した時は実際の変更はスクリプト終了時に一括して行う（毎回するとちらつきが大きい為）
    また、小数点以下は代入により丸められている
    }
    TuSysColor = class(TCalcuAddition)
    ColBuf
      , ColNo: array[0..ColorNameM] of DWORD;
    ColBufSz: integer;
  public
 //  function CallFunc(const lab: AnsiString; Labels: TAMyCalLabel): boolean ;override;
    function ExeLabel(const lab: AnsiString; var ret: Extended; cmd: TGetLabelCmd): boolean; override;
    procedure StartEndScript(n: Integer); override; //0:start 1:end;
    function LineCmd(const lab: AnsiString; var p: PChar): boolean; override; //#で始まる行コマンド
  end;


function readFileStr(fname: ansistring): ansistring;
implementation

function Color2Str(c: longint): string;
var
  i: integer;
begin
    //  if ColorToIdent(c, Result) then exit;
  for i := Low(ColTbls) to High(ColTbls) do
    if c = ColTbls[i].c then
    begin
      Result := ColTbls[i].n;
      exit;
    end;
  Result := format('$%6.6X', [c]);
end;

function ColorCode(s: ansistring): longint;
var
  i, OX: integer;
begin
  OX := 0;
  if s[1] in ['~', '!'] then
  begin
    OX := $FFFFFF;
    Delete(s, 1, 1);
    s := Trim(s);
  end;
  for i := Low(ColTbls) to High(ColTbls) do
    if SameText(s, ColTbls[i].n) then
    begin
      Result := ColTbls[i].c xor OX;
      exit;
    end;
  if s[1] in ['$', '0'..'9'] then
  begin
    Result := StrToInt(s) xor OX;
    exit;
  end;
  raise Exception.Create(s + ':名前がない');
end;


{ TuSysColor }



function TuSysColor.ExeLabel(const lab: AnsiString; var ret: Extended; cmd: TGetLabelCmd): boolean;
var
  i, j: integer;
begin
  Result := True;
  for i := Low(ColTbls) to High(ColTbls) do
    if SameText(lab, ColTbls[i].n) then
    begin
      if cmd = glGetData then begin
        ret := ColTbls[i].c;
        exit;
      end;
      owner.Err(lab + ':const');
    end;

  for i := Low(ColNmTbls) to High(ColNmTbls) do
    if SameText(lab, ColNmTbls[i].n) then
      case cmd of
        glSetData: begin
            for j := 0 to ColBufSz - 1 do
              if ColNo[j] = ColNmTbls[i].c then begin
                ColBuf[j] := round(ret);
                exit;
              end;
            ColNo[ColBufSz] := ColNmTbls[i].c;
            ColBuf[ColBufSz] := round(ret); ;
            Inc(ColBufSz);
            exit;
          end;
        glGetData: begin //既に代入していたら
            for j := 0 to ColBufSz - 1 do
              if ColNo[j] = ColNmTbls[i].c then begin
                ret := ColBuf[j];
                exit;
              end;
            ret := GetSysColor(ColNmTbls[i].c);
            exit;
          end;
        glPrePP: begin
            owner.Err('++/-- ng ' + lab);
            exit;
          end;
      end;
  Result := False;
  exit;
end;

//LazarusのDelphi変換でGetFileSizeを無条件にFileSizeに変換するバグの回避

function ExtGetFileSize(hFile: THandle; lpFileSizeHigh: Pointer): DWORD; stdcall; external kernel32 name 'GetFileSize';

function readFileStr(fname: ansistring): ansistring;
var
  hin: THandle;
  rsize: DWORD;
begin
  Result := '';
  rsize := 0;
  hin := CreateFile(pansichar(fname), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL, 0);
  if hin <> INVALID_HANDLE_VALUE then try

    SetLength(Result, ExtGetFileSize(hin, nil));
    windows.ReadFile(hin, pansichar(Result)^, Length(Result), rsize, nil);
  finally CloseHandle(hin);
  end;
end;

procedure writeFileStr(fname, s: ansistring);
var
  hin: THandle;
  rsize: DWORD;
begin
  rsize := 0;
  hin := CreateFile(pansichar(fname), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL, 0);
  if hin <> INVALID_HANDLE_VALUE then try
    windows.Writefile(hin, pansichar(s)^, Length(s), rsize, nil);
  finally CloseHandle(hin);
  end;
end;




function getWin32Find(const fname: ansistring): TWin32FindData;
var
  h: THandle;
begin
  h := FindFirstFile(pansichar(fname), Result);
  if h = INVALID_HANDLE_VALUE then
  begin
    Result.cFileName[0] := #0;
  end
  else Windows.FindClose(h);
end;

function SysColorTxt(): ansistring;
var
  s: ansistring;
  i, c, sz: integer;
begin
  Result := '';
  for i := LOw(ColNmTbls) to High(ColNmTbls) do
  begin
    c := GetSysColor(ColNmTbls[i].c);
    s := ColNmTbls[i].n;
    sz := length(s);
    while sz < 24 do
    begin s := s + ' '; Inc(sz); end;
    s := s + '=' + Color2Str(c);
    sz := length(s);
    while sz < 40 do
    begin s := s + ' '; Inc(sz); end;
    s := addS([s + '//', cvU(ColNmTbls[i].h)]);
    if i <> High(ColNmTbls) then s := addS([s, #13#10]); //CR+LFを追加する
    Result := addS([Result, s]);
  end;
end;


//初期化

function TuSysColor.LineCmd(const lab: AnsiString; var p: PChar): boolean;
var
  c, fname, s: string;
begin
  Result := False;
  if SameText(lab, 'h') or (lab = '') then //helpの時は処理してもfalseを返す
  begin
    owner.MsgOutLn(cvU(
      '#scolのみなら　現在の設定値が読まれ'#13#10 +
      '#scol name で  SysColorにname.scol.txtを設定する'#13#10 +
      '#scol +name で nameに現在の設定値を書き出す'#13#10 +
      '#scol -name で nameを削除する'));

  end;
  if not SameText(lab, 'scol') then exit;
  Result := True;
  c := '';
  if p^ in ['+', '-'] then begin c := p^; inc(p); end;
  CAnsiSkipBlank(p); //空白は開けてもよい
  fname := CAnsiGetAccordZenChars(p, ['@'..'Z', 'a'..'z', '0'..'9']); //ファイル名は全角が英数字に限定(数字のファイルも作れる)
  CAnsiSkipBlank(p);
  if not (p^ in ['#', #0, #13, #10]) then owner.Err('#' + lab + ' ' + fname + '??'); //コメントか改行で終わっていない
//#scol のみの場合はsysColorを読み出す
  if (c = '') and (fname = '') then begin
    s := SysColorTxt();
    owner.MsgOutLn(s);
    exit;
  end;
  if fname = '' then owner.Err('#' + lab + '?');
// #scol 1
  s := ExtractFilePath(ParamStr(0)) { +'scol\'};
//   CreateDir(s);
  fname := s + fname + '.scol.txt'; //exeと同じフォルダだけを指定する
//#scol name で name.scolでSysColorに設定する
  if (c = '') then begin
    s := readFileStr(fname);
    if s = '' then owner.Err('#' + lab + '?')
    else begin
      owner.formulaLine(s); //代入でない状態で終わってる場合は無視
      if ColBufSz > 0 then SetSysColors(ColBufsz, ColNo, ColBuf);
      ColBufSz := 0;
    end;
  end;
  //#scol +name で name.scolに現在の設定値を書き出す
  if c = '+' then writeFileStr(fname, SysColorTxt());

//#scol -name で name.scolを削除する
  if c = '-' then
    if FileExists(fname) then DeleteFile(fname);
end;


procedure TuSysColor.StartEndScript(n: Integer);
begin
  case n of
    0: ColBufSz := 0;
    1: begin
        if ColBufSz > 0 then
          SetSysColors(ColBufsz, ColNo, ColBuf);
        ColBufSz := 0;
      end;
  end;
end;
initialization
  CalcAddTCalcuAddition(TuSysColor);
end.

