home *** CD-ROM | disk | FTP | other *** search
/ Delphi Anthology / aDELPHI.iso / Runimage / Delphi50 / Source / Samples / colorgrd.pas < prev    next >
Pascal/Delphi Source File  |  1999-08-11  |  17KB  |  560 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Borland Delphi Visual Component Library         }
  5. {                                                       }
  6. {       Copyright (c) 1995,99 Inprise Corporation       }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit ColorGrd;
  11.  
  12. {$R-}
  13.  
  14. interface
  15.  
  16. uses Windows, Messages, Classes, Graphics, Forms, Controls, ExtCtrls;
  17.  
  18. const
  19.   NumPaletteEntries = 20;
  20.  
  21. type
  22.   TGridOrdering = (go16x1, go8x2, go4x4, go2x8, go1x16);
  23.  
  24.   TColorGrid = class(TCustomControl)
  25.   private
  26.     FPaletteEntries: array[0..NumPaletteEntries - 1] of TPaletteEntry;
  27.     FClickEnablesColor: Boolean;
  28.     FForegroundIndex: Integer;
  29.     FBackgroundIndex: Integer;
  30.     FForegroundEnabled: Boolean;
  31.     FBackgroundEnabled: Boolean;
  32.     FSelection: Integer;
  33.     FCellXSize, FCellYSize: Integer;
  34.     FNumXSquares, FNumYSquares: Integer;
  35.     FGridOrdering: TGridOrdering;
  36.     FHasFocus: Boolean;
  37.     FOnChange: TNotifyEvent;
  38.     FButton: TMouseButton;
  39.     FButtonDown: Boolean;
  40.     procedure DrawSquare(Which: Integer; ShowSelector: Boolean);
  41.     procedure DrawFgBg;
  42.     procedure UpdateCellSizes(DoRepaint: Boolean);
  43.     procedure SetGridOrdering(Value: TGridOrdering);
  44.     function GetForegroundColor: TColor;
  45.     function GetBackgroundColor: TColor;
  46.     procedure SetForegroundIndex(Value: Integer);
  47.     procedure SetBackgroundIndex(Value: Integer);
  48.     procedure SetSelection(Value: Integer);
  49.     procedure EnableForeground(Value: Boolean);
  50.     procedure EnableBackground(Value: Boolean);
  51.     procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
  52.     procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
  53.     procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
  54.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  55.     procedure CMCtl3DChanged(var Message: TMessage); message CM_CTL3DCHANGED;
  56.   protected
  57.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  58.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  59.       X, Y: Integer); override;
  60.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  61.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  62.       X, Y: Integer); override;
  63.     procedure CreateWnd; override;
  64.     procedure Paint; override;
  65.     procedure Change; dynamic;
  66.     function SquareFromPos(X, Y: Integer): Integer;
  67.   public
  68.     constructor Create(AOwner: TComponent); override;
  69.     function ColorToIndex(AColor: TColor): Integer;
  70.     property ForegroundColor: TColor read GetForegroundColor;
  71.     property BackgroundColor: TColor read GetBackgroundColor;
  72.   published
  73.     property Anchors;
  74.     property ClickEnablesColor: Boolean read FClickEnablesColor write FClickEnablesColor default False;
  75.     property Constraints;
  76.     property Ctl3D;
  77.     property DragCursor;
  78.     property DragMode;
  79.     property Enabled;
  80.     property GridOrdering: TGridOrdering read FGridOrdering write SetGridOrdering default go4x4;
  81.     property ForegroundIndex: Integer read FForegroundIndex write SetForegroundIndex default 0;
  82.     property BackgroundIndex: Integer read FBackgroundIndex write SetBackgroundIndex default 0;
  83.     property ForegroundEnabled: Boolean read FForegroundEnabled write EnableForeground default True;
  84.     property BackgroundEnabled: Boolean read FBackgroundEnabled write EnableBackground default True;
  85.     property Font;
  86.     property ParentCtl3D;
  87.     property ParentFont;
  88.     property ParentShowHint;
  89.     property PopupMenu;
  90.     property Selection: Integer read FSelection write SetSelection default 0;
  91.     property ShowHint;
  92.     property TabOrder;
  93.     property TabStop;
  94.     property Visible;
  95.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  96.     property OnClick;
  97.     property OnDragDrop;
  98.     property OnDragOver;
  99.     property OnEndDrag;
  100.     property OnEnter;
  101.     property OnExit;
  102.     property OnKeyDown;
  103.     property OnKeyPress;
  104.     property OnKeyUp;
  105.     property OnMouseDown;
  106.     property OnMouseMove;
  107.     property OnMouseUp;
  108.     property OnStartDrag;
  109.   end;
  110.  
  111. implementation
  112.  
  113. uses SysUtils, Consts, StdCtrls;
  114.  
  115. constructor TColorGrid.Create(AOwner: TComponent);
  116. begin
  117.   inherited Create(AOwner);
  118.   ControlStyle := ControlStyle + [csOpaque];
  119.   FGridOrdering := go4x4;
  120.   FNumXSquares := 4;
  121.   FNumYSquares := 4;
  122.   FForegroundEnabled := True;
  123.   FBackgroundEnabled := True;
  124.   Color := clBtnFace;
  125.   Canvas.Brush.Style := bsSolid;
  126.   Canvas.Pen.Color := clBlack;
  127.   SetBounds(0, 0, 100, 100);
  128.   GetPaletteEntries(GetStockObject(DEFAULT_PALETTE), 0, NumPaletteEntries,
  129.     FPaletteEntries);
  130. end;
  131.  
  132. function TColorGrid.ColorToIndex(AColor: TColor): Integer;
  133. var
  134.   I: Integer;
  135.   RealColor: TColor;
  136. begin
  137.   Result := 0;
  138.   I := 0;
  139.   RealColor := ColorToRGB(AColor);
  140.   while I < 20 do
  141.   begin
  142.     with FPaletteEntries[I] do
  143.       if RealColor = TColor(RGB(peRed, peGreen, peBlue)) then Exit;
  144.     if I <> 7 then
  145.       Inc(I)
  146.     else
  147.       Inc(I, 5);
  148.     Inc(Result);
  149.   end;
  150.   Result := -1;    
  151. end;
  152.  
  153. procedure TColorGrid.CreateWnd;
  154. begin
  155.   inherited CreateWnd;
  156.   SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE)
  157.     or WS_CLIPSIBLINGS);
  158. end;
  159.  
  160. procedure TColorGrid.DrawSquare(Which: Integer; ShowSelector: Boolean);
  161. var
  162.   WinTop, WinLeft: Integer;
  163.   PalIndex: Integer;
  164.   CellRect: TRect;
  165. begin
  166.   if (Which >=0) and (Which <= 15) then
  167.   begin
  168.     if Which < 8 then
  169.       PalIndex := Which else PalIndex := Which + 4;
  170.     WinTop := (Which div FNumXSquares) * FCellYSize;
  171.     WinLeft := (Which mod FNumXSquares) * FCellXSize;
  172.     CellRect := Bounds(WinLeft, WinTop, FCellXSize, FCellYSize);
  173.     if Ctl3D then
  174.     begin
  175.       Canvas.Pen.Color := clBtnFace;
  176.       with CellRect do Canvas.Rectangle(Left, Top, Right, Bottom);
  177.       InflateRect(CellRect, -1, -1);
  178.       Frame3D(Canvas, CellRect, clBtnShadow, clBtnHighlight, 2);
  179.     end else Canvas.Pen.Color := clBlack;
  180.     with FPaletteEntries[PalIndex] do
  181.     begin
  182.       Canvas.Brush.Color := TColor(RGB(peRed, peGreen, peBlue));
  183.       if Ctl3D then Canvas.Pen.Color := TColor(RGB(peRed, peGreen, peBlue));
  184.     end;
  185.     if not ShowSelector then with CellRect do
  186.       Canvas.Rectangle(Left, Top, Right, Bottom)
  187.     else with CellRect do
  188.     begin
  189.       if Ctl3D then
  190.       begin
  191.         Canvas.Rectangle(Left, Top, Right, Bottom);
  192.         InflateRect(CellRect, -1, -1);
  193.         DrawFocusRect(Canvas.Handle, CellRect);
  194.       end else with Canvas do
  195.       begin
  196.         Pen.Color := clBlack;
  197.         Pen.Mode := pmNot;
  198.         Rectangle(Left, Top, Right, Bottom);
  199.         Pen.Mode := pmCopy;
  200.         Rectangle(Left + 2, Top + 2, Right - 2, Bottom - 2);
  201.       end;
  202.     end;
  203.   end;
  204. end;
  205.  
  206. procedure TColorGrid.DrawFgBg;
  207. var
  208.   TextColor: TPaletteEntry;
  209.   PalIndex: Integer;
  210.   TheText: string;
  211.   OldBkMode: Integer;
  212.   R: TRect;
  213.  
  214.   function TernaryOp(Test: Boolean; ResultTrue, ResultFalse: Integer): Integer;
  215.   begin
  216.     if Test then
  217.       Result := ResultTrue
  218.     else Result := ResultFalse;
  219.   end;
  220.  
  221. begin
  222.   OldBkMode := SetBkMode(Canvas.Handle, TRANSPARENT);
  223.   if FForegroundEnabled then
  224.   begin
  225.     if (FForegroundIndex = FBackgroundIndex) and FBackgroundEnabled then
  226.       TheText := SFB else TheText := SFG;
  227.     if FForegroundIndex < 8 then
  228.       PalIndex := FForegroundIndex else PalIndex := FForegroundIndex + 4;
  229.     TextColor := FPaletteEntries[PalIndex];
  230.     with TextColor do
  231.     begin
  232.       peRed := TernaryOp(peRed >= $80, 0, $FF);
  233.       peGreen := TernaryOp(peGreen >= $80, 0, $FF);
  234.       peBlue := TernaryOp(peBlue >= $80, 0, $FF);
  235.       Canvas.Font.Color := TColor(RGB(peRed, peGreen, peBlue));
  236.     end;
  237.     with R do
  238.     begin
  239.       left := (FForegroundIndex mod FNumXSquares) * FCellXSize;
  240.       right := left + FCellXSize;
  241.       top := (FForegroundIndex div FNumXSquares) * FCellYSize;
  242.       bottom := top + FCellYSize;
  243.     end;
  244.     DrawText(Canvas.Handle, PChar(TheText), -1, R,
  245.        DT_NOCLIP or DT_SINGLELINE or DT_CENTER or DT_VCENTER);
  246.   end;
  247.   if FBackgroundEnabled then
  248.   begin
  249.     if (FForegroundIndex = FBackgroundIndex) and FForegroundEnabled then
  250.       TheText := SFB else TheText := SBG;
  251.     if FBackgroundIndex < 8 then
  252.       PalIndex := FBackgroundIndex else PalIndex := FBackgroundIndex + 4;
  253.     TextColor := FPaletteEntries[PalIndex];
  254.     with TextColor do
  255.     begin
  256.       peRed := TernaryOp(peRed >= $80, 0, $FF);
  257.       peGreen := TernaryOp(peGreen >= $80, 0, $FF);
  258.       peBlue := TernaryOp(peBlue >= $80, 0, $FF);
  259.       Canvas.Font.Color := TColor(RGB(peRed, peGreen, peBlue));
  260.     end;
  261.     with R do
  262.     begin
  263.       left := (FBackgroundIndex mod FNumXSquares) * FCellXSize;
  264.       right := left + FCellXSize;
  265.       top := (FBackgroundIndex div FNumXSquares) * FCellYSize;
  266.       bottom := top + FCellYSize;
  267.     end;
  268.     DrawText(Canvas.Handle, PChar(TheText), -1, R,
  269.       DT_NOCLIP or DT_SINGLELINE or DT_CENTER or DT_VCENTER);
  270.   end;
  271.   SetBkMode(Canvas.Handle, OldBkMode);
  272. end;
  273.  
  274. procedure TColorGrid.EnableForeground(Value: Boolean);
  275. begin
  276.   if FForegroundEnabled = Value then Exit;
  277.   FForegroundEnabled := Value;
  278.   DrawSquare(FForegroundIndex, (FForegroundIndex = FSelection) and FHasFocus);
  279.   DrawFgBg;
  280. end;
  281.  
  282. procedure TColorGrid.EnableBackground(Value: Boolean);
  283. begin
  284.   if FBackgroundEnabled = Value then Exit;
  285.   FBackgroundEnabled := Value;
  286.   DrawSquare(FBackgroundIndex, (FBackgroundIndex = FSelection) and FHasFocus);
  287.   DrawFgBg;
  288. end;
  289.  
  290. function TColorGrid.GetForegroundColor: TColor;
  291. var
  292.   PalIndex: Integer;
  293. begin
  294.   if FForegroundIndex < 8 then
  295.     PalIndex := FForegroundIndex else PalIndex := FForegroundIndex + 4;
  296.   with FPaletteEntries[PalIndex] do
  297.     Result := TColor(RGB(peRed, peGreen, peBlue));
  298. end;
  299.  
  300. function TColorGrid.GetBackgroundColor: TColor;
  301. var
  302.   PalIndex: Integer;
  303. begin
  304.   if FBackgroundIndex < 8 then
  305.     PalIndex := FBackgroundIndex else PalIndex := FBackgroundIndex + 4;
  306.   with FPaletteEntries[PalIndex] do
  307.     Result := TColor(RGB(peRed, peGreen, peBlue));
  308. end;
  309.  
  310. procedure TColorGrid.WMSetFocus(var Message: TWMSetFocus);
  311. begin
  312.   FHasFocus := True;
  313.   DrawSquare(FSelection, True);
  314.   DrawFgBg;
  315.   inherited;
  316. end;
  317.  
  318. procedure TColorGrid.WMKillFocus(var Message: TWMKillFocus);
  319. begin
  320.   FHasFocus := False;
  321.   DrawSquare(FSelection, False);
  322.   DrawFgBg;
  323.   inherited;
  324. end;
  325.  
  326. procedure TColorGrid.KeyDown(var Key: Word; Shift: TShiftState);
  327. var
  328.   NewSelection: Integer;
  329.   Range: Integer;
  330. begin
  331.   inherited KeyDown(Key, Shift);
  332.   NewSelection := FSelection;
  333.   Range := FNumXSquares * FNumYSquares;
  334.   case Key of
  335.     $46, $66:
  336.       begin
  337.         if not FForegroundEnabled and FClickEnablesColor then
  338.         begin
  339.           FForegroundEnabled := True;
  340.           DrawSquare(FForegroundIndex, (FForegroundIndex = FSelection) and FHasFocus);
  341.           FForegroundIndex := -1;
  342.         end;
  343.         SetForegroundIndex(NewSelection);
  344.         SetSelection(NewSelection);
  345.         Click;
  346.       end;
  347.     $42, $62:
  348.       begin
  349.         if not FBackgroundEnabled and FClickEnablesColor then
  350.         begin
  351.           FBackgroundEnabled := True;
  352.           DrawSquare(FBackgroundIndex, (FBackgroundIndex = FSelection) and FHasFocus);
  353.           FBackgroundIndex := -1;
  354.         end;
  355.         SetBackgroundIndex(NewSelection);
  356.         SetSelection(NewSelection);
  357.         Click;
  358.       end;
  359.     VK_HOME: NewSelection := 0;
  360.     VK_UP:
  361.       if FSelection >= FNumXSquares then
  362.         NewSelection := FSelection - FNumXSquares
  363.       else if FSelection <> 0 then
  364.         NewSelection := Range - FNumXSquares + FSelection - 1
  365.       else NewSelection := Range - 1;
  366.     VK_LEFT:
  367.       if FSelection <> 0 then
  368.         NewSelection := FSelection - 1
  369.       else NewSelection := Range - 1;
  370.     VK_DOWN:
  371.       if FSelection + FNumXSquares < Range then
  372.         NewSelection := FSelection + FNumXSquares
  373.       else if FSelection <> Range - 1 then
  374.         NewSelection := FSelection mod FNumXSquares + 1
  375.       else NewSelection := 0;
  376.     VK_SPACE,
  377.     VK_RIGHT:
  378.       if FSelection <> Range - 1 then
  379.         NewSelection := FSelection + 1
  380.       else NewSelection := 0;
  381.     VK_END: NewSelection := Range - 1;
  382.   else
  383.     inherited KeyDown(Key, Shift);
  384.     Exit;
  385.   end;
  386.   Key := 0;
  387.   if FSelection <> NewSelection then
  388.     SetSelection(NewSelection);
  389. end;
  390.  
  391. procedure TColorGrid.WMGetDlgCode(var Message: TWMGetDlgCode);
  392. begin
  393.   Message.Result := DLGC_WANTARROWS + DLGC_WANTCHARS;
  394. end;
  395.  
  396. procedure TColorGrid.WMSize(var Message: TWMSize);
  397. begin
  398.   DisableAlign;
  399.   try
  400.     inherited;
  401.     UpdateCellSizes(False);
  402.   finally
  403.     EnableAlign;
  404.   end;
  405. end;
  406.  
  407. procedure TColorGrid.CMCtl3DChanged(var Message: TMessage);
  408. begin
  409.   inherited;
  410.   Invalidate;
  411. end;
  412.  
  413. procedure TColorGrid.MouseDown(Button: TMouseButton; Shift: TShiftState;
  414.   X, Y: Integer);
  415. var
  416.   Square: Integer;
  417. begin
  418.   inherited MouseDown(Button, Shift, X, Y);
  419.   FButton := Button;
  420.   FButtonDown := True;
  421.   Square := SquareFromPos(X, Y);
  422.   if Button = mbLeft then
  423.   begin
  424.     if not FForegroundEnabled and FClickEnablesColor then
  425.     begin
  426.       FForegroundEnabled := True;
  427.       DrawSquare(FForegroundIndex, (FForegroundIndex = FSelection) and FHasFocus);
  428.       FForegroundIndex := -1;
  429.     end;
  430.     SetForegroundIndex(Square);
  431.   end
  432.   else begin
  433.     MouseCapture := True;
  434.     if not FBackgroundEnabled and FClickEnablesColor then
  435.     begin
  436.       FBackgroundEnabled := True;
  437.       DrawSquare(FBackgroundIndex, (FBackgroundIndex = FSelection) and FHasFocus);
  438.       FBackgroundIndex := -1;
  439.     end;
  440.     SetBackgroundIndex(Square);
  441.   end;
  442.   SetSelection(Square);
  443.   if TabStop then SetFocus;
  444. end;
  445.  
  446. procedure TColorGrid.MouseMove(Shift: TShiftState; X, Y: Integer);
  447. var
  448.   Square: Integer;
  449. begin
  450.   inherited MouseMove(Shift, X, Y);
  451.   if FButtonDown then
  452.   begin
  453.     Square := SquareFromPos(X, Y);
  454.     if FButton = mbLeft then
  455.       SetForegroundIndex(Square)
  456.     else SetBackgroundIndex(Square);
  457.     SetSelection(Square);
  458.   end;
  459. end;
  460.  
  461. procedure TColorGrid.MouseUp(Button: TMouseButton; Shift: TShiftState;
  462.   X, Y: Integer);
  463. begin
  464.   inherited MouseUp(Button, Shift, X, Y);
  465.   FButtonDown := False;
  466.   if FButton = mbRight then
  467.   begin
  468.     MouseCapture := False;
  469.     Click;
  470.   end;
  471. end;
  472.  
  473. procedure TColorGrid.Paint;
  474. var
  475.   Row, Col, wEntryIndex: Integer;
  476. begin
  477.   Canvas.Font := Font;
  478.   for Row := 0 to FNumYSquares do
  479.     for Col := 0 to FNumXSquares do
  480.     begin
  481.       wEntryIndex := Row * FNumXSquares + Col;
  482.       DrawSquare(wEntryIndex, False);
  483.     end;
  484.   DrawSquare(FSelection, FHasFocus);
  485.   DrawFgBg;
  486. end;
  487.  
  488. procedure TColorGrid.SetBackgroundIndex(Value: Integer);
  489. begin
  490.   if (FBackgroundIndex <> Value) and FBackgroundEnabled then
  491.   begin
  492.     DrawSquare(FBackgroundIndex, (FBackgroundIndex = FSelection) and FHasFocus);
  493.     FBackgroundIndex := Value;
  494.     if FBackgroundIndex = FForegroundIndex then
  495.       DrawSquare(FBackgroundIndex, (FBackgroundIndex = FSelection) and FHasFocus);
  496.     DrawFgBg;
  497.     Change;
  498.   end;
  499. end;
  500.  
  501. procedure TColorGrid.SetForegroundIndex(Value: Integer);
  502. begin
  503.   if (FForegroundIndex <> Value) and FForegroundEnabled then
  504.   begin
  505.     DrawSquare(FForegroundIndex, (FForegroundIndex = FSelection) and FHasFocus);
  506.     FForegroundIndex := Value;
  507.     if FForegroundIndex = FBackgroundIndex then
  508.       DrawSquare(FForegroundIndex, (FForegroundIndex = FSelection) and FHasFocus);
  509.     DrawFgBg;
  510.     Change;
  511.   end;
  512. end;
  513.  
  514. procedure TColorGrid.SetGridOrdering(Value: TGridOrdering);
  515. begin
  516.   if FGridOrdering = Value then Exit;
  517.   FGridOrdering := Value;
  518.   FNumXSquares := 16 shr Ord(FGridOrdering);
  519.   FNumYSquares := 1 shl Ord(FGridOrdering);
  520.   UpdateCellSizes(True);
  521. end;
  522.  
  523. procedure TColorGrid.SetSelection(Value: Integer);
  524. begin
  525.   if FSelection = Value then Exit;
  526.   DrawSquare(FSelection, False);
  527.   FSelection := Value;
  528.   DrawSquare(FSelection, FHasFocus);
  529.   DrawFgBg;
  530. end;
  531.  
  532. function TColorGrid.SquareFromPos(X, Y: Integer): Integer;
  533. begin
  534.   if X > Width - 1 then X := Width - 1
  535.   else if X < 0 then X := 0;
  536.   if Y > Height - 1 then Y := Height - 1
  537.   else if Y < 0 then Y := 0;
  538.   Result := (Y div FCellYSize) * FNumXSquares + (X div FCellXSize);
  539. end;
  540.  
  541. procedure TColorGrid.UpdateCellSizes(DoRepaint: Boolean);
  542. var
  543.   NewWidth, NewHeight: Integer;
  544. begin
  545.   NewWidth := (Width div FNumXSquares) * FNumXSquares;
  546.   NewHeight := (Height div FNumYSquares) * FNumYSquares;
  547.   BoundsRect := Bounds(Left, Top, NewWidth, NewHeight);
  548.   FCellXSize := Width div FNumXSquares;
  549.   FCellYSize := Height div FNumYSquares;
  550.   if DoRepaint then Invalidate;
  551. end;
  552.  
  553. procedure TColorGrid.Change;
  554. begin
  555.   Changed;
  556.   if Assigned(FOnChange) then FOnChange(Self);
  557. end;
  558.  
  559. end.
  560.