www.pudn.com > Tank拊親蚔牁測鎢.rar > MAIN.PAS


unit main; 
 
interface 
 
uses 
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
  Menus, StdCtrls, ExtCtrls, Spin, Grids, ExtDlgs, Math, TileUnit, ComCtrls; 
 
type 
  TMainForm = class(TForm) 
    mnuMain: TMainMenu; 
    F1: TMenuItem; 
    H1: TMenuItem; 
    mnuAbout: TMenuItem; 
    mnuExit: TMenuItem; 
    N1: TMenuItem; 
    mnuOpen: TMenuItem; 
    mnuSave: TMenuItem; 
    mnuNew: TMenuItem; 
    dlgOpen: TOpenDialog; 
    dlgSave: TSaveDialog; 
    mnuSaveAs: TMenuItem; 
    N3: TMenuItem; 
    dlgOpenPicture: TOpenPictureDialog; 
    tvwTiles: TTreeView; 
    stbMain: TStatusBar; 
    pnlRight: TPanel; 
    Splitter1: TSplitter; 
    grdTile: TDrawGrid; 
    lblTileNo: TLabel; 
    lblDimension: TLabel; 
    GroupBox1: TGroupBox; 
    cbxCanPass: TCheckBox; 
    cbxBulletCanPass: TCheckBox; 
    cbxCanBreak: TCheckBox; 
    mnuTiles: TMenuItem; 
    mnuAdd: TMenuItem; 
    mnuRemove: TMenuItem; 
    cbxFlag: TCheckBox; 
    procedure mnuExitClick(Sender: TObject); 
    procedure FormCreate(Sender: TObject); 
    procedure FormClose(Sender: TObject; var Action: TCloseAction); 
    procedure mnuNewClick(Sender: TObject); 
    procedure mnuOpenClick(Sender: TObject); 
    procedure mnuSaveClick(Sender: TObject); 
    procedure grdTileDrawCell(Sender: TObject; ACol, ARow: Integer; 
      Rect: TRect; State: TGridDrawState); 
    procedure mnuAboutClick(Sender: TObject); 
    procedure grdTileSelectCell(Sender: TObject; ACol, ARow: Integer; 
      var CanSelect: Boolean); 
    procedure tvwTilesChange(Sender: TObject; Node: TTreeNode); 
    procedure mnuAddClick(Sender: TObject); 
    procedure mnuRemoveClick(Sender: TObject); 
  private 
    FFileName: string; 
    FFirstNo: Integer; 
     
    procedure BackupAttr(Col, Row: Integer); 
    procedure RestoreAttr(Col, Row: Integer); 
     
    procedure UpdateControlStatus; 
  public 
    { Public declarations } 
  end; 
   
var 
  MainForm: TMainForm; 
   
implementation 
 
uses util, about, xFiles; 
 
{$R *.DFM} 
 
procedure TMainForm.mnuExitClick(Sender: TObject); 
begin 
  Close; 
end; 
 
procedure TMainForm.FormCreate(Sender: TObject); 
begin 
  Tiles := TTiles.Create; // 建立圖庫物件 
 
  mnuNewClick(nil); 
end; 
 
procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction); 
begin 
  Tiles.Free; 
end; 
 
procedure TMainForm.mnuNewClick(Sender: TObject); 
begin 
  Tiles.FreeTiles; // 新的圖庫 
  FFileName := ''; 
  FFirstNo := -1; 
  tvwTiles.Items.Clear; 
 
  UpdateControlStatus; 
end; 
 
procedure TMainForm.mnuOpenClick(Sender: TObject); 
begin 
  with dlgOpen do 
    if Execute then // 開啟舊檔對話盒 
      try 
        mnuNewClick(nil); // 先釋放圖庫內容 
 
        // 載入圖庫 
        Tiles.LoadFromFile(Filename); 
        // 讀取圖片群組描述 
        ReadComponentResFile(ChangeFileExt(Filename, '.TVW'), 
          tvwTiles); 
 
        FFileName := Filename; // 讀取地形圖庫成功 
 
       // 若末選擇任何群組, 則幫他選擇第一個節點         
        if tvwTiles.Selected = nil then 
          tvwTiles.Selected := tvwTiles.Items[0]; 
      finally 
        UpdateControlStatus; 
      end; 
end; 
 
procedure TMainForm.mnuSaveClick(Sender: TObject); 
begin 
  // 若是"另存新檔" 或還未指定檔名, 就先問使用者檔名 
  if ((Sender as TComponent).Tag = 1) or (FFileName = '') then 
  begin 
    dlgSave.Filter := dlgOpen.Filter; 
    // 詢問使用者檔名, 若按取消就離開 
    if not dlgSave.Execute then Exit; 
    FFileName := dlgSave.Filename; // 將檔名記起來 
  end; 
 
  BackupAttr(grdTile.Col, grdTile.Row); // 儲存目前圖片屬性 
 
  Tiles.SaveToFile(FFileName); // 儲存圖庫 
  // 儲存圖片群組描述 
  WriteComponentResFile(ChangeFileExt(FFileName, '.TVW'), 
    tvwTiles); 
  UpdateControlStatus; // 更新視窗標題 
end; 
 
procedure TMainForm.UpdateControlStatus; 
var 
  sFileName: string; 
begin 
  sFileName := FFileName; 
  if sFileName = '' then sFileName := 'Untitled'; 
  Caption := Format('%s - %s',[Application.Title, sFileName]); 
   
  stbMain.SimpleText := Format('圖片總數: %d',[Tiles.TileNum]); 
   
  mnuSave.Enabled := Tiles.TileNum <> 0; 
  mnuSaveAs.Enabled := Tiles.TileNum <> 0; 
   
  grdTile.Invalidate; 
end; 
 
procedure TMainForm.grdTileDrawCell(Sender: TObject; ACol, 
    ARow: Integer; Rect: TRect; State: TGridDrawState); 
var 
  No: Integer; // 對應的圖片編號 
begin 
  if tvwTiles.Selected = nil then Exit; // 一定要選擇某群組才行 
 
  // 此格所對應的圖片編號 = 首張圖片編號 + ARow * 橫軸數目 + ACol 
  No := Integer(tvwTiles.Selected.Data) + 
    ARow * grdTile.ColCount + ACol; 
  if No >= Tiles.TileNum then Exit; // 是否為合法編號 ? 
 
  with grdTile.Canvas do // 畫出對應的圖片 
    Draw(Rect.Left, Rect.Top, Tiles[No].Bitmap); 
end; 
 
procedure TMainForm.grdTileSelectCell(Sender: TObject; ACol, 
    ARow: Integer; var CanSelect: Boolean); 
begin 
  BackupAttr(grdTile.Col, grdTile.Row); 
  RestoreAttr(ACol, ARow); 
 
  lblTileNo.Caption := Format('編號: %d (%d - %d)',[FFirstNo, FFirstNo, FFirstNo + Tiles[FFirstNo].xNum * Tiles[FFirstNo].yNum - 1]); 
end; 
 
procedure TMainForm.BackupAttr(Col, Row: Integer); 
var 
  No: Integer; 
begin 
  if FFirstNo = -1 then Exit; 
 
  No := FFirstNo + Row * grdTile.ColCount + Col; // 計算原本選擇的圖片編號 
 
  // 將使用者設定的圖片屬性寫回去 
  Tiles[No].Attr := []; 
 
  // 可以穿越的地形 
  if cbxCanPass.Checked then Tiles[No].Attr := Tiles[No].Attr + [taCanpass]; 
  if cbxBulletCanPass.Checked then Tiles[No].Attr := Tiles[No].Attr + [taBulletCanpass]; 
  if cbxCanBreak.Checked then Tiles[No].Attr := Tiles[No].Attr + [taCanBreak]; 
  if cbxFlag.Checked then Tiles[No].Attr := Tiles[No].Attr + [taFlag]; 
end; 
 
procedure TMainForm.RestoreAttr(Col, Row: Integer); 
var 
  No: Integer; 
begin 
  if FFirstNo = -1 then Exit; 
 
  No := FFirstNo + Row * grdTile.ColCount + Col; // 計算即將選擇的圖片編號 
 
  // 將所選擇的圖片屬性由 checkbox 元件表現出來 
  cbxCanPass.Checked := taCanpass in Tiles[No].Attr; 
  cbxBulletCanPass.Checked := taBulletCanpass in Tiles[No].Attr; 
  cbxCanBreak.Checked := taCanBreak in Tiles[No].Attr; 
  cbxFlag.Checked := taFlag in Tiles[No].Attr; 
end; 
 
procedure TMainForm.mnuAboutClick(Sender: TObject); 
begin 
  with TAboutBox.Create(self) do 
    try 
      ShowModal; 
    finally 
      Free; 
    end; 
end; 
 
procedure TMainForm.tvwTilesChange(Sender: TObject; Node: TTreeNode); 
var 
  No: Integer; 
begin 
  if tvwTiles.Selected = nil then Exit; 
 
  // 儲回目前值 
  BackupAttr(grdTile.Col, grdTile.Row); 
 
  No := Integer(tvwTiles.Selected.Data); 
  if No < Tiles.TileNum then 
  begin 
    grdTile.ColCount := Tiles[No].xNum; 
    grdTile.RowCount := Tiles[No].yNum; 
 
    grdTile.Row := 0; 
    grdTile.Col := 0; 
 
    FFirstNo := No; 
    lblDimension.Caption := Format('大小: %d x %d',[Tiles[FFirstNo].xNum, Tiles[FFirstNo].yNum]); 
 
    RestoreAttr(0, 0); 
  end; 
 
  UpdateControlStatus; 
end; 
 
procedure TMainForm.mnuAddClick(Sender: TObject); 
 
  procedure AddTreeNode(const Filename: string; FirstNo: Integer); 
  begin 
    // 在樹狀檢視元件中加入此圖片群組的節點(描述) 
    // 圖片群組描述預設值為加入的 BMP 圖形檔檔名 
    with tvwTiles.Items.Add(nil, 
      ExtractFileNameNoExt(ExtractFileName(Filename))) do 
    begin 
      Data := Pointer(FirstNo);  // 記錄此群組對應的第一張圖片編號 
    end; 
 
    // 若末選擇任何群組, 則幫他選擇第一個節點 
    if tvwTiles.Selected = nil then 
      tvwTiles.Selected := tvwTiles.Items[0]; 
  end; 
 
var 
  Bits         : TBitmap; // 欲加入的 bitmap 
  X, Y, FirstNo: Integer; 
  xNum, yNum   : Integer; // 圖形切割後的橫軸及縱軸圖片數目 
  Tile         : TTile;   // 產生的新圖片 
begin 
  if dlgOpenPicture.Execute then 
    try 
      Bits := TBitmap.Create; // 產生及載入欲加入圖庫的 bitmap 
      Bits.LoadFromFile(dlgOpenPicture.Filename); 
 
      // 若 bitmap 比單張圖片的尺寸還小, 無法處理 
      if (Bits.Width < TILE_WIDTH) or (Bits.Height < TILE_HEIGHT) then 
        raise Exception.Create('Bitmap is too small'); 
 
      // 最大是 5 x 5 的圖片群組 
      xNum := Min(5, Bits.Width div TILE_WIDTH); 
      yNum := Min(5, Bits.Height div TILE_HEIGHT); 
 
      // 依序切割出 xNum * yNum 個圖片 
      for Y := 0 to yNum - 1 do 
        for X := 0 to xNum - 1 do 
        begin 
          Tile := TTile.Create;  // 產生圖片物件 
          // 將對應的圖形複製到圖片的 bitmap 上 
          Tile.Bitmap.Canvas.CopyRect(TILE_RECT, Bits.Canvas, 
            Rect(X * TILE_WIDTH, Y * TILE_HEIGHT, 
            (X + 1) * TILE_WIDTH, (Y + 1) * TILE_HEIGHT)); 
 
          Tile.FirstTile := (X = 0) and (Y = 0); // 是不是群組頭頭 
          Tile.xNum := xNum;  // 是群組頭頭的話, 負責記錄 
          Tile.yNum := yNum;  // 圖片群組的橫軸及縱軸圖片數目 
 
          // 將產生的新圖片加入圖庫中 
          if Tile.FirstTile then 
            FirstNo := Tiles.AddTile(Tile) // 取得此群組的頭頭編號 
          else 
            Tiles.AddTile(Tile); 
        end; 
 
      // 將群組描述加入樹狀檢視元件 
      AddTreeNode(dlgOpenPicture.Filename, FirstNo); 
 
      UpdateControlStatus; 
    finally 
      Bits.Free;  // 原始影像沒有用了, 釋放掉 
    end; 
end; 
 
procedure TMainForm.mnuRemoveClick(Sender: TObject); 
var 
  I, No: Integer; 
begin 
  if tvwTiles.Selected = nil then Exit; // 一定要選定某個群組才行 
 
  // 取得目前圖片群組首張圖片編號 
  No := Integer(tvwTiles.Selected.Data); 
 
  // 將整個圖片群組的圖片都設為"棄置" 
  for I := 0 to Tiles[No].xNum * Tiles[No].yNum - 1 do 
    Tiles[No + I].Disposed := True; 
 
  tvwTiles.Selected.Delete; // 將圖片群組描述砍掉 
  UpdateControlStatus; 
end; 
 
end.