rm_grid.pas

来自「胜天进销存源码,国产优秀的进销存」· PAS 代码 · 共 2,110 行 · 第 1/5 页

PAS
2,110
字号
procedure FillDWord(var Dest; Count, Value: Integer); register;
asm
  XCHG  EDX, ECX
  PUSH  EDI
  MOV   EDI, EAX
  MOV   EAX, EDX
  REP   STOSD
  POP   EDI
end;

{ StackAlloc allocates a 'small' block of memory from the stack by
  decrementing SP.  This provides the allocation speed of a local variable,
  but the runtime size flexibility of heap allocated memory.  }

function StackAlloc(Size: Integer): Pointer; register;
asm
  POP   ECX          { return address }
  MOV   EDX, ESP
  ADD   EAX, 3
  AND   EAX, not 3   // round up to keep ESP dword aligned
  CMP   EAX, 4092
  JLE   @@2
@@1:
  SUB   ESP, 4092
  PUSH  EAX          { make sure we touch guard page, to grow stack }
  SUB   EAX, 4096
  JNS   @@1
  ADD   EAX, 4096
@@2:
  SUB   ESP, EAX
  MOV   EAX, ESP     { function result = low memory address of block }
  PUSH  EDX          { save original SP, for cleanup }
  MOV   EDX, ESP
  SUB   EDX, 4
  PUSH  EDX          { save current SP, for sanity check  (sp = [sp]) }
  PUSH  ECX          { return to caller }
end;

procedure StackFree(P: Pointer); register;
asm
  POP   ECX                     { return address }
  MOV   EDX, DWORD PTR [ESP]
  SUB   EAX, 8
  CMP   EDX, ESP                { sanity check #1 (SP = [SP]) }
  JNE   @@1
  CMP   EDX, EAX                { sanity check #2 (P = this stack block) }
  JNE   @@1
  MOV   ESP, DWORD PTR [ESP+4]  { restore previous SP  }
@@1:
  PUSH  ECX                     { return to caller }
end;

procedure TRMGridEx.SetClipRect(ACanvas: TCanvas; ClipR: TRect);
begin
  FOldRgn := 0;
  FOldRgn := CreateRectRgn(0, 0, 0, 0);
  FHaveClip := GetClipRgn(ACanvas.Handle, FOldRgn);

  FNewRgn := CreateRectRgnIndirect(ClipR);
  SelectClipRgn(ACanvas.Handle, FNewRgn);
  DeleteObject(FNewRgn);
end;

procedure TRMGridEx.RestoreClipRect(ACanvas: TCanvas);
begin
  if FHaveClip > 0 then
    SelectClipRgn(ACanvas.Handle, FOldRgn)
  else
    SelectClipRgn(ACanvas.Handle, 0);
  DeleteObject(FOldRgn);
end;

procedure TRMGridEx.ShowFrame(t: TRMView; aCanvas: TCanvas; x, y, x1, y1: Integer);

  procedure Line1(x, y, x1, y1: Integer);
  begin
    aCanvas.MoveTo(x, y);
    aCanvas.LineTo(x1, y1);
  end;

  procedure DrawFrame(const x, y, x1, y1: Integer; b: TRMFrameLine; aFlag: Byte);
  begin
    aCanvas.Pen.Width := Round(b.Width);
    aCanvas.Pen.Style := b.Style;
    aCanvas.Pen.Color := b.Color;
    aCanvas.MoveTo(x, y);
    aCanvas.LineTo(x1, y1);
  end;

begin
  if t.LeftFrame.Visible then
    Inc(x, Round(t.LeftFrame.Width) div 2 - 1);
  if t.TopFrame.Visible then
    Inc(y, Round(t.TopFrame.Width) div 2 - 1);
  if t.RightFrame.Visible then
    Dec(x1, Round(t.RightFrame.Width) div 2);
  if t.BottomFrame.Visible then
    Dec(y1, Round(t.BottomFrame.Width) div 2);

  if t.LeftFrame.Visible then
    DrawFrame(x, y, x, y1, t.LeftFrame, 1);
  if t.TopFrame.Visible then
    DrawFrame(x, y, x1, y, t.TopFrame, 2);
  if t.RightFrame.Visible then
    DrawFrame(x1, y, x1, y1, t.RightFrame, 3);
  if t.BottomFrame.Visible then
    DrawFrame(x, y1, x1, y1, t.BottomFrame, 4);

  if t.LeftRightFrame > 0 then
  begin
    aCanvas.Brush.Style := bsSolid;
    aCanvas.Pen.Style := psSolid;
    aCanvas.Pen.Width := 1;
    aCanvas.Pen.Color := t.LeftFrame.Color;
    case t.LeftRightFrame of
      1: Line1(x, y, x1, y1);
      2:
        begin
          Line1(x, y, x1 div 2, y1);
          Line1(x, y, x1, y1 div 2);
        end;
      3:
        begin
          Line1(x, y, x1, y1);
          Line1(x, y, x1 div 2, y1);
          Line1(x, y, x1, y1 div 2);
        end;
      4: Line1(x, y1, x1, y);
      5:
        begin
          Line1(x, y1 div 2, x1, y);
          Line1(x1 div 2, y1, x1, y);
        end;
      6:
        begin
          Line1(x, y1, x1, y);
          Line1(x, y1 div 2, x1, y);
          Line1(x1 div 2, y1, x1, y);
        end;
    end;
  end;
end;

procedure TRMGridEx.DrawCell(ACol, ARow: Longint; ARect, AClipRect: TRect; AState: TRMGridDrawState);
var
  liTextAlignMode: UINT;
  liTextToDraw: PChar;
  liTestRect: TRect; // 边框范围与文本试输出范围
  liTestWidth, liTestHeight: Integer; // 实际宽高
  liDrawWidth, liDrawHeight: Integer; // 绘画区宽高

  procedure CalcTestRect;
  var
    CalcMode: Cardinal;
  begin
    liTestRect := ARect;
    with liTestRect do
    begin
      Dec(Right, Left);
      Dec(Bottom, Top);
      Left := 0;
      Top := 0;
    end;
    CalcMode := DT_CALCRECT;
    if Cells[ACol, ARow].AutoWordBreak then
      CalcMode := CalcMode or DT_WORDBREAK;
    DrawText(Canvas.Handle, liTextToDraw, -1, liTestRect, CalcMode);
    liTestWidth := liTestRect.Right - liTestRect.Left;
    liTestHeight := liTestRect.Bottom - liTestRect.Top;
    liDrawWidth := ARect.Right - ARect.Left;
    liDrawHeight := ARect.Bottom - ARect.Top;
    liTestRect.Left := (liDrawWidth - liTestWidth) div 2;
    liTestRect.Right := liTestRect.Left + liTestWidth;
    liTestRect.Top := (liDrawHeight - liTestHeight) div 2;
    liTestRect.Bottom := liTestRect.Top + liTestHeight;
  end;

begin
  if (aCol > 0) and (aRow > 0) then
    ShowFrame(Cells[ACol, ARow].View, Canvas, aRect.Left, aRect.Top, aRect.Right, aRect.Bottom);

  if (ARow = 0) and (ACol <> 0) then
  begin
    Canvas.Brush.Style := bsClear;
    //    Canvas.Font.Name := 'MS Sans Serif';
    //    Canvas.Font.Size := 8;
    //    Canvas.Font.Style := [];
    Canvas.Font.Color := clWindowText;
    DrawText(Canvas.Handle, PChar(ColTitle(ACol - 1)), -1, ARect, DT_CENTER or DT_VCENTER or DT_SINGLELINE)
  end
  else if (ACol = 0) and (ARow <> 0) then
  begin
    Canvas.Brush.Style := bsClear;
    //    Canvas.Font.Name := 'MS Sans Serif';
    //    Canvas.Font.Size := 8;
    //    Canvas.Font.Style := [];
    Canvas.Font.Color := clWindowText;
    aRect.Right := aRect.Right - 2;
    liTestRect := Rect(ARect.Left + 2, ARect.Top + 2, ARect.Right, ARect.Bottom);
    DrawText(Canvas.Handle, PChar(IntToStr(ARow)), -1, liTestRect, DT_LEFT or DT_TOP or DT_SINGLELINE);
    DrawText(Canvas.Handle, PChar(Cells[0, aRow].Text), -1, aRect, DT_RIGHT {DT_CENTER} or DT_VCENTER or DT_SINGLELINE)
      //    DrawText(Canvas.Handle, PChar(IntToStr(ARow)), -1, ARect, DT_CENTER or DT_VCENTER or DT_SINGLELINE)
  end
  else if (ARow <> 0) and (ACol <> 0) then
  begin
    InflateRect(ARect, -1, -1);
    IntersectClipRect(Canvas.Handle, ARect.Left, ARect.Top, ARect.Right, ARect.Bottom);
    with Cells[ACol, ARow] do
    begin
      if Text <> '' then
      begin
        liTextToDraw := PChar(Text);
        Canvas.Font.Assign(Font);
        if rmgdSelected in AState then //and ((ACol <> FCurrent.X) or (ARow <> FCurrent.Y)) then
          Canvas.Font.Color := FHighLightTextColor;

        CalcTestRect;
        case HAlign of
          rmHLeft: liTextAlignMode := DT_TOP or DT_LEFT;
          rmHRight: liTextAlignMode := DT_TOP or DT_RIGHT;
        else
          liTextAlignMode := DT_CENTER;
        end;
        case VAlign of
          rmVBottom: ARect.Top := ARect.Bottom - liTestHeight;
          rmVCenter: Inc(ARect.Top, liTestRect.Top);
        end;
        if AutoWordBreak then
          liTextAlignMode := liTextAlignMode or DT_WORDBREAK;
        Windows.DrawText(Canvas.Handle, liTextToDraw, -1, ARect, liTextAlignMode)
      end;
    end;
    RestoreClipRect(Canvas);
    SetClipRect(Canvas, AClipRect);
  end;

  //  if Assigned(FOnDrawCell) then
  //  begin
  //    FOnDrawCell(Self, ACol, ARow, ARect, AState);
  //  end;
end;

{$IFNDEF Delphi4}

function Max(Value1, Value2: Integer): Integer;
begin
  if Value1 > Value2 then
    Result := Value1
  else
    Result := Value2;
end;

function Min(Value1, Value2: Integer): Integer;
begin
  if Value1 > Value2 then
    Result := Value2
  else
    Result := Value1;
end;
{$ENDIF}

procedure TRMGridEx.Paint;
var
  DrawInfo: TRMGridDrawInfo;
  Sel: TRect;
  UpdateRect: TRect;
  DrawRect, ClipRect, IRect: TRect;
  PointsList: PIntArray;
  StrokeList: PIntArray;
  MaxStroke: Integer;
  FrameFlags1, FrameFlags2: DWORD;
  MaxHorzExtent, MaxVertExtent: Integer;
  MaxHorzCell, MaxVertCell: Integer;
  MinHorzCell, MinVertCell: Integer;

  procedure _DrawLines(DoHorz, DoVert: Boolean; StartCol, StartRow, EndCol, EndRow: Longint;
    const CellBounds: array of Integer; OnColor, OffColor: TColor);
  const
    FlatPenStyle = PS_Geometric or PS_Solid or PS_EndCap_Flat or PS_Join_Miter;

    procedure DrawAxisLines(const AxisInfo: TRMGridAxisDrawInfo;
      MajorIndex: Integer; UseOnColor: Boolean);
    var
      LogBrush: TLOGBRUSH;
      Cell, Index: Integer;
      Points: PIntArray;
      StartMajor, StopMajor, StartMinor, StopMinor: Integer;
      MayHaveMerge: Boolean;
      TopIndex: Integer;
      MergePoint: TPoint;

      function FindHorzMerge(ARow, StartIndex: Integer): TPoint;
      var
        I: Integer;
        liCell: TRMCellInfo;
      begin
        Result.x := -1;
        Result.y := -1;
        for i := StartIndex to EndCol do
        begin
          liCell := Cells[i, ARow];
          if CellInMerge(i, ARow) and (ARow <> liCell.EndRow) then
          begin
            Result.x := liCell.StartCol;
            Result.y := liCell.EndCol;
            Exit;
          end;
        end;
      end;

      function FindVertMerge(ACol, StartIndex: Integer): TPoint;
      var
        i: Integer;
        liCell: TRMCellInfo;
      begin
        Result.x := -1;
        Result.y := -1;
        for i := StartIndex to EndRow do
        begin
          liCell := Cells[ACol, i];
          if CellInMerge(ACol, i) and (ACol <> liCell.EndCol) then
          begin
            Result.x := liCell.StartRow;
            Result.y := liCell.EndRow;
            Exit;
          end;
        end;
      end;

    begin
      with Canvas, AxisInfo do
      begin
        Pen.Style := psSolid;
        Pen.Mode := pmCopy;
        if EffectiveLineWidth <> 0 then
        begin
          Pen.Width := FGridLineWidth;
          if UseOnColor then
            Pen.Color := OnColor
          else
            Pen.Color := OffColor;
          if Pen.Width > 1 then
          begin
            LogBrush.lbStyle := BS_Solid;
            LogBrush.lbColor := Pen.Color;
            LogBrush.lbHatch := 0;
            Pen.Handle := ExtCreatePen(FlatPenStyle, Pen.Width, LogBrush, 0, nil);
          end;
          if MajorIndex = 0 then
            Cell := StartCol // 画竖线
          else
            Cell := StartRow; // 画横线
          // 第一根线的位置
          StartMajor := CellBounds[MajorIndex] + EffectiveLineWidth shr 1 +
            GetExtent(Cell);
          // 最后一根线的位置
          StopMajor := CellBounds[2 + MajorIndex] + EffectiveLineWidth;
          // 画线起点
          StartMinor := CellBounds[MajorIndex xor 1];
          // 画线终点
          StopMinor := CellBounds[2 + (MajorIndex xor 1)];
          MayHaveMerge := False;
          // 计算是否可能存在合并区域
          if ((StartMinor > 0) and (StartMajor > 0) or
            (StartMinor > 0) and (StartMajor > 0)) then
            MayHaveMerge := True;
          Points := PointsList;
          Index := 0;
          repeat
            if ((MajorIndex = 0) and (ColWidths[Cell] >= 0)) or
              ((MajorIndex = 1) and (RowHeights[Cell] >= 0)) then
            begin
              // 画线起点
              Points^[Index + MajorIndex] := StartMajor; // MoveTo
              Points^[Index + (MajorIndex xor 1)] := StartMinor;
              Inc(Index, 2);
              // 如果可能存在合并区域
              if MayHaveMerge then
              begin
                if MajorIndex = 0 then // 画竖线
                begin
                  TopIndex := StartRow;
                  while TopIndex <= EndRow do
                  begin
                    MergePoint := FindVertMerge(Cell, TopIndex);
                    if MergePoint.x > 0 then //Have Merge
                    begin
                      Points^[Index + MajorIndex] := StartMajor; // LineTo
                      Points^[Index + (MajorIndex xor 1)] := CellRect(Cell, MergePoint.x).Top;
                      Inc(Index, 2);
                      Points^[Index + MajorIndex] := StartMajor; // MoveTo
                      Points^[Index + (MajorIndex xor 1)] := CellRect(Cell, MergePoint.y).Bottom;
                      Inc(Index, 2);
                      TopIndex := MergePoint.y + 1;
                    end
                    else
                      Inc(TopIndex);
                  end;
                end
                else // 画横线
                begin
                  TopIndex := StartCol;
                  while TopIndex <= EndCol do
                  begin
                    MergePoint := FindHorzMerge(Cell, TopIndex);
                    if MergePoint.x > 0 then
                    begin
                      Points^[Index + MajorIndex] := StartMajor; // LineTo
                      Points^[Index + (MajorIndex xor 1)] := CellRect(MergePoint.x, Cell).Left;
                      Inc(Index, 2);
                      Points^[Index + MajorIndex] := StartMajor; // MoveTo
                      Points^[Index + (MajorIndex xor 1)] := CellRect(MergePoint.y, Cell).Right;
                      Inc(Index, 2);
                      TopIndex := MergePoint.y + 1;
                    end
                    else
                      Inc(TopIndex);
                  end;
                end;
              end;
              // 画线终点
              Points^[I

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?