var
  SkinRes,srMax,srMin:TxspSkinRes;
  btns;
  btnCount:integer;
  total:Real;
  Number:Real
  complete:boolean;
  operator:char;
  MiniMode:boolean;

{字符串到实数转换函数}
function ValFn(S:string):Real;
var
  code:integer;
  L:real;
begin
  Val(S,L,code);
  result:=L;
end;

{实数到字符串转换函数,详细内容请参考前面的转换步骤}
function StrFn(L:Real):string;
var
  Sc,Scientific,Converted,Digit:string;
  I,Exponent:integer;
  Negate:boolean;
begin
  str(L,Scientific);
  sc:=Scientific;
  //Scientific格式:3.00000000000000E+0000
  if Copy(Scientific,1,1)='-'then Negate:=true
    else Negate:=false;
  Delete(scientific,1,1);
  //删除Scientific小数点后的多余0
  I:=pos('E',Scientific);
  dec(I);
  while(Copy(Scientific,I,1)='0')do
  begin
    Delete(Scientific,i,1);
    dec(I);
  end;
  //将E前面的数字转换到converted中
  converted:='';
  I:= 1;
  repeat
    Digit:= Copy(Scientific,I,1);
    if (Digit<>'.') and (Digit<>'E') then
      Converted:= converted + Digit;
    Inc(I);
  until (Digit='E');
  //
  Val(Copy(Scientific,I,255),Exponent,i);
  i:=exponent+2;
  while i>length(converted)+1 do converted:=converted+'0';
  while i<1 do
  begin
    Inc(i);
    converted:='0'+converted;
  end;
  if i<=Length(Converted) then Insert('.',Converted,i);
  if Negate then Converted:='-'+Converted;
  if Length(Converted)>17 then result:=Sc
  else result:=Converted;
end;

{计算过程}
procedure calculate(Nextop:char);
begin
  Number:=ValFn(lblResult.caption);
  if (Nextop='s') or (Nextop='c') or (Nextop='r')
    or (Nextop='v') or (Nextop='i') or (Nextop='o') or (Nextop='±') or (Nextop='%') then
  begin//其它特殊运算
    case Nextop of
      's': Total:=number*number;       //
      'c': Total:=number*number*number;
      'r': Total:=Sqrt(number);//√ 开方
      'v': Total:=1/number;    //1/x
      'i': Total:=Sin(number); //sin
      'o': Total:=cos(number); //cos
      '±': Total:=0-Number;
      '%': Total:=Number/100;
      //'=': Total:=Number;
    end;
    
    lblResult.caption:=StrFn(Total);
    complete:=false;
    operator:='n';
  end
  else//加减乘除
  begin
    //showtrayhint('ca',floattostr(total)+operator+floattostr(number)+nextop);
    case  operator of
      '+' : Total:=Total+number; 
      '-' : Total:=Total-number;
      'x' : Total:=Total*number;
      'd' : if number<>0 then Total:=Total/number;
      '=' : Total:=Number;
      {'m' :Total:=Total mod number;}
      //'n':
    end;
    lblResult.caption:=StrFn(Total);
      
    complete:= true;
    operator:=Nextop;
  end;
end;

procedure KeyPress(aKey:string);
var
  r:real;
begin
  s:=lblResult.caption;
  case aKey of
    '0','1','2','3','4','5','6','7','8','9':
      begin
        if complete then
        begin
          s:='';
          complete:=false;
        end;
        s:=s+aKey;
        lblResult.caption:=s;
      end;
    '.':
      begin
        if complete then
        begin
          s:='';
          complete:=false;
        end;
        if (pos('.',s) = 0)  then
	begin
          s:=s+aKey;
	  lblResult.caption:=s;
	end;
      end
    '+','-': calculate(aKey); 
    '×': calculate('x'); 
    '÷': calculate('d'); 
    '=': calculate('=');
    '√': calculate('r');
    '%': calculate('%');
    '1/x': calculate('v');
    '±': calculate('±');
    //"c"键是彻底清除键，也就是之前所有操作清除。 
    //"ce"键是本次操作清除键。如果输入数据错误可以用"ce"键清除本次输入的数据，如果不小心用了"c"键就是把以前的运算全部取消了。
    'CE':
      begin
        lblResult.caption:='';
      end;
    'C':
      begin
        s:='0';
        total:=0;
        complete:=true;
        operator:='+';
        lblResult.caption:=s;
      end;
    'DEL':
      begin
        lblResult.caption:=copy(s,1,length(s)-1);
        Total:=ValFn(lblResult.caption);
      end;
  end;
end;

procedure btnClick(sender);
begin
  KeyPress(sender.caption);
end;

procedure SetMiniMode(value:boolean);
begin
  if MiniMode=value then exit;
  MiniMode:=value;
  BeginUpdate;
  if MiniMode then
  begin
    Widget.Width:=139;
    Widget.Height:=196;
    lblResult.left:=7;
    lblResult.top:=16;
    lblResult.width:=115;
    lblResult.height:=22;
    imgbg.FileName:=WidgetPath+'images\bg_dock.png';
    SkinRes.ButtonLeft:=7;
    SkinRes.ButtonRight:=7;
    SkinRes.ButtonFileName:=WidgetPath+'images\btn2.png';
    srMax.ButtonLeft:=11;
    srMax.ButtonRight:=11;
    srMax.ButtonFileName:=WidgetPath+'images\btnd0.png';
    srMin.ButtonLeft:=7;
    srMin.ButtonRight:=7;
    srMin.ButtonFileName:=WidgetPath+'images\btnd1.png';
    //0-9,.,C
    for i:=0 to 11 do
    begin
      btns[i].SkinRes:=SkinRes;
      btns[i].Width:=22;
      btns[i].Height:=23;
    end;
    for i:=0 to 9 do
    begin
      j:=(i mod 3);
      if j<>0 then j:=3-j;
      btns[i].left:=j*28+18;
      btns[i].top:=152-((i+2) div 3)*28;
    end;
    //+-*/
    for i:=12 to 17 do
    begin
      btns[i].SkinRes:=srMin;
      if (i=12) or (i=13) then
      begin
        btns[i].Width:=32;
        btns[i].Height:=17;
        btns[i].top:=44;
        btns[i].left:=btn0.left+(i-12)*40;
      end
      else
      begin
        btns[i].Width:=16;
        btns[i].Height:=17;
        btns[i].left:=103;
        btns[i].top:=(i-14)*23+48;
      end;
    end;
    //=
    btnCal.SkinRes:=srMax;
    btnCal.Width:=16;
    btnCal.Height:=38;
    btnCal.left:=btnAdd.left;
    btnCal.top:=138;

  end
  else
  begin
    Widget.Width:=190;
    Widget.Height:=260;
    lblResult.left:=20;
    lblResult.top:=26;
    lblResult.width:=145;
    lblResult.height:=24;
    
    imgbg.FileName:=WidgetPath+'images\bg.png';
    SkinRes.ButtonLeft:=14;
    SkinRes.ButtonRight:=14;
    SkinRes.ButtonFileName:=WidgetPath+'images\btn1.png';
    srMax.ButtonLeft:=10;
    srMax.ButtonRight:=10;
    srMax.ButtonFileName:=WidgetPath+'images\btn0.png';
    srMin.ButtonLeft:=10;
    srMin.ButtonRight:=10;
    srMin.ButtonFileName:=WidgetPath+'images\btn2.png';
    
    //0-9,.,C
    for i:=0 to 11 do
    begin
      btns[i].SkinRes:=SkinRes;
      btns[i].Width:=30;
      btns[i].Height:=30;
    end;
    for i:=0 to 9 do
    begin
      j:=(i mod 3);
      if j<>0 then j:=3-j;
      btns[i].left:=j*38+28;
      btns[i].top:=207-((i+2) div 3)*38;
    end;
    //+-*/
    for i:=12 to 17 do
    begin
      btns[i].SkinRes:=srMin;
      if (i=12) or (i=13) then
      begin
        btns[i].Width:=45;
        btns[i].Height:=23;
        btns[i].top:=60;
        btns[i].left:=btn0.left+(i-12)*50;
      end
      else
      begin
        btns[i].Width:=22;
        btns[i].Height:=23;
        btns[i].left:=141;
        btns[i].top:=(i-14)*31+66;
      end;
    end;
    //=
    btnCal.SkinRes:=srMax;
    btnCal.Width:=22;
    btnCal.Height:=52;
    btnCal.left:=btnAdd.left;
    btnCal.top:=185;
  end;
  btnDot.left:=btns[2].left;
  btnDot.top:=btns[0].top;
  btnC.left:=btns[1].left;
  btnC.top:=btns[0].top;
  EndUpdate;
end;

//读取当前Widget的INI设置
procedure InitIni;
begin

end;

//--- Widget移入边栏事件，当Widget被移到边栏上时会触发此事件 ---
procedure OnWidgetDock;
begin
  SetMiniMode(true);
end;

//--- Widget移出边栏事件，当Widget被移出边栏时会触发此事件 ---
procedure OnWidgetUnDock;
begin
  SetMiniMode(false);
end;

//--- Widget初始化事件，当打开Widget时会触发此事件 ---
procedure OnWidgetInit;
begin
  Total:=0.0;
  Number:=0.0;
  complete:=true;
  operator:='+';
  MiniMode:=false;
  SkinRes:=TxspSkinRes.create(Widget);
  srMax:=TxspSkinRes.create(Widget);
  srMin:=TxspSkinRes.create(Widget);
  btnCount:=19;
  btns:=[btn0,btn1,btn2,btn3,btn4,btn5,btn6,btn7,btn8,btn9,
    btnDot,btnC,btnDel,btnCE,
    btnDiv,btnMul,btnSub,btnAdd,btnCal];
  BeginUpdate;
  SkinRes.ButtonGlyphCount:=3;
  SkinRes.ButtonLeft:=14;
  SkinRes.ButtonRight:=14;
  SkinRes.ButtonFileName:=WidgetPath+'images\btn1.png';
  srMax.ButtonGlyphCount:=3;
  srMax.ButtonLeft:=10;
  srMax.ButtonRight:=10;
  srMax.ButtonFileName:=WidgetPath+'images\btn0.png';
  srMin.ButtonGlyphCount:=3;
  srMin.ButtonLeft:=10;
  srMin.ButtonRight:=10;
  srMin.ButtonFileName:=WidgetPath+'images\btn2.png';
  if btnCount>0 then
    for i:=0 to btnCount-1 do
    begin
      btns[i].SkinRes:=SkinRes;
      btns[i].OnClick:='btnClick';
    end;
  for i:=12 to 17 do
    btns[i].SkinRes:=srMin;
  btnCal.SkinRes:=srMax;

  InitIni;
  if Docking then 
  	OnWidgetDock;
  EndUpdate;
  
  lblResult.OnChange:='lblResultChange';
  Widget.KeyPreview:=true;
  Widget.OnKeyDown:='FormKeyDown';
end;

//--- Widget关闭事件，当关闭Widget时会触发此事件 ---
procedure OnWidgetClose;
begin
  SkinRes.free;
end;

procedure lblResultChange(sender);
begin
  if lblResult.caption='' then complete:=false;
end;

procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
const
  VK_NUMPAD0 = 96;
  VK_NUMPAD9 = 105;
var
  s:string;
begin
  if Key=16 then exit;
  //s:=shift;
  //s:=copy(s,length(s),1);
  if (Key>=VK_NUMPAD0) and (Key<=VK_NUMPAD9) then
    KeyPress(IntToStr(Key-96))
  else if (Key>=48) and (Key<=57) then
  begin
    if Shift=1 then //shift key press
    begin
      case key of
        53: KeyPress('%');
        56: KeyPress('×');
      end;
    end
    else
      KeyPress(IntToStr(Key-48));
  end;
  //else  
  case Key of
    109,189: KeyPress('-');
    107: KeyPress('+');
    106: KeyPress('×');
    111: KeyPress('÷');
    13:  KeyPress('=');
    187:
      if Shift=318637057 then  
        KeyPress('+')
      else
        KeyPress('=');
    8:   KeyPress('DEL');
    191: KeyPress('÷');
    110,190: KeyPress('.');
    //else
    //  showmsg(key);
  end;
end;
