home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 2000 March / pcp161b.iso / full / delphi / RUNIMAGE / DELPHI30 / SOURCE / VCL / MPLAYER.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-08-03  |  45.1 KB  |  1,572 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Delphi Visual Component Library                 }
  5. {                                                       }
  6. {       Copyright (c) 1995,97 Borland International     }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit MPlayer;
  11.  
  12. {$R-}
  13.  
  14. interface
  15.  
  16. uses Windows, Classes, Controls, Forms, Graphics, Messages,
  17.   MMSystem, Dialogs, SysUtils;
  18.  
  19. type
  20.   TMPBtnType = (btPlay, btPause, btStop, btNext, btPrev, btStep, btBack,
  21.     btRecord, btEject);
  22.   TButtonSet = set of TMPBtnType;
  23.  
  24.   TMPGlyph = (mgEnabled, mgDisabled, mgColored);
  25.   TMPButton = record
  26.     Visible: Boolean;
  27.     Enabled: Boolean;
  28.     Colored: Boolean;
  29.     Auto: Boolean;
  30.     Bitmaps: array[TMPGlyph] of TBitmap;
  31.   end;
  32.  
  33.   TMPDeviceTypes = (dtAutoSelect, dtAVIVideo, dtCDAudio, dtDAT, dtDigitalVideo, dtMMMovie,
  34.     dtOther, dtOverlay, dtScanner, dtSequencer, dtVCR, dtVideodisc, dtWaveAudio);
  35.   TMPTimeFormats = (tfMilliseconds, tfHMS, tfMSF, tfFrames, tfSMPTE24, tfSMPTE25,
  36.     tfSMPTE30, tfSMPTE30Drop, tfBytes, tfSamples, tfTMSF);
  37.   TMPModes = (mpNotReady, mpStopped, mpPlaying, mpRecording, mpSeeking,
  38.     mpPaused, mpOpen);
  39.   TMPNotifyValues = (nvSuccessful, nvSuperseded, nvAborted, nvFailure);
  40.     
  41.   TMPDevCaps = (mpCanStep, mpCanEject, mpCanPlay, mpCanRecord, mpUsesWindow);
  42.   TMPDevCapsSet = set of TMPDevCaps;
  43.   
  44.   EMPNotify = procedure (Sender: TObject; Button: TMPBtnType;
  45.     var DoDefault: Boolean) of object;
  46.   EMPPostNotify = procedure (Sender: TObject; Button: TMPBtnType) of object;
  47.  
  48.   EMCIDeviceError = class(Exception);
  49.   
  50.   TMediaPlayer = class(TCustomControl)
  51.   private
  52.     Buttons: array[TMPBtnType] of TMPButton;
  53.     FVisibleButtons: TButtonSet;
  54.     FEnabledButtons: TButtonSet;
  55.     FColoredButtons: TButtonSet;
  56.     FAutoButtons: TButtonSet;
  57.     Pressed: Boolean;
  58.     Down: Boolean;
  59.     CurrentButton: TMPBtnType;
  60.     CurrentRect: TRect;
  61.     ButtonWidth: Integer;
  62.     MinBtnSize: TPoint;
  63.     FOnClick: EMPNotify;
  64.     FOnPostClick: EMPPostNotify;
  65.     FOnNotify: TNotifyEvent;
  66.     FocusedButton: TMPBtnType;
  67.     MCIOpened: Boolean;
  68.     FCapabilities: TMPDevCapsSet;
  69.     FCanPlay: Boolean;
  70.     FCanStep: Boolean;
  71.     FCanEject: Boolean;
  72.     FCanRecord: Boolean;
  73.     FHasVideo: Boolean;
  74.     FFlags: Longint;
  75.     FWait: Boolean;
  76.     FNotify: Boolean;
  77.     FUseWait: Boolean;
  78.     FUseNotify: Boolean;
  79.     FUseFrom: Boolean;
  80.     FUseTo: Boolean;
  81.     FDeviceID: Word;
  82.     FDeviceType: TMPDeviceTypes;
  83.     FTo: Longint;
  84.     FFrom: Longint;
  85.     FFrames: Longint;
  86.     FError: Longint;
  87.     FNotifyValue: TMPNotifyValues;
  88.     FDisplay: TWinControl;
  89.     FDWidth: Integer;
  90.     FDHeight: Integer;
  91.     FElementName: string;
  92.     FAutoEnable: Boolean;
  93.     FAutoOpen: Boolean;
  94.     FAutoRewind: Boolean;
  95.     FShareable: Boolean;
  96.  
  97.     procedure LoadBitmaps;
  98.     procedure DestroyBitmaps;
  99.     procedure SetEnabledButtons(Value: TButtonSet);
  100.     procedure SetColored(Value: TButtonSet);
  101.     procedure SetVisible(Value: TButtonSet);
  102.     procedure SetAutoEnable(Value: Boolean);
  103.     procedure DrawAutoButtons;
  104.     procedure DoMouseDown(XPos, YPos: Integer);
  105.     procedure WMLButtonDown(var Message: TWMLButtonDown);
  106.       message WM_LButtonDown;
  107.     procedure WMLButtonDblClk(var Message: TWMLButtonDblClk);
  108.       message WM_LButtonDblClk;
  109.     procedure WMMouseMove(var Message: TWMMouseMove);
  110.       message WM_MouseMove;
  111.     procedure WMLButtonUp(var Message: TWMLButtonUp);
  112.       message WM_LButtonUp;
  113.     procedure WMSetFocus(var Message: TWMSetFocus);
  114.       message WM_SETFOCUS;
  115.     procedure WMKillFocus(var Message: TWMKillFocus);
  116.       message WM_KILLFOCUS;
  117.     procedure WMGetDlgCode(var Message: TWMGetDlgCode);
  118.       message WM_GETDLGCODE;
  119.     procedure WMSize(var Message: TWMSize);
  120.       message WM_SIZE;
  121.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  122.     function VisibleButtonCount: Integer;
  123.     procedure Adjust;
  124.     procedure DoClick(Button: TMPBtnType);
  125.     procedure DoPostClick(Button: TMPBtnType);
  126.     procedure DrawButton(Btn: TMPBtnType; X: Integer);
  127.     procedure CheckIfOpen;
  128.     procedure SetPosition(Value: Longint);
  129.     procedure SetDeviceType( Value: TMPDeviceTypes );
  130.     procedure SetWait( Flag: Boolean );
  131.     procedure SetNotify( Flag: Boolean );
  132.     procedure SetFrom( Value: Longint );
  133.     procedure SetTo( Value: Longint );
  134.     procedure SetTimeFormat( Value: TMPTimeFormats );
  135.     procedure SetDisplay( Value: TWinControl );
  136.     procedure SetOrigDisplay;
  137.     procedure SetDisplayRect( Value: TRect );
  138.     function GetDisplayRect: TRect;
  139.     procedure GetDeviceCaps;
  140.     function GetStart: Longint;
  141.     function GetLength: Longint;
  142.     function GetMode: TMPModes;
  143.     function GetTracks: Longint;
  144.     function GetPosition: Longint;
  145.     function GetErrorMessage: string;
  146.     function GetTimeFormat: TMPTimeFormats;
  147.     function GetTrackLength(TrackNum: Integer): Longint;
  148.     function GetTrackPosition(TrackNum: Integer): Longint;
  149.   protected
  150.     procedure Loaded; override;
  151.     procedure AutoButtonSet(Btn: TMPBtnType); dynamic;
  152.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  153.     procedure Paint; override;
  154.     procedure MMNotify(var Message: TMessage); message MM_MCINOTIFY;
  155.     procedure Click(Button: TMPBtnType; var DoDefault: Boolean); dynamic;
  156.     procedure PostClick(Button: TMPBtnType); dynamic;
  157.     procedure DoNotify; dynamic;
  158.     procedure Updated; override;
  159.   public
  160.     constructor Create(AOwner: TComponent); override;
  161.     destructor Destroy; override;
  162.     procedure Open;
  163.     procedure Close;
  164.     procedure Play;
  165.     procedure Stop;
  166.     procedure Pause; {Pause & Resume/Play}
  167.     procedure Step;
  168.     procedure Back;
  169.     procedure Previous;
  170.     procedure Next;
  171.     procedure StartRecording;
  172.     procedure Eject;
  173.     procedure Save;
  174.     procedure PauseOnly;
  175.     procedure Resume;
  176.     procedure Rewind;
  177.     property TrackLength[TrackNum: Integer]: Longint read GetTrackLength;
  178.     property TrackPosition[TrackNum: Integer]: Longint read GetTrackPosition;
  179.     property Capabilities: TMPDevCapsSet read FCapabilities;
  180.     property Error: Longint read FError;
  181.     property ErrorMessage: string read GetErrorMessage;
  182.     property Start: Longint read GetStart;
  183.     property Length: Longint read GetLength;
  184.     property Tracks: Longint read GetTracks;
  185.     property Frames: Longint read FFrames write FFrames;
  186.     property Mode: TMPModes read GetMode;
  187.     property Position: Longint read GetPosition write SetPosition;
  188.     property Wait: Boolean read FWait write SetWait;
  189.     property Notify: Boolean read FNotify write SetNotify;
  190.     property NotifyValue: TMPNotifyValues read FNotifyValue;
  191.     property StartPos: Longint read FFrom write SetFrom;
  192.     property EndPos: Longint read FTo write SetTo;
  193.     property DeviceID: Word read FDeviceID;
  194.     property TimeFormat: TMPTimeFormats read GetTimeFormat write SetTimeFormat;
  195.     property DisplayRect: TRect read GetDisplayRect write SetDisplayRect;
  196.   published
  197.     property ColoredButtons: TButtonSet read FColoredButtons write SetColored
  198.        default [btPlay, btPause, btStop, btNext, btPrev, btStep, btBack,
  199.       btRecord, btEject];
  200.     property Enabled;
  201.     property EnabledButtons: TButtonSet read FEnabledButtons write SetEnabledButtons
  202.        default [btPlay, btPause, btStop, btNext, btPrev, btStep, btBack,
  203.       btRecord, btEject];
  204.     property VisibleButtons: TButtonSet read FVisibleButtons write SetVisible
  205.        default [btPlay, btPause, btStop, btNext, btPrev, btStep, btBack,
  206.       btRecord, btEject];
  207.     property AutoEnable: Boolean read FAutoEnable write SetAutoEnable default True;
  208.     property AutoOpen: Boolean read FAutoOpen write FAutoOpen default False;
  209.     property AutoRewind: Boolean read FAutoRewind write FAutoRewind default True;
  210.     property DeviceType: TMPDeviceTypes read FDeviceType write SetDeviceType default dtAutoSelect;
  211.     property Display: TWinControl read FDisplay write SetDisplay;
  212.     property FileName: string read FElementName write FElementName;
  213.     property Shareable: Boolean read FShareable write FShareable default False;
  214.     property Visible;
  215.     property ParentShowHint;
  216.     property ShowHint;
  217.     property PopupMenu;
  218.     property TabOrder;
  219.     property TabStop default True;
  220.     property OnClick: EMPNotify read FOnClick write FOnClick;
  221.     property OnEnter;
  222.     property OnExit;
  223.     property OnPostClick: EMPPostNotify read FOnPostClick write FOnPostClick;
  224.     property OnNotify: TNotifyEvent read FOnNotify write FOnNotify;
  225.   end;
  226.  
  227. implementation
  228.  
  229. uses Consts;
  230.  
  231. {$R MPLAYER}
  232.  
  233. const
  234.   mci_Back     = $0899;  { mci_Step reverse }
  235.  
  236.   BtnStateName: array[TMPGlyph] of PChar = ('EN', 'DI', 'CL');
  237.   BtnTypeName: array[TMPBtnType] of PChar = ('MPPLAY', 'MPPAUSE', 'MPSTOP',
  238.     'MPNEXT', 'MPPREV', 'MPSTEP', 'MPBACK', 'MPRECORD', 'MPEJECT');
  239.  
  240. constructor TMediaPlayer.Create(AOwner: TComponent);
  241. var
  242.   I: TMPBtnType;
  243. begin
  244.   inherited Create(AOwner);
  245.   ControlStyle := ControlStyle + [csOpaque];
  246.   LoadBitmaps;
  247.   FVisibleButtons := [btPlay, btPause, btStop, btNext, btPrev, btStep,
  248.     btBack, btRecord, btEject];
  249.   FEnabledButtons := [btPlay, btPause, btStop, btNext, btPrev, btStep,
  250.     btBack, btRecord, btEject];
  251.   FColoredButtons := [btPlay, btPause, btStop, btNext, btPrev, btStep,
  252.     btBack, btRecord, btEject];
  253.   for I := Low(Buttons) to High(Buttons) do
  254.   begin
  255.     Buttons[I].Visible := True;
  256.     Buttons[I].Enabled := True;
  257.     Buttons[I].Colored := True;
  258.     Buttons[I].Auto := False; {enabled/disabled dynamically}
  259.   end;
  260.   Width := 240;
  261.   Height := 30;
  262.   FocusedButton := btPlay;
  263.   FAutoEnable := True;
  264.   FAutoOpen := False;
  265.   FAutoRewind := True;
  266.   FDeviceType := dtAutoSelect; {select through file name extension}
  267.   TabStop := True;
  268. end;
  269.  
  270. destructor TMediaPlayer.Destroy;
  271. var
  272.   GenParm: TMCI_Generic_Parms;
  273. begin
  274.   if FDeviceID <> 0 then
  275.     mciSendCommand( FDeviceID, mci_Close, mci_Wait, Longint(@GenParm));
  276.   DestroyBitmaps;
  277.   inherited Destroy;
  278. end;
  279.  
  280. procedure TMediaPlayer.Loaded;
  281. begin
  282.   inherited Loaded;
  283.   if (not (csDesigning in ComponentState)) and FAutoOpen then
  284.     Open;
  285. end;
  286.  
  287. procedure TMediaPlayer.LoadBitmaps;
  288. var
  289.   I: TMPBtnType;
  290.   J: TMPGlyph;
  291.   ResName: array[0..40] of Char;
  292. begin
  293.   MinBtnSize := Point(0, 0);
  294.   for I := Low(Buttons) to High(Buttons) do
  295.   begin
  296.     for J := Low(TMPGlyph) to High(TMPGlyph) do
  297.     begin
  298.       Buttons[I].Bitmaps[J] := TBitmap.Create;
  299.       Buttons[I].Bitmaps[J].Handle := LoadBitmap(HInstance,
  300.         StrFmt(ResName, '%s_%s', [BtnStateName[J], BtnTypeName[I]]));
  301.       if MinBtnSize.X < Buttons[I].Bitmaps[J].Width then
  302.         MinBtnSize.X := Buttons[I].Bitmaps[J].Width;
  303.       if MinBtnSize.Y < Buttons[I].Bitmaps[J].Height then
  304.         MinBtnSize.Y := Buttons[I].Bitmaps[J].Height;
  305.     end;
  306.   end;
  307.   Inc(MinBtnSize.X, 2 * 4);
  308.   Inc(MinBtnSize.Y, 2 * 2);
  309. end;
  310.  
  311. procedure TMediaPlayer.DestroyBitmaps;
  312. var
  313.   I: TMPBtnType;
  314.   J: TMPGlyph;
  315. begin
  316.   for I := Low(Buttons) to High(Buttons) do
  317.     for J := Low(TMPGlyph) to High(TMPGlyph) do
  318.       Buttons[I].Bitmaps[J].Free;
  319. end;
  320.  
  321.  
  322. procedure TMediaPlayer.SetAutoEnable(Value: Boolean);
  323. begin
  324.   if Value <> FAutoEnable then
  325.   begin
  326.     FAutoEnable := Value;
  327.     if FAutoEnable then
  328.       DrawAutoButtons  {paint buttons based on current state of device}
  329.     else
  330.       SetEnabledButtons(FEnabledButtons);  {paint buttons based on Enabled}
  331.   end;
  332. end;
  333.  
  334. procedure TMediaPlayer.SetEnabledButtons(Value: TButtonSet);
  335. var
  336.   I: TMPBtnType;
  337. begin
  338.   FEnabledButtons := Value;
  339.   for I := Low(Buttons) to High(Buttons) do
  340.     Buttons[I].Enabled := I in FEnabledButtons;
  341.   Invalidate;
  342. end;
  343.  
  344. procedure TMediaPlayer.DrawAutoButtons;
  345. var
  346.   I: TMPBtnType;
  347. begin
  348.   for I := Low(Buttons) to High(Buttons) do
  349.     Buttons[I].Auto := I in FAutoButtons;
  350.   Invalidate;
  351. end;
  352.  
  353. procedure TMediaPlayer.SetColored(Value: TButtonSet);
  354. var
  355.   I: TMPBtnType;
  356. begin
  357.   FColoredButtons := Value;
  358.   for I := Low(Buttons) to High(Buttons) do
  359.     Buttons[I].Colored := I in FColoredButtons;
  360.   Invalidate;
  361. end;
  362.  
  363. procedure TMediaPlayer.SetVisible(Value: TButtonSet);
  364. var
  365.   I: TMPBtnType;
  366. begin
  367.   FVisibleButtons := Value;
  368.   for I := Low(Buttons) to High(Buttons) do
  369.     Buttons[I].Visible := I in FVisibleButtons;
  370.   if csUpdating in ComponentState then
  371.   begin
  372.     ButtonWidth := ((Width - 1) div VisibleButtonCount) + 1;
  373.     Invalidate;
  374.   end
  375.   else Adjust;
  376. end;
  377.  
  378. function TMediaPlayer.VisibleButtonCount: Integer;
  379. var
  380.   I: TMPBtnType;
  381. begin
  382.   Result := 0;
  383.   for I := Low(Buttons) to High(Buttons) do
  384.     if Buttons[I].Visible then Inc(Result);
  385.   if Result = 0 then Inc(Result);
  386. end;
  387.  
  388. procedure TMediaPlayer.Adjust;
  389. var
  390.   Count: Integer;
  391. begin
  392.   Count := VisibleButtonCount;
  393.   Width := Count * (ButtonWidth - 1) + 1;
  394.   Invalidate;
  395. end;
  396.  
  397. procedure TMediaPlayer.WMSize(var Message: TWMSize);
  398. var
  399.   Count: Integer;
  400.   MinSize: TPoint;
  401.   W, H: Integer;
  402. begin
  403.   inherited;
  404.   if not (csUpdating in ComponentState) then
  405.   begin
  406.     { check for minimum size }
  407.     Count := VisibleButtonCount;
  408.     MinSize.X := Count * (MinBtnSize.X - 1) + 1;
  409.     MinSize.Y := MinBtnSize.Y;
  410.     ButtonWidth := ((Width - 1) div Count) + 1;
  411.  
  412.     W := Count * (ButtonWidth - 1) + 1;
  413.     if W < MinSize.X then W := MinSize.X;
  414.     if Height < MinSize.Y then H := MinSize.Y
  415.     else H := Height;
  416.  
  417.     if (W <> Width) or (H <> Height) then
  418.       SetBounds(Left, Top, W, H);
  419.  
  420.     Message.Result := 0;
  421.   end;
  422. end;
  423.  
  424. procedure TMediaPlayer.DrawButton(Btn: TMPBtnType; X: Integer);
  425. var
  426.   IsDown: Boolean;
  427.   BX, BY: Integer;
  428.   TheGlyph: TMPGlyph;
  429.   Bitmap: TBitmap;
  430.   R: TRect;
  431. begin
  432.   IsDown := Down and (Btn = CurrentButton);
  433.   with Canvas do
  434.   begin
  435.     Brush.Style := bsSolid;
  436.     Brush.Color := clBtnFace;
  437.     Pen.Color := clWindowFrame;
  438.     Pen.Width := 1;
  439.     Rectangle(X, 0, X + ButtonWidth, Height);
  440.  
  441.     { draw button beveling }
  442.     if IsDown then
  443.     begin
  444.       Pen.Color := clBtnShadow;
  445.       MoveTo(X + 1, Height - 2);
  446.       LineTo(X + 1, 1);
  447.       LineTo(X + ButtonWidth - 1, 1);
  448.     end
  449.     else
  450.     begin
  451.       Pen.Color := clBtnHighlight;
  452.       MoveTo(X + 1, Height - 2);
  453.       LineTo(X + 1, 1);
  454.       LineTo(X + ButtonWidth - 1, 1);
  455.       Pen.Color := clBtnShadow;
  456.       MoveTo(X + 2, Height - 2);
  457.       LineTo(X + ButtonWidth - 2, Height - 2);
  458.       LineTo(X + ButtonWidth - 2, 1);
  459.     end;
  460.  
  461.     {which bitmap logic - based on Enabled, Colored, and AutoEnable}
  462.     if Enabled or (csDesigning in ComponentState) then
  463.     begin  {Enabled only affects buttons at runtime}
  464.       if FAutoEnable and not (csDesigning in ComponentState) then
  465.       begin  {AutoEnable only affects buttons at runtime}
  466.         if Buttons[Btn].Auto then {is button available, based on device state}
  467.         begin
  468.           TheGlyph := mgEnabled;
  469.           if Buttons[Btn].Colored then
  470.             TheGlyph := mgColored;
  471.         end
  472.         else TheGlyph := mgDisabled;  {button is not available}
  473.       end
  474.       else  {when not AutoEnabled or at design-time, check Enabled}
  475.       begin
  476.         if Buttons[Btn].Enabled then
  477.         begin
  478.           TheGlyph := mgEnabled;
  479.           if Buttons[Btn].Colored then
  480.             TheGlyph := mgColored;
  481.         end
  482.         else TheGlyph := mgDisabled;
  483.       end;
  484.     end
  485.     else TheGlyph := mgDisabled; {main switch set to disabled}
  486.  
  487.     Bitmap := Buttons[Btn].Bitmaps[TheGlyph];
  488.     BX := (ButtonWidth div 2) - (Bitmap.Width div 2);
  489.     BY := (Height div 2) - (Bitmap.Height div 2);
  490.     if IsDown then
  491.     begin
  492.       Inc(BX);
  493.       Inc(BY);
  494.     end;
  495.     BrushCopy(Bounds(X + BX, BY, Bitmap.Width, Bitmap.Height),
  496.       Bitmap, Rect(0, 0, Bitmap.Width, Bitmap.Height), clOlive);
  497.   end;
  498.  
  499.   if (GetFocus = Handle) and (Btn = FocusedButton) then
  500.   begin
  501.     R := Bounds(X, 0, ButtonWidth, Height);
  502.     InflateRect(R, -3, -3);
  503.     if IsDown then OffsetRect(R, 1, 1);
  504.     DrawFocusRect(Canvas.Handle, R);
  505.   end;
  506. end;
  507.  
  508. procedure TMediaPlayer.Paint;
  509. var
  510.   X: Integer;
  511.   I: TMPBtnType;
  512. begin
  513.   with Canvas do
  514.   begin
  515.     Brush.Style := bsClear;
  516.     Pen.Color := clWindowFrame;
  517.     Pen.Width := 1;
  518.     Rectangle(0, 0, Width, Height);
  519.  
  520.     X := 0;
  521.     for I := Low(Buttons) to High(Buttons) do
  522.     begin
  523.       if Buttons[I].Visible then
  524.       begin
  525.         DrawButton(I, X);
  526.         Inc(X, ButtonWidth - 1);
  527.       end;
  528.     end;
  529.   end;
  530. end;
  531.  
  532. {AutoEnable=True, enable/disable button set based on button passed (pressed)}
  533. procedure TMediaPlayer.AutoButtonSet(Btn: TMPBtnType);
  534. begin
  535.   case Btn of
  536.     btPlay:
  537.     begin
  538.       FAutoButtons := FAutoButtons - [btPlay,btRecord];
  539.       FAutoButtons := FAutoButtons + [btStop,btPause];
  540.     end;
  541.     btPause:
  542.     begin
  543.       if FCanPlay then Include(FAutoButtons,btPlay);
  544.       if FCanRecord then Include(FAutoButtons,btRecord);
  545.     end;
  546.     btStop:
  547.     begin
  548.       if FCanPlay then Include(FAutoButtons,btPlay);
  549.       if FCanRecord then Include(FAutoButtons,btRecord);
  550.       FAutoButtons := FAutoButtons - [btStop,btPause];
  551.     end;
  552.     btNext:
  553.     begin
  554.       if FCanPlay then Include(FAutoButtons,btPlay);
  555.       if FCanRecord then Include(FAutoButtons,btRecord);
  556.       FAutoButtons := FAutoButtons - [btStop,btPause];
  557.     end;
  558.     btPrev:
  559.     begin
  560.       if FCanPlay then Include(FAutoButtons,btPlay);
  561.       if FCanRecord then Include(FAutoButtons,btRecord);
  562.       FAutoButtons := FAutoButtons - [btStop,btPause];
  563.     end;
  564.     btStep:
  565.     begin
  566.       if FCanPlay then Include(FAutoButtons,btPlay);
  567.       if FCanRecord then Include(FAutoButtons,btRecord);
  568.       FAutoButtons := FAutoButtons - [btStop,btPause];
  569.     end;
  570.     btBack:
  571.     begin
  572.       if FCanPlay then Include(FAutoButtons,btPlay);
  573.       if FCanRecord then Include(FAutoButtons,btRecord);
  574.       FAutoButtons := FAutoButtons - [btStop,btPause];
  575.     end;
  576.     btRecord:
  577.     begin
  578.       FAutoButtons := FAutoButtons - [btPlay,btRecord];
  579.       FAutoButtons := FAutoButtons + [btStop,btPause];
  580.     end;
  581.     btEject: {without polling no way to determine when CD is inserted}
  582.     begin
  583.       if FCanPlay then Include(FAutoButtons,btPlay);
  584.       if FCanRecord then Include(FAutoButtons,btRecord);
  585.       FAutoButtons := FAutoButtons - [btStop,btPause];
  586.     end;
  587.   end;
  588. end;
  589.       
  590. procedure TMediaPlayer.DoMouseDown(XPos, YPos: Integer);
  591. var
  592.   I: TMPBtnType;
  593.   X: Integer;
  594. begin
  595.   {which button was clicked}
  596.   X := 0;
  597.   for I := Low(Buttons) to High(Buttons) do
  598.   begin
  599.     if Buttons[I].Visible then
  600.     begin
  601.       if (XPos >= X) and (XPos <= X + ButtonWidth) then
  602.       begin
  603.         if FAutoEnable then
  604.           if Buttons[I].Auto then Break
  605.           else Exit;
  606.         if Buttons[I].Enabled then Break
  607.         else Exit;
  608.       end;
  609.       Inc(X, ButtonWidth - 1);
  610.     end;
  611.   end;
  612.   CurrentButton := I;
  613.   if CurrentButton <> FocusedButton then
  614.   begin
  615.     FocusedButton := CurrentButton;
  616.     Paint;
  617.   end;
  618.   CurrentRect := Rect(X, 0, X + ButtonWidth, Height);
  619.   Pressed := True;
  620.   Down := True;
  621.   DrawButton(I, X);
  622.   MouseCapture := True;
  623. end;
  624.  
  625. procedure TMediaPlayer.WMLButtonDown(var Message: TWMLButtonDown);
  626. begin
  627.   DoMouseDown(Message.XPos, Message.YPos);
  628. end;
  629.  
  630. procedure TMediaPlayer.WMLButtonDblClk(var Message: TWMLButtonDblClk);
  631. begin
  632.   DoMouseDown(Message.XPos, Message.YPos);
  633. end;
  634.  
  635. procedure TMediaPlayer.WMMouseMove(var Message: TWMMouseMove);
  636. var
  637.   P: TPoint;
  638. begin
  639.   if Pressed then
  640.   begin
  641.     P := Point(Message.XPos, Message.YPos);
  642.     if PtInRect(CurrentRect, P) <> Down then
  643.     begin
  644.       Down := not Down;
  645.       DrawButton(CurrentButton, CurrentRect.Left);
  646.     end;
  647.   end;
  648. end;
  649.  
  650. procedure TMediaPlayer.DoClick(Button: TMPBtnType);
  651. var
  652.   DoDefault: Boolean;
  653. begin
  654.   DoDefault := True;
  655.   Click(CurrentButton, DoDefault);
  656.   if DoDefault then
  657.   begin
  658.     case CurrentButton of
  659.       btPlay: Play;
  660.       btPause: Pause;
  661.       btStop: Stop;
  662.       btNext: Next;
  663.       btPrev: Previous;
  664.       btStep: Step;
  665.       btBack: Back;
  666.       btRecord: StartRecording;
  667.       btEject: Eject;
  668.     end;
  669.     DoPostClick(CurrentButton);
  670.   end;
  671. end;
  672.  
  673. procedure TMediaPlayer.DoPostClick(Button: TMPBtnType);
  674. begin
  675.   PostClick(CurrentButton);
  676. end;
  677.  
  678. procedure TMediaPlayer.WMLButtonUp(var Message: TWMLButtonUp);
  679. begin
  680.   MouseCapture := False;
  681.   if Pressed and Down then
  682.   begin
  683.     Down := False;
  684.     DrawButton(CurrentButton, CurrentRect.Left);  {raise button before calling code}
  685.     DoClick(CurrentButton);
  686.     if FAutoEnable and (FError = 0) and MCIOpened then
  687.     begin
  688.       AutoButtonSet(CurrentButton);
  689.       DrawAutoButtons;
  690.     end;
  691.   end;
  692.   Pressed := False;
  693. end;
  694.  
  695. procedure TMediaPlayer.WMSetFocus(var Message: TWMSetFocus);
  696. begin
  697.   Paint;
  698. end;
  699.  
  700. procedure TMediaPlayer.WMKillFocus(var Message: TWMKillFocus);
  701. begin
  702.   Paint;
  703. end;
  704.  
  705. procedure TMediaPlayer.WMGetDlgCode(var Message: TWMGetDlgCode);
  706. begin
  707.   Message.Result := DLGC_WANTARROWS;
  708. end;
  709.  
  710. procedure TMediaPlayer.KeyDown(var Key: Word; Shift: TShiftState);
  711. var
  712.   NewFocus: TMPBtnType;
  713. begin
  714.   case Key of
  715.     VK_RIGHT:
  716.       begin
  717.         NewFocus := FocusedButton;
  718.         repeat
  719.           if NewFocus < High(Buttons) then
  720.             NewFocus := Succ(NewFocus);
  721.         until (NewFocus = High(Buttons)) or (Buttons[NewFocus].Visible);
  722.         if NewFocus <> FocusedButton then
  723.         begin
  724.           FocusedButton := NewFocus;
  725.           Invalidate;
  726.         end;
  727.       end;
  728.     VK_LEFT:
  729.       begin
  730.         NewFocus := FocusedButton;
  731.         repeat
  732.           if NewFocus > Low(Buttons) then
  733.             NewFocus := Pred(NewFocus);
  734.         until (NewFocus = Low(Buttons)) or (Buttons[NewFocus].Visible);
  735.         if NewFocus <> FocusedButton then
  736.         begin
  737.           FocusedButton := NewFocus;
  738.           Invalidate;
  739.         end;
  740.       end;
  741.     VK_SPACE:
  742.       begin
  743.         if Buttons[FocusedButton].Enabled then
  744.         begin
  745.           CurrentButton := FocusedButton;
  746.           DoClick(CurrentButton);
  747.           if FAutoEnable then
  748.           begin
  749.             AutoButtonSet(CurrentButton);
  750.             DrawAutoButtons;
  751.           end;
  752.         end;
  753.       end;
  754.   end;
  755. end;
  756.  
  757. {MCI message generated when Notify=True, and MCI command completes}
  758. procedure TMediaPlayer.MMNotify(var Message: TMessage);
  759. begin
  760.   if FAutoEnable and (Mode = mpStopped) then
  761.   begin {special AutoEnable case for when Play and Record finish}
  762.     if FCanPlay then Include(FAutoButtons,btPlay);
  763.     if FCanRecord then Include(FAutoButtons,btRecord);
  764.     FAutoButtons := FAutoButtons - [btStop,btPause];
  765.     DrawAutoButtons;
  766.   end;
  767.   case Message.WParam of
  768.     mci_Notify_Successful: FNotifyValue := nvSuccessful;
  769.     mci_Notify_Superseded: FNotifyValue := nvSuperseded;
  770.     mci_Notify_Aborted: FNotifyValue := nvAborted;
  771.     mci_Notify_Failure: FNotifyValue := nvFailure;
  772.   end;
  773.   DoNotify;
  774. end;
  775.  
  776. {for MCI Commands to make sure device is open, else raise exception}
  777. procedure TMediaPlayer.CheckIfOpen;
  778. begin
  779.   if not MCIOpened then raise EMCIDeviceError.Create(sNotOpenErr);
  780. end;
  781.  
  782. procedure TMediaPlayer.Click(Button: TMPBtnType; var DoDefault: Boolean);
  783. begin
  784.   if Assigned(FOnCLick) then FOnClick(Self, Button, DoDefault);
  785. end;
  786.  
  787. procedure TMediaPlayer.PostClick(Button: TMPBtnType);
  788. begin
  789.   if Assigned(FOnPostCLick) then FOnPostClick(Self, Button);
  790. end;
  791.  
  792. procedure TMediaPlayer.DoNotify;
  793. begin
  794.   if Assigned(FOnNotify) then FOnNotify(Self);
  795. end;
  796.  
  797. procedure TMediaPlayer.Updated;
  798. begin
  799.   inherited;
  800.   Adjust;
  801. end;
  802.  
  803. {***** MCI Commands *****}
  804.  
  805. procedure TMediaPlayer.Open;
  806. const
  807.   DeviceName: array[TMPDeviceTypes] of PChar = ('', 'AVIVideo', 'CDAudio', 'DAT',
  808.     'DigitalVideo', 'MMMovie', 'Other', 'Overlay', 'Scanner', 'Sequencer',
  809.     'VCR', 'Videodisc', 'WaveAudio');
  810. var
  811.   OpenParm: TMCI_Open_Parms;
  812.   DisplayR: TRect;
  813. begin
  814.   if MCIOpened then Close; {must close MCI Device first before opening another}
  815.  
  816.   OpenParm.dwCallback := 0;
  817.   if FDeviceType <> dtAutoSelect then {fill in Device Type}
  818.    OpenParm.lpstrDeviceType := DeviceName[FDeviceType];
  819.   if FElementName <> '' then
  820.     OpenParm.lpstrElementName := PChar(FElementName);
  821.  
  822.   FFlags := 0;
  823.   if FUseWait then
  824.   begin
  825.     if FWait then FFlags := mci_Wait;
  826.     FUseWait := False;
  827.   end
  828.   else FFlags := mci_Wait;
  829.   if FUseNotify then
  830.   begin
  831.     if FNotify then FFlags := FFlags or mci_Notify;
  832.     FUseNotify := False;
  833.   end;
  834.   if FElementName <> '' then FFlags := FFlags or mci_Open_Element;
  835.   if FDeviceType <> dtAutoSelect then FFlags := FFlags or mci_Open_Type;
  836.   if FShareable then FFlags := FFlags or mci_Open_Shareable;
  837.   OpenParm.dwCallback := Handle;
  838.   FError := mciSendCommand(0, mci_Open, FFlags, Longint(@OpenParm));
  839.  
  840.   if FError <> 0 then {problem opening device}
  841.     raise EMCIDeviceError.Create(ErrorMessage)
  842.   else {device successfully opened}
  843.   begin
  844.     MCIOpened := True;
  845.     FDeviceID := OpenParm.wDeviceID;
  846.     FFrames := Length div 10;  {default frames to step = 10% of total frames}
  847.     GetDeviceCaps; {must first get device capabilities}
  848.     if FHasVideo then {used for video output positioning}
  849.     begin
  850.       Display := FDisplay; {if one was set in design mode}
  851.       DisplayR := GetDisplayRect;
  852.       FDWidth := DisplayR.Right-DisplayR.Left;
  853.       FDHeight := DisplayR.Bottom-DisplayR.Top;
  854.     end;
  855.     if (FDeviceType = dtCDAudio) or (FDeviceType = dtVideodisc) then
  856.       TimeFormat := tfTMSF; {set timeformat to use tracks}
  857.     
  858.     FAutoButtons := [btNext,btPrev]; {assumed all devices can seek to start, end}
  859.     if FCanStep then FAutoButtons := FAutoButtons + [btStep,btBack];
  860.     if FCanPlay then Include(FAutoButtons, btPlay);
  861.     if FCanRecord then Include(FAutoButtons, btRecord);
  862.     if FCanEject then Include(FAutoButtons, btEject);
  863.     if Mode = mpPlaying then AutoButtonSet(btPlay); {e.g. CD device}
  864.     DrawAutoButtons;
  865.   end;
  866.     
  867. end;
  868.  
  869. procedure TMediaPlayer.Close;
  870. var
  871.   GenParm: TMCI_Generic_Parms;
  872. begin
  873.   if FDeviceID <> 0 then
  874.   begin
  875.     FFlags := 0;
  876.     if FUseWait then
  877.     begin
  878.       if FWait then FFlags := mci_Wait;
  879.       FUseWait := False;
  880.     end
  881.     else FFlags := mci_Wait;
  882.     if FUseNotify then
  883.     begin
  884.       if FNotify then FFlags := FFlags or mci_Notify;
  885.       FUseNotify := False;
  886.     end;
  887.     GenParm.dwCallback := Handle;
  888.     FError := mciSendCommand( FDeviceID, mci_Close, FFlags, Longint(@GenParm));
  889.     if FError = 0 then
  890.     begin
  891.       MCIOpened := False;
  892.       FDeviceID := 0;
  893.       FAutoButtons := [];
  894.       DrawAutoButtons;
  895.     end;
  896.   end; {if DeviceID <> 0}
  897. end;
  898.  
  899. procedure TMediaPlayer.Play;
  900. var
  901.   PlayParm: TMCI_Play_Parms;
  902. begin
  903.   CheckIfOpen; {raises exception if device is not open}
  904.  
  905.   {if at the end of media, and not using StartPos or EndPos - go to start}
  906.   if FAutoRewind and (Position = Length) then
  907.     if not FUseFrom and not FUseTo then Rewind;
  908.  
  909.   FFlags := 0;
  910.   if FUseNotify then
  911.   begin
  912.     if FNotify then FFlags := mci_Notify;
  913.     FUseNotify := False;
  914.   end else FFlags := mci_Notify;
  915.   if FUseWait then
  916.   begin
  917.     if FWait then FFlags := FFlags or mci_Wait;
  918.     FUseWait := False;
  919.   end;
  920.   if FUseFrom then
  921.   begin
  922.     FFlags := FFlags or mci_From;
  923.     PlayParm.dwFrom := FFrom;
  924.     FUseFrom := False; {only applies to this mciSendCommand}
  925.   end;
  926.   if FUseTo then
  927.   begin
  928.     FFlags := FFlags or mci_To;
  929.     PlayParm.dwTo := FTo;
  930.     FUseTo := False; {only applies to this mciSendCommand}
  931.   end;
  932.   PlayParm.dwCallback := Handle;
  933.   FError := mciSendCommand( FDeviceID, mci_Play, FFlags, Longint(@PlayParm));
  934. end;
  935.  
  936. procedure TMediaPlayer.StartRecording;
  937. var
  938.   RecordParm: TMCI_Record_Parms;
  939. begin
  940.   CheckIfOpen; {raises exception if device is not open}
  941.  
  942.   FFlags := 0;
  943.   if FUseNotify then
  944.   begin
  945.     if FNotify then FFlags := mci_Notify;
  946.     FUseNotify := False;
  947.   end
  948.   else FFlags := mci_Notify;
  949.   if FUseWait then
  950.   begin
  951.     if FWait then FFlags := FFlags or mci_Wait;
  952.     FUseWait := False;
  953.   end;
  954.  
  955.   if FUseFrom then
  956.   begin
  957.     FFlags := FFlags or mci_From;
  958.     RecordParm.dwFrom := FFrom;
  959.     FUseFrom := False;
  960.   end;
  961.   if FUseTo then
  962.   begin
  963.     FFlags := FFlags or mci_To;
  964.     RecordParm.dwTo := FTo;
  965.     FUseTo := False;
  966.   end;
  967.   RecordParm.dwCallback := Handle;
  968.   FError := mciSendCommand( FDeviceID, mci_Record, FFlags, Longint(@RecordParm));
  969. end;
  970.  
  971. procedure TMediaPlayer.Stop;
  972. var
  973.   GenParm: TMCI_Generic_Parms;
  974. begin
  975.   CheckIfOpen; {raises exception if device is not open}
  976.  
  977.   FFlags := 0;
  978.   if FUseWait then
  979.   begin
  980.     if FWait then FFlags := mci_Wait;
  981.     FUseWait := False;
  982.   end
  983.   else FFlags := mci_Wait;
  984.   if FUseNotify then
  985.   begin
  986.     if FNotify then FFlags := FFlags or mci_Notify;
  987.     FUseNotify := False;
  988.   end;
  989.   GenParm.dwCallback := Handle;
  990.   FError := mciSendCommand( FDeviceID, mci_Stop, FFlags, Longint(@GenParm));
  991. end;
  992.  
  993. procedure TMediaPlayer.Pause;
  994. begin
  995.   if not MCIOpened then Raise EMCIDeviceError.Create(sNotOpenErr);
  996.   if Mode = mpPlaying then PauseOnly
  997.   else
  998.    if Mode = mpPaused then Resume;
  999. end;
  1000.  
  1001. procedure TMediaPlayer.PauseOnly;
  1002. var
  1003.   GenParm: TMCI_Generic_Parms;
  1004. begin
  1005.   CheckIfOpen; {raises exception if device is not open}
  1006.  
  1007.   FFlags := 0;
  1008.   if FUseWait then
  1009.   begin
  1010.     if FWait then FFlags := mci_Wait;
  1011.     FUseWait := False;
  1012.   end
  1013.   else FFlags := mci_Wait;
  1014.   if FUseNotify then
  1015.   begin
  1016.     if FNotify then FFlags := FFlags or mci_Notify;
  1017.     FUseNotify := False;
  1018.   end;
  1019.   GenParm.dwCallback := Handle;
  1020.   FError := mciSendCommand( FDeviceID, mci_Pause, FFlags, Longint(@GenParm));
  1021. end;
  1022.  
  1023. procedure TMediaPlayer.Resume;
  1024. var
  1025.   GenParm: TMCI_Generic_Parms;
  1026. begin
  1027.   CheckIfOpen; {raises exception if device is not open}
  1028.  
  1029.   FFlags := 0;
  1030.   if FUseNotify then
  1031.   begin
  1032.     if FNotify then FFlags := mci_Notify;
  1033.   end
  1034.   else FFlags := mci_Notify;
  1035.   if FUseWait then
  1036.   begin
  1037.     if FWait then FFlags := FFlags or mci_Wait;
  1038.   end;
  1039.   GenParm.dwCallback := Handle;
  1040.   FError := mciSendCommand( FDeviceID, mci_Resume, FFlags, Longint(@GenParm));
  1041.   
  1042.   {if error calling resume (resume not supported),  call Play}
  1043.   if FError <> 0 then
  1044.     Play {FUseNotify & FUseWait reset by Play}
  1045.   else
  1046.   begin
  1047.     if FUseNotify then
  1048.       FUseNotify := False;
  1049.     if FUseWait then
  1050.       FUseWait := False;
  1051.   end;
  1052. end;
  1053.  
  1054. procedure TMediaPlayer.Next;
  1055. var
  1056.   SeekParm: TMCI_Seek_Parms;
  1057.   TempFlags: Longint;
  1058. begin
  1059.   CheckIfOpen; {raises exception if device is not open}
  1060.  
  1061.   FFlags := 0;
  1062.   if FUseWait then
  1063.   begin
  1064.     if FWait then FFlags := mci_Wait;
  1065.     FUseWait := False;
  1066.   end
  1067.   else FFlags := mci_Wait;
  1068.   if FUseNotify then
  1069.   begin
  1070.     if FNotify then FFlags := FFlags or mci_Notify;
  1071.     FUseNotify := False;
  1072.   end;
  1073.  
  1074.   TempFlags := FFlags; {preserve FFlags from GetTimeFormat & GetPosition}
  1075.   if TimeFormat = tfTMSF then {using Tracks}
  1076.   begin
  1077.     if Mode = mpPlaying then 
  1078.     begin
  1079.       if mci_TMSF_Track(Position) = Tracks then {if at last track}
  1080.          StartPos := GetTrackPosition(Tracks) {go to beg of last}
  1081.       else {go to next track}
  1082.          StartPos := GetTrackPosition((mci_TMSF_Track(Position))+1);
  1083.       Play;
  1084.       CurrentButton := btPlay;
  1085.       Exit;
  1086.     end
  1087.     else
  1088.     begin
  1089.       if mci_TMSF_Track(Position) = Tracks then {if at last track}
  1090.          SeekParm.dwTo := GetTrackPosition(Tracks) {go to beg of last}
  1091.       else {go to next track}
  1092.          SeekParm.dwTo := GetTrackPosition((mci_TMSF_Track(Position))+1);
  1093.       FFlags := TempFlags or mci_To;
  1094.     end;
  1095.   end
  1096.   else
  1097.     FFlags := TempFlags or mci_Seek_To_End;
  1098.     
  1099.   SeekParm.dwCallback := Handle;
  1100.   FError := mciSendCommand( FDeviceID, mci_Seek, FFlags, Longint(@SeekParm));
  1101. end; {Next}
  1102.  
  1103.  
  1104. procedure TMediaPlayer.Previous;
  1105. var
  1106.   SeekParm: TMCI_Seek_Parms;
  1107.   tpos,cpos,TempFlags: Longint;
  1108. begin
  1109.   CheckIfOpen; {raises exception if device is not open}
  1110.  
  1111.   FFlags := 0;
  1112.   if FUseWait then
  1113.   begin
  1114.     if FWait then FFlags := mci_Wait;
  1115.     FUseWait := False;
  1116.   end
  1117.   else FFlags := mci_Wait;
  1118.   if FUseNotify then
  1119.   begin
  1120.     if FNotify then FFlags := FFlags or mci_Notify;
  1121.     FUseNotify := False;
  1122.   end;
  1123.   
  1124.   TempFlags := FFlags; {preserve FFlags from GetTimeFormat & GetPosition}
  1125.   if TimeFormat = tfTMSF then {using Tracks}
  1126.   begin
  1127.     cpos := Position;
  1128.     tpos := GetTrackPosition(mci_TMSF_Track(Position));
  1129.     if Mode = mpPlaying then 
  1130.     begin
  1131.         {if not on first track, and at beginning of current track}
  1132.         if (mci_TMSF_Track(cpos) <> 1) and
  1133.           (mci_TMSF_Minute(cpos) = mci_TMSF_Minute(tpos)) and
  1134.           (mci_TMSF_Second(cpos) = mci_TMSF_Second(tpos)) then
  1135.           StartPos := GetTrackPosition(mci_TMSF_Track(Position)-1) {go to previous}
  1136.         else
  1137.           StartPos := tpos; {otherwise, go to beginning of current}
  1138.       Play;
  1139.       CurrentButton := btPlay;
  1140.       Exit;
  1141.      end
  1142.      else
  1143.      begin
  1144.         {if not on first track, and at beginning of current track}
  1145.         if (mci_TMSF_Track(cpos) <> 1) and
  1146.           (mci_TMSF_Minute(cpos) = mci_TMSF_Minute(tpos)) and
  1147.           (mci_TMSF_Second(cpos) = mci_TMSF_Second(tpos)) then
  1148.           SeekParm.dwTo := GetTrackPosition(mci_TMSF_Track(Position)-1) {go to previous}
  1149.         else
  1150.           SeekParm.dwTo := tpos; {otherwise, go to beginning of current}
  1151.         FFlags := TempFlags or mci_To;
  1152.      end;
  1153.   end
  1154.   else
  1155.     FFlags := TempFlags or mci_Seek_To_Start;
  1156.     
  1157.   SeekParm.dwCallback := Handle;
  1158.   FError := mciSendCommand( FDeviceID, mci_Seek, FFlags, Longint(@SeekParm));
  1159. end; {Previous}
  1160.  
  1161. procedure TMediaPlayer.Step;
  1162. var
  1163.   AStepParm: TMCI_Anim_Step_Parms;
  1164. begin
  1165.   CheckIfOpen; {raises exception if device is not open}
  1166.  
  1167.   if FHasVideo then
  1168.   begin
  1169.     if FAutoRewind and (Position = Length) then Rewind;
  1170.  
  1171.     FFlags := 0;
  1172.     if FUseWait then
  1173.     begin
  1174.       if FWait then FFlags := mci_Wait;
  1175.       FUseWait := False;
  1176.     end
  1177.     else FFlags := mci_Wait;
  1178.     if FUseNotify then
  1179.     begin
  1180.       if FNotify then FFlags := FFlags or mci_Notify;
  1181.       FUseNotify := False;
  1182.     end;
  1183.     FFlags := FFlags or mci_Anim_Step_Frames;
  1184.     AStepParm.dwFrames := FFrames;
  1185.     AStepParm.dwCallback := Handle;
  1186.     FError := mciSendCommand( FDeviceID, mci_Step, FFlags, Longint(@AStepParm) );
  1187.   end; {if HasVideo}
  1188. end;
  1189.  
  1190. procedure TMediaPlayer.Back;
  1191. var
  1192.   AStepParm: TMCI_Anim_Step_Parms;
  1193. begin
  1194.   CheckIfOpen; {raises exception if device is not open}
  1195.  
  1196.   if FHasVideo then
  1197.   begin
  1198.     FFlags := 0;
  1199.     if FUseWait then
  1200.     begin
  1201.       if FWait then FFlags := mci_Wait;
  1202.       FUseWait := False;
  1203.     end
  1204.     else FFlags := mci_Wait;
  1205.     if FUseNotify then
  1206.     begin
  1207.       if FNotify then FFlags := FFlags or mci_Notify;
  1208.       FUseNotify := False;
  1209.     end;
  1210.     FFlags := FFlags or mci_Anim_Step_Frames or mci_Anim_Step_Reverse;
  1211.     AStepParm.dwFrames := FFrames;
  1212.     AStepParm.dwCallback := Handle;
  1213.     FError := mciSendCommand( FDeviceID, mci_Step, FFlags, Longint(@AStepParm) );
  1214.   end; {if HasVideo}
  1215. end; {Back}
  1216.  
  1217. procedure TMediaPlayer.Eject;
  1218. var
  1219.   SetParm: TMCI_Set_Parms;
  1220. begin
  1221.   CheckIfOpen; {raises exception if device is not open}
  1222.  
  1223.   if FCanEject then
  1224.   begin
  1225.     FFlags := 0;
  1226.     if FUseWait then
  1227.     begin
  1228.       if FWait then FFlags := mci_Wait;
  1229.       FUseWait := False;
  1230.     end
  1231.     else FFlags := mci_Wait;
  1232.     if FUseNotify then
  1233.     begin
  1234.       if FNotify then FFlags := FFlags or mci_Notify;
  1235.       FUseNotify := False;
  1236.     end;
  1237.     FFlags := FFlags or mci_Set_Door_Open;
  1238.     SetParm.dwCallback := Handle;
  1239.     FError := mciSendCommand( FDeviceID, mci_Set, FFlags, Longint(@SetParm) );
  1240.   end; {if CanEject}
  1241. end; {Eject}
  1242.  
  1243. procedure TMediaPlayer.SetPosition(Value: Longint);
  1244. var
  1245.   SeekParm: TMCI_Seek_Parms;
  1246. begin
  1247.   CheckIfOpen; {raises exception if device is not open}
  1248.  
  1249.   FFlags := 0;
  1250.   if FUseWait then
  1251.   begin
  1252.     if FWait then FFlags := mci_Wait;
  1253.     FUseWait := False;
  1254.   end
  1255.   else FFlags := mci_Wait;
  1256.   if FUseNotify then
  1257.   begin
  1258.     if FNotify then FFlags := FFlags or mci_Notify;
  1259.     FUseNotify := False;
  1260.   end;
  1261.   FFlags := FFlags or mci_To;
  1262.   SeekParm.dwCallback := Handle;
  1263.   SeekParm.dwTo := Value;
  1264.   FError := mciSendCommand( FDeviceID, mci_Seek, FFlags, Longint(@SeekParm));
  1265. end;
  1266.  
  1267. procedure TMediaPlayer.Rewind;
  1268. var
  1269.   SeekParm: TMCI_Seek_Parms;
  1270.   RFlags: Longint;
  1271. begin
  1272.   CheckIfOpen; {raises exception if device is not open}
  1273.   RFlags := mci_Wait or mci_Seek_To_Start;
  1274.   mciSendCommand( FDeviceID, mci_Seek, RFlags, Longint(@SeekParm));
  1275. end;
  1276.  
  1277. function TMediaPlayer.GetTrackLength(TrackNum: Integer): Longint;
  1278. var
  1279.   StatusParm: TMCI_Status_Parms;
  1280. begin
  1281.   CheckIfOpen; {raises exception if device is not open}
  1282.   FFlags := mci_Wait or mci_Status_Item or mci_Track;
  1283.   StatusParm.dwItem := mci_Status_Length;
  1284.   StatusParm.dwTrack := Longint(TrackNum);
  1285.   mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1286.   Result := StatusParm.dwReturn;
  1287. end;
  1288.  
  1289. function TMediaPlayer.GetTrackPosition(TrackNum: Integer): Longint;
  1290. var
  1291.   StatusParm: TMCI_Status_Parms;
  1292. begin
  1293.   FFlags := mci_Wait or mci_Status_Item or mci_Track;
  1294.   StatusParm.dwItem := mci_Status_Position;
  1295.   StatusParm.dwTrack := Longint(TrackNum);
  1296.   mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1297.   Result := StatusParm.dwReturn;
  1298. end;
  1299.  
  1300. procedure TMediaPlayer.Save;
  1301. var
  1302.   SaveParm: TMCI_SaveParms;
  1303. begin
  1304.   CheckIfOpen; {raises exception if device is not open}
  1305.   if FElementName <> '' then {make sure a file has been specified to save to}
  1306.   begin
  1307.     SaveParm.lpfilename := PChar(FElementName);
  1308.  
  1309.     FFlags := 0;
  1310.     if FUseWait then
  1311.     begin
  1312.       if FWait then FFlags := mci_Wait;
  1313.       FUseWait := False;
  1314.     end
  1315.     else FFlags := mci_Wait;
  1316.     if FUseNotify then
  1317.     begin
  1318.       if FNotify then FFlags := FFlags or mci_Notify;
  1319.       FUseNotify := False;
  1320.     end;
  1321.     SaveParm.dwCallback := Handle;
  1322.     FFlags := FFlags or mci_Save_File;
  1323.     FError := mciSendCommand(FDeviceID, mci_Save, FFlags, Longint(@SaveParm));
  1324.     end;
  1325. end;
  1326.  
  1327.  
  1328. {*** procedures that set control flags for MCI Commands ***}
  1329. procedure TMediaPlayer.SetWait( Flag: Boolean );
  1330. begin
  1331.   if Flag <> FWait then FWait := Flag;
  1332.   FUseWait := True;
  1333. end;
  1334.  
  1335. procedure TMediaPlayer.SetNotify( Flag: Boolean );
  1336. begin
  1337.   if Flag <> FNotify then FNotify := Flag;
  1338.   FUseNotify := True;
  1339. end;
  1340.  
  1341. procedure TMediaPlayer.SetFrom( Value: Longint );
  1342. begin
  1343.   if Value <> FFrom then FFrom := Value;
  1344.   FUseFrom := True;
  1345. end;
  1346.  
  1347. procedure TMediaPlayer.SetTo( Value: Longint );
  1348. begin
  1349.   if Value <> FTo then FTo := Value;
  1350.   FUseTo := True;
  1351. end;
  1352.  
  1353.  
  1354. procedure TMediaPlayer.SetDeviceType( Value: TMPDeviceTypes );
  1355. begin
  1356.   if Value <> FDeviceType then FDeviceType := Value;
  1357. end;
  1358.  
  1359. procedure TMediaPlayer.SetTimeFormat( Value: TMPTimeFormats );
  1360. var
  1361.   SetParm: TMCI_Set_Parms;
  1362. begin
  1363.   begin
  1364.     FFlags := mci_Notify or mci_Set_Time_Format;
  1365.     SetParm.dwTimeFormat := Longint(Value);
  1366.     FError := mciSendCommand( FDeviceID, mci_Set, FFlags, Longint(@SetParm) );
  1367.   end;
  1368. end;
  1369.  
  1370. {setting a TWinControl to display video devices' output}
  1371. procedure TMediaPlayer.SetDisplay( Value: TWinControl );
  1372. var
  1373.   AWindowParm: TMCI_Anim_Window_Parms;
  1374. begin
  1375.   if (Value <> nil) and MCIOpened and FHasVideo then
  1376.   begin
  1377.     FFlags := mci_Wait or mci_Anim_Window_hWnd;
  1378.     AWindowParm.Wnd := Longint(Value.Handle);
  1379.     FError := mciSendCommand( FDeviceID, mci_Window, FFlags, Longint(@AWindowParm) );
  1380.     if FError <> 0 then
  1381.       FDisplay := nil {alternate window not supported}
  1382.     else
  1383.     begin
  1384.       FDisplay := Value; {alternate window supported}
  1385.       Value.FreeNotification(Self);
  1386.     end;
  1387.   end
  1388.   else FDisplay := Value;
  1389. end;
  1390.  
  1391. procedure TMediaPlayer.Notification(AComponent: TComponent;
  1392.   Operation: TOperation);
  1393. begin
  1394.   inherited Notification(AComponent, Operation);
  1395.   if (Operation = opRemove) and (AComponent = FDisplay) then
  1396.   begin
  1397.     if MCIOpened then SetOrigDisplay;
  1398.     FDisplay := nil;
  1399.   end;
  1400. end;
  1401.  
  1402. { special case to set video display back to original window,
  1403.   when FDisplay's TWinControl is deleted at runtime }
  1404. procedure TMediaPlayer.SetOrigDisplay;
  1405. var
  1406.   AWindowParm: TMCI_Anim_Window_Parms;
  1407. begin
  1408.   if MCIOpened and FHasVideo then
  1409.   begin
  1410.     FFlags := mci_Wait or mci_Anim_Window_hWnd;
  1411.     AWindowParm.Wnd := mci_Anim_Window_Default;
  1412.     FError := mciSendCommand( FDeviceID, mci_Window, FFlags, Longint(@AWindowParm) );
  1413.   end;
  1414. end;
  1415.  
  1416. {setting a rect for user-defined form to display video devices' output}
  1417. procedure TMediaPlayer.SetDisplayRect( Value: TRect );
  1418. var
  1419.   RectParms: TMCI_Anim_Rect_Parms;
  1420.   WorkR: TRect;
  1421. begin
  1422.   if MCIOpened and FHasVideo then
  1423.   begin
  1424.     {special case, use default width and height}
  1425.     if (Value.Bottom = 0) and (Value.Right = 0) then
  1426.     begin
  1427.       with Value do
  1428.         WorkR := Rect(Left, Top, FDWidth, FDHeight);
  1429.     end
  1430.     else WorkR := Value;
  1431.     FFlags := mci_Anim_RECT or mci_Anim_Put_Destination;
  1432.     RectParms.rc := WorkR;
  1433.     FError := mciSendCommand( FDeviceID, mci_Put, FFlags, Longint(@RectParms) );
  1434.   end;
  1435. end;
  1436.  
  1437.  
  1438. {***** functions to get device capabilities and status ***}
  1439.  
  1440. function TMediaPlayer.GetDisplayRect: TRect;
  1441. var
  1442.   RectParms: TMCI_Anim_Rect_Parms;
  1443. begin
  1444.   if MCIOpened and FHasVideo then
  1445.   begin
  1446.     FFlags := mci_Anim_Where_Destination;
  1447.     FError := mciSendCommand( FDeviceID, mci_Where, FFlags, Longint(@RectParms) );
  1448.     Result := RectParms.rc;
  1449.   end;
  1450. end;
  1451.  
  1452. { fills in static properties upon opening MCI Device }
  1453. procedure TMediaPlayer.GetDeviceCaps;
  1454. var
  1455.   DevCapParm: TMCI_GetDevCaps_Parms;
  1456.   devType: Longint;
  1457.   RectParms: TMCI_Anim_Rect_Parms;
  1458.   WorkR: TRect;
  1459. begin
  1460.   FFlags := mci_Wait or mci_GetDevCaps_Item;
  1461.  
  1462.   DevCapParm.dwItem := mci_GetDevCaps_Can_Play;
  1463.   mciSendCommand(FDeviceID, mci_GetDevCaps, FFlags,  Longint(@DevCapParm) );
  1464.   FCanPlay := Boolean(DevCapParm.dwReturn);
  1465.   if FCanPlay then Include(FCapabilities, mpCanPlay);
  1466.  
  1467.   DevCapParm.dwItem := mci_GetDevCaps_Can_Record;
  1468.   mciSendCommand(FDeviceID, mci_GetDevCaps, FFlags,  Longint(@DevCapParm) );
  1469.   FCanRecord := Boolean(DevCapParm.dwReturn);
  1470.   if FCanRecord then Include(FCapabilities, mpCanRecord);
  1471.  
  1472.   DevCapParm.dwItem := mci_GetDevCaps_Can_Eject;
  1473.   mciSendCommand(FDeviceID, mci_GetDevCaps, FFlags,  Longint(@DevCapParm) );
  1474.   FCanEject := Boolean(DevCapParm.dwReturn);
  1475.   if FCanEject then Include(FCapabilities, mpCanEject);
  1476.  
  1477.   DevCapParm.dwItem := mci_GetDevCaps_Has_Video;
  1478.   mciSendCommand(FDeviceID, mci_GetDevCaps, FFlags,  Longint(@DevCapParm) );
  1479.   FHasVideo := Boolean(DevCapParm.dwReturn);
  1480.   if FHasVideo then Include(FCapabilities, mpUsesWindow);
  1481.  
  1482.   DevCapParm.dwItem := mci_GetDevCaps_Device_Type;
  1483.   mciSendCommand(FDeviceID, mci_GetDevCaps, FFlags,  Longint(@DevCapParm) );
  1484.   devType := DevCapParm.dwReturn;
  1485.   if (devType = mci_DevType_Animation) or
  1486.      (devType = mci_DevType_Digital_Video) or
  1487.      (devType = mci_DevType_Overlay) or
  1488.      (devType = mci_DevType_VCR) then FCanStep := True;
  1489.   if FCanStep then Include(FCapabilities, mpCanStep);
  1490.  
  1491.   FFlags := mci_Anim_Where_Source;
  1492.   FError := mciSendCommand( FDeviceID, mci_Where, FFlags, Longint(@RectParms) );
  1493.   WorkR := RectParms.rc;
  1494.   FDWidth := WorkR.Right - WorkR.Left;
  1495.   FDHeight := WorkR.Bottom - WorkR.Top;
  1496. end; {GetDeviceCaps}
  1497.  
  1498. function TMediaPlayer.GetStart: Longint;
  1499. var
  1500.   StatusParm: TMCI_Status_Parms;
  1501. begin
  1502.   CheckIfOpen; {raises exception if device is not open}
  1503.   FFlags := mci_Wait or mci_Status_Item or mci_Status_Start;
  1504.   StatusParm.dwItem := mci_Status_Position;
  1505.   FError := mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1506.   Result := StatusParm.dwReturn;
  1507. end;
  1508.  
  1509. function TMediaPlayer.GetLength: Longint;
  1510. var
  1511.   StatusParm: TMCI_Status_Parms;
  1512. begin
  1513.   CheckIfOpen; {raises exception if device is not open}
  1514.   FFlags := mci_Wait or mci_Status_Item;
  1515.   StatusParm.dwItem := mci_Status_Length;
  1516.   FError := mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1517.   Result := StatusParm.dwReturn;
  1518. end;
  1519.  
  1520. function TMediaPlayer.GetTracks: Longint;
  1521. var
  1522.   StatusParm: TMCI_Status_Parms;
  1523. begin
  1524.   CheckIfOpen; {raises exception if device is not open}
  1525.   FFlags := mci_Wait or mci_Status_Item;
  1526.   StatusParm.dwItem := mci_Status_Number_Of_Tracks;
  1527.   FError := mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1528.   Result := StatusParm.dwReturn;
  1529. end;
  1530.  
  1531. function TMediaPlayer.GetMode: TMPModes;
  1532. var
  1533.   StatusParm: TMCI_Status_Parms;
  1534. begin
  1535.   FFlags := mci_Wait or mci_Status_Item;
  1536.   StatusParm.dwItem := mci_Status_Mode;
  1537.   FError := mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1538.   Result := TMPModes(StatusParm.dwReturn - 524); {MCI Mode #s are 524+enum}
  1539. end;
  1540.  
  1541. function TMediaPlayer.GetPosition: Longint;
  1542. var
  1543.   StatusParm: TMCI_Status_Parms;
  1544. begin
  1545.   FFlags := mci_Wait or mci_Status_Item;
  1546.   StatusParm.dwItem := mci_Status_Position;
  1547.   FError := mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1548.   Result := StatusParm.dwReturn;
  1549. end;
  1550.  
  1551. function TMediaPlayer.GetTimeFormat: TMPTimeFormats;
  1552. var
  1553.   StatusParm: TMCI_Status_Parms;
  1554. begin
  1555.   CheckIfOpen; {raises exception if device is not open}
  1556.   FFlags := mci_Wait or mci_Status_Item;
  1557.   StatusParm.dwItem := mci_Status_Time_Format;
  1558.   FError := mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1559.   Result := TMPTimeFormats(StatusParm.dwReturn);
  1560. end;
  1561.  
  1562. function TMediaPlayer.GetErrorMessage: string;
  1563. var
  1564.   ErrMsg: array[0..4095] of Char;
  1565. begin
  1566.   if not mciGetErrorString(FError, ErrMsg, SizeOf(ErrMsg)) then
  1567.     Result := SMCIUnknownError
  1568.   else SetString(Result, ErrMsg, StrLen(ErrMsg));
  1569. end;
  1570.  
  1571. end.
  1572.