unit Settings;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
  FMX.ListBox, FMX.Layouts, FMX.Memo, FMX.ScrollBox, FMX.Controls.Presentation,
  Winsoft.Android.Camera, FMX.TabControl, FMX.TreeView;

type
  TFormSettings = class(TForm)
    LabelCamera: TLabel;
    ComboBoxCamera: TComboBox;
    LabelPreviewSize: TLabel;
    ComboBoxPreviewSize: TComboBox;
    ComboBoxFocusMode: TComboBox;
    LabelFocusMode: TLabel;
    ComboBoxFlashMode: TComboBox;
    LabelFlashMode: TLabel;
    VertScrollBox: TVertScrollBox;
    ComboBoxColorEffect: TComboBox;
    LabelColorEffect: TLabel;
    ComboBoxAntibanding: TComboBox;
    LabelAntibanding: TLabel;
    ComboBoxWhiteBalance: TComboBox;
    LabelWhiteBalance: TLabel;
    TabControl: TTabControl;
    TabItemSettings: TTabItem;
    TabItemProperties: TTabItem;
    LabelPictureSize: TLabel;
    ComboBoxPictureSize: TComboBox;
    LabelSceneMode: TLabel;
    ComboBoxSceneMode: TComboBox;
    TreeView: TTreeView;
    procedure ComboBoxCameraChange(Sender: TObject);
    procedure ComboBoxPreviewSizeChange(Sender: TObject);
    procedure ComboBoxFocusModeChange(Sender: TObject);
    procedure ComboBoxFlashModeChange(Sender: TObject);
    procedure ComboBoxColorEffectChange(Sender: TObject);
    procedure ComboBoxAntibandingChange(Sender: TObject);
    procedure ComboBoxWhiteBalanceChange(Sender: TObject);
    procedure ComboBoxPictureSizeChange(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure ComboBoxSceneModeChange(Sender: TObject);
    procedure TabControlChange(Sender: TObject);
    procedure FormDeactivate(Sender: TObject);
  private
    { Private declarations }
    Initialized: Boolean;
    ChangesDisabled: Boolean;
    function AddItem(const Text: string): TTreeViewItem; overload;
    function AddItem(TreeViewItem: TTreeViewItem; const Text: string): TTreeViewItem; overload;
    procedure SetComboBoxSceneMode(Camera: TACamera);
    procedure SetComboBoxPreviewSize(Camera: TACamera);
    procedure SetComboBoxPictureSize(Camera: TACamera);
    procedure SetComboBoxFocusMode(Camera: TACamera);
    procedure SetComboBoxFlashMode(Camera: TACamera);
    procedure SetComboBoxColorEffect(Camera: TACamera);
    procedure SetComboBoxAntibanding(Camera: TACamera);
    procedure SetComboBoxWhiteBalance(Camera: TACamera);
    procedure SetCameraInfo;
  public
    { Public declarations }
    procedure ApplySettings;
  end;

var
  FormSettings: TFormSettings;

implementation

uses Main, FMX.Objects;

{$R *.fmx}

function BooleanToStr(Value: Boolean): string;
begin
  if Value then
    Result := 'True'
  else
    Result := 'False'
end;

procedure TFormSettings.ComboBoxCameraChange(Sender: TObject);
var Camera: TACamera;
begin
  Camera := FormMain.ACamera;
  Camera.Active := False;

  ChangesDisabled := True;
  try
    Camera.CameraIndex := ComboBoxCamera.ItemIndex;

    try
      Camera.Active := True;
      Camera.PreviewSize := Camera.PreferredPreviewSize;
      if foContinuousVideo in Camera.SupportedFocusModes then
        Camera.FocusMode := foContinuousVideo;

      SetComboBoxSceneMode(Camera);
      SetComboBoxPreviewSize(Camera);
      SetComboBoxPictureSize(Camera);
      SetComboBoxFocusMode(Camera);
      SetComboBoxFlashMode(Camera);
      SetComboBoxColorEffect(Camera);
      SetComboBoxAntibanding(Camera);
      SetComboBoxWhiteBalance(Camera);
    except
      on E: Exception do
        ShowMessage(E.Message);
    end;
  finally
    ChangesDisabled := False;
  end;
end;

const SceneModeNames: array [TSceneMode] of string = (
  'Unknown', 'Action', 'Auto', 'Barcode', 'Beach', 'Candle light', 'Fireworks', 'HDR', 'Landscape',
  'Night', 'Nigh portrait', 'Party', 'Portrait', 'Snow', 'Sports', 'Steady photo', 'Sunset', 'Theatre');

procedure TFormSettings.SetComboBoxSceneMode(Camera: TACamera);
var CameraSceneMode, SceneMode: TSceneMode;
begin
  ComboBoxSceneMode.ItemIndex := -1;
  ComboBoxSceneMode.Items.Clear;
  ComboBoxSceneMode.Enabled := False;

  CameraSceneMode := Camera.SceneMode;
  for SceneMode in Camera.SupportedSceneModes do
  begin
    ComboBoxSceneMode.Items.Add(SceneModeNames[SceneMode]);
    if SceneMode = CameraSceneMode then
      ComboBoxSceneMode.ItemIndex := ComboBoxSceneMode.Items.Count - 1;
  end;
  ComboBoxSceneMode.Enabled := ComboBoxSceneMode.Items.Count > 1;
end;

procedure TFormSettings.SetComboBoxPreviewSize(Camera: TACamera);
var CameraSize, Size: TSize;
begin
  ComboBoxPreviewSize.ItemIndex := -1;
  ComboBoxPreviewSize.Items.Clear;
  ComboBoxPreviewSize.Enabled := False;

  CameraSize := Camera.PreviewSize;
  for Size in Camera.SupportedPreviewSizes do
  begin
    ComboBoxPreviewSize.Items.Append(IntToStr(Size.Width) + ' x ' + IntToStr(Size.Height));
    if (Size.Width = CameraSize.Width) and (Size.Height = CameraSize.Height) then
      ComboBoxPreviewSize.ItemIndex := ComboBoxPreviewSize.Items.Count - 1;
  end;
  ComboBoxPreviewSize.Enabled := ComboBoxPreviewSize.Items.Count > 1;
end;

procedure TFormSettings.SetComboBoxPictureSize(Camera: TACamera);
var CameraSize, Size: TSize;
begin
  ComboBoxPictureSize.ItemIndex := -1;
  ComboBoxPictureSize.Items.Clear;
  ComboBoxPictureSize.Enabled := False;

  CameraSize := Camera.PictureSize;
  for Size in Camera.SupportedPictureSizes do
  begin
    ComboBoxPictureSize.Items.Append(IntToStr(Size.Width) + ' x ' + IntToStr(Size.Height));
    if (Size.Width = CameraSize.Width) and (Size.Height = CameraSize.Height) then
      ComboBoxPictureSize.ItemIndex := ComboBoxPictureSize.Items.Count - 1;
  end;
  ComboBoxPictureSize.Enabled := ComboBoxPictureSize.Items.Count > 1;
end;

const FocusModeNames: array [TFocusMode] of string = (
  'Unknown', 'Auto', 'Continuous picture', 'Continuous video', 'EDOF', 'Fixed', 'Infinity', 'Macro');

procedure TFormSettings.SetComboBoxFocusMode(Camera: TACamera);
var CameraFocusMode, FocusMode: TFocusMode;
begin
  ComboBoxFocusMode.ItemIndex := -1;
  ComboBoxFocusMode.Items.Clear;
  ComboBoxFocusMode.Enabled := False;

  CameraFocusMode := Camera.FocusMode;
  for FocusMode in Camera.SupportedFocusModes do
  begin
    ComboBoxFocusMode.Items.Add(FocusModeNames[FocusMode]);
    if FocusMode = CameraFocusMode then
      ComboBoxFocusMode.ItemIndex := ComboBoxFocusMode.Items.Count - 1;
  end;
  ComboBoxFocusMode.Enabled := ComboBoxFocusMode.Items.Count > 1;
end;

const FlashModeNames: array [TFlashMode] of string = (
  'Unknown', 'Off', 'Auto', 'On', 'Torch', 'Red eye');

procedure TFormSettings.SetComboBoxFlashMode(Camera: TACamera);
var CameraFlashMode, FlashMode: TFlashMode;
begin
  ComboBoxFlashMode.ItemIndex := -1;
  ComboBoxFlashMode.Items.Clear;
  ComboBoxFlashMode.Enabled := False;

  CameraFlashMode := Camera.FlashMode;
  for FlashMode in Camera.SupportedFlashModes do
  begin
    ComboBoxFlashMode.Items.Add(FlashModeNames[FlashMode]);
    if FlashMode = CameraFlashMode then
      ComboBoxFlashMode.ItemIndex := ComboBoxFlashMode.Items.Count - 1;
  end;
  ComboBoxFlashMode.Enabled := ComboBoxFlashMode.Items.Count > 1;
end;

const ColorEffectNames: array [TColorEffect] of string = (
  'Unknown', 'None', 'Mono', 'Negative', 'Solarize', 'Sepia', 'Posterize',
  'White board', 'Black board', 'Aqua', 'Emboss', 'Sketch', 'Neon');

procedure TFormSettings.SetComboBoxColorEffect(Camera: TACamera);
var CameraColorEffect, ColorEffect: TColorEffect;
begin
  ComboBoxColorEffect.ItemIndex := -1;
  ComboBoxColorEffect.Items.Clear;
  ComboBoxColorEffect.Enabled := False;

  CameraColorEffect := Camera.ColorEffect;
  for ColorEffect in Camera.SupportedColorEffects do
  begin
    ComboBoxColorEffect.Items.Add(ColorEffectNames[ColorEffect]);
    if ColorEffect = CameraColorEffect then
      ComboBoxColorEffect.ItemIndex := ComboBoxColorEffect.Items.Count - 1;
  end;
  ComboBoxColorEffect.Enabled := ComboBoxColorEffect.Items.Count > 1;
end;

const AntibandingNames: array [TAntibanding] of string = (
  'Unknown', 'Off', 'Auto', '50Hz', '60Hz');

procedure TFormSettings.SetComboBoxAntibanding(Camera: TACamera);
var CameraAntibanding, Antibanding: TAntibanding;
begin
  ComboBoxAntibanding.ItemIndex := -1;
  ComboBoxAntibanding.Items.Clear;
  ComboBoxAntibanding.Enabled := False;

  CameraAntibanding := Camera.Antibanding;
  for Antibanding in Camera.SupportedAntibandings do
  begin
    ComboBoxAntibanding.Items.Add(AntibandingNames[Antibanding]);
    if Antibanding = CameraAntibanding then
      ComboBoxAntibanding.ItemIndex := ComboBoxAntibanding.Items.Count - 1;
  end;
  ComboBoxAntibanding.Enabled := ComboBoxAntibanding.Items.Count > 1;
end;

const WhiteBalanceNames: array [TWhiteBalance] of string = (
  'Unknown', 'Auto', 'Cloudy daylight', 'Daylight', 'Fluorescent',
  'Incandescent', 'Shade', 'Twilight', 'Warm fluorescent');

procedure TFormSettings.SetComboBoxWhiteBalance(Camera: TACamera);
var CameraWhiteBalance, WhiteBalance: TWhiteBalance;
begin
  ComboBoxWhiteBalance.ItemIndex := -1;
  ComboBoxWhiteBalance.Items.Clear;
  ComboBoxWhiteBalance.Enabled := False;

  CameraWhiteBalance := Camera.WhiteBalance;
  for WhiteBalance in Camera.SupportedWhiteBalance do
  begin
    ComboBoxWhiteBalance.Items.Add(WhiteBalanceNames[WhiteBalance]);
    if WhiteBalance = CameraWhiteBalance then
      ComboBoxWhiteBalance.ItemIndex := ComboBoxWhiteBalance.Items.Count - 1;
  end;
  ComboBoxWhiteBalance.Enabled := ComboBoxWhiteBalance.Items.Count > 1;
end;

procedure TFormSettings.TabControlChange(Sender: TObject);
begin
  if TabControl.TabIndex = 1 then
    SetCameraInfo
end;

function TFormSettings.AddItem(const Text: string): TTreeViewItem;
begin
  Result := TTreeViewItem.Create(TreeView);
  Result.Text := Text;
  Result.IsExpanded := True;
  TreeView.AddObject(Result);
end;

function TFormSettings.AddItem(TreeViewItem: TTreeViewItem; const Text: string): TTreeViewItem;
begin
  Result := TTreeViewItem.Create(TreeViewItem);
  Result.Text := Text;
  TreeViewItem.AddObject(Result);
end;

procedure TFormSettings.SetCameraInfo;
const
  ImageFormatNames: array [TImageFormat] of string = (
    'Unknown', 'JPEG', 'NV16', 'NV21',
    'Raw10', 'Raw12', 'RawSensor', 'RawPrivate',
    'Private', 'Depth16', 'DepthPointCloud',
    'RGB565', 'FlexRGB888', 'FlexRGBA8888',
    'YUV420_888', 'YUV422_888', 'YUV444_888', 'YUY2', 'YV12');
var
  Camera: TACamera;
  CameraInfo: TCameraInfo;
  Size: TSize;
  Sizes: TArray<TSize>;
  Format: TImageFormat;
  ZoomRatio: Integer;
  Item: TTreeViewItem;
begin
  TreeView.Clear;

  Camera := FormMain.ACamera;
  if not Camera.Active then
    Exit;

  CameraInfo := Camera.CameraInfo[ComboBoxCamera.ItemIndex];

  AddItem('Can disable shutter sound: ' + BooleanToStr(CameraInfo.CanDisableShutterSound));
  AddItem('EV: ' + FloatToStrF(Camera.EV, ffFixed, 10, 2));
  AddItem('Exposure compensation: ' + IntToStr(Camera.ExposureCompensation));
  AddItem('Exposure compensation step: ' + FloatToStrF(Camera.ExposureCompensationStep, ffFixed, 10, 2));
  AddItem('Focal length: ' + FloatToStrF(Camera.FocalLength, ffFixed, 10, 2));
  AddItem('Horizontal view angle: ' + FloatToStrF(Camera.HorizontalViewAngle, ffFixed, 10, 2));
  AddItem('JPEG quality: ' + IntToStr(Camera.JpegQuality));
  AddItem('JPEG thumbnail quality: ' + IntToStr(Camera.JpegThumbnailQuality));
  AddItem('JPEG thumbnail size: ' + IntToStr(Camera.JpegThumbnailSize.Width) + ' x ' + IntToStr(Camera.JpegThumbnailSize.Height));
  AddItem('Max detected faces: ' + IntToStr(Camera.MaxDetectedFaces));
  AddItem('Max exposure compensation: ' + IntToStr(Camera.MaxExposureCompensation));
  if Camera.ZoomSupported then
    AddItem('Max zoom: ' + IntToStr(Camera.MaxZoom));
  AddItem('Min exposure compensation: ' + IntToStr(Camera.MinExposureCompensation));
  AddItem('Orientation: ' + IntToStr(CameraInfo.Orientation));
  if Camera.SupportedPictureFormats <> [] then
    AddItem('Picture format: ' + ImageFormatNames[Camera.PictureFormat]);
  AddItem('Preferred preview size: ' + IntToStr(Camera.PreferredPreviewSize.Width) + ' x ' + IntToStr(Camera.PreferredPreviewSize.Height));
  if Camera.SupportedPreviewFormats <> [] then
    AddItem('Preview format: ' + ImageFormatNames[Camera.PreviewFormat]);
  AddItem('Preview FPS: ' + FloatToStr(Camera.PreviewFps.Min / 1000.0) + ' - ' + FloatToStr(Camera.PreviewFps.Max / 1000.0));
  if Camera.ZoomSupported then
    AddItem('Smooth zoom supported: ' + BooleanToStr(Camera.SmoothZoomSupported));

  Sizes := Camera.SupportedJpegThumbnailSizes;
  if Length(Sizes) > 0 then
  begin
    Item := AddItem('Supported JPEG thumbnail sizes');
    for Size in Sizes do
      AddItem(Item, IntToStr(Size.Width) + ' x ' + IntToStr(Size.Height));
  end;

  if Camera.SupportedPictureFormats <> [] then
  begin
    Item := AddItem('Supported picture formats');
    for Format in Camera.SupportedPictureFormats do
      AddItem(Item, ImageFormatNames[Format]);
  end;

  if Camera.SupportedPreviewFormats <> [] then
  begin
    Item := AddItem('Supported preview formats');
    for Format in Camera.SupportedPreviewFormats do
      AddItem(Item, ImageFormatNames[Format]);
  end;

  Sizes := Camera.SupportedVideoSizes;
  if Length(Sizes) > 0 then
  begin
    Item := AddItem('Supported video sizes');
    for Size in Sizes do
      AddItem(Item, IntToStr(Size.Width) + ' x ' + IntToStr(Size.Height));
  end;

  AddItem('Vertical view angle: ' + FloatToStrF(Camera.VerticalViewAngle, ffFixed, 10, 2));

  if Camera.VideoStabilizationSupported then
    AddItem('Video stabilization: ' + BooleanToStr(Camera.VideoStabilization))
  else
    AddItem('Video stabilization suppported: False');

  if Camera.ZoomSupported then
  begin
    AddItem('Zoom: ' + IntToStr(Camera.Zoom));
    Item := AddItem('Zoom ratios');
    for ZoomRatio in Camera.ZoomRatios do
      AddItem(Item, FloatToStr(ZoomRatio / 100.0));
  end
  else
    AddItem('Zoom suppported: False');
end;

procedure TFormSettings.ComboBoxPictureSizeChange(Sender: TObject);
begin
  if ChangesDisabled or (ComboBoxPictureSize.ItemIndex = -1) then
    Exit;

  FormMain.ACamera.PictureSize := FormMain.ACamera.SupportedPictureSizes[ComboBoxPictureSize.ItemIndex];
end;

procedure TFormSettings.ComboBoxPreviewSizeChange(Sender: TObject);
begin
  if ChangesDisabled or (ComboBoxPreviewSize.ItemIndex = -1) then
    Exit;

  FormMain.ACamera.PreviewSize := FormMain.ACamera.SupportedPreviewSizes[ComboBoxPreviewSize.ItemIndex];
end;

procedure TFormSettings.ComboBoxSceneModeChange(Sender: TObject);
var SceneMode: TSceneMode;
begin
  if ChangesDisabled or (ComboBoxSceneMode.ItemIndex = -1) then
    Exit;

  for SceneMode := Low(TSceneMode) to High(TSceneMode) do
    if SceneModeNames[SceneMode] = ComboBoxSceneMode.Items[ComboBoxSceneMode.ItemIndex] then
    begin
      if FormMain.ACamera.SceneMode <> SceneMode then
      begin
        FormMain.ACamera.SceneMode := SceneMode;

        ChangesDisabled := True;
        try
          SetComboBoxPreviewSize(FormMain.ACamera);
          SetComboBoxPictureSize(FormMain.ACamera);
          SetComboBoxFocusMode(FormMain.ACamera);
          SetComboBoxFlashMode(FormMain.ACamera);
          SetComboBoxColorEffect(FormMain.ACamera);
          SetComboBoxAntibanding(FormMain.ACamera);
          SetComboBoxWhiteBalance(FormMain.ACamera);
        finally
          ChangesDisabled := False;
        end;
      end;
      Break;
    end;
end;

procedure TFormSettings.ComboBoxFocusModeChange(Sender: TObject);
var FocusMode: TFocusMode;
begin
  if ChangesDisabled or (ComboBoxFocusMode.ItemIndex = -1) then
    Exit;

  for FocusMode := Low(TFocusMode) to High(TFocusMode) do
    if FocusModeNames[FocusMode] = ComboBoxFocusMode.Items[ComboBoxFocusMode.ItemIndex] then
    begin
      FormMain.ACamera.FocusMode := FocusMode;
      Break;
    end;
end;

procedure TFormSettings.ComboBoxFlashModeChange(Sender: TObject);
var FlashMode: TFlashMode;
begin
  if ChangesDisabled or (ComboBoxFlashMode.ItemIndex = -1) then
    Exit;

  for FlashMode := Low(TFlashMode) to High(TFlashMode) do
    if FlashModeNames[FlashMode] = ComboBoxFlashMode.Items[ComboBoxFlashMode.ItemIndex] then
    begin
      FormMain.ACamera.FlashMode := FlashMode;
      Break;
    end;
end;

procedure TFormSettings.ComboBoxColorEffectChange(Sender: TObject);
var ColorEffect: TColorEffect;
begin
  if ChangesDisabled or (ComboBoxColorEffect.ItemIndex = -1) then
    Exit;

  for ColorEffect := Low(TColorEffect) to High(TColorEffect) do
    if ColorEffectNames[ColorEffect] = ComboBoxColorEffect.Items[ComboBoxColorEffect.ItemIndex] then
    begin
      FormMain.ACamera.ColorEffect := ColorEffect;
      Break;
    end;
end;

procedure TFormSettings.ComboBoxAntibandingChange(Sender: TObject);
var Antibanding: TAntibanding;
begin
  if ChangesDisabled or (ComboBoxAntibanding.ItemIndex = -1) then
    Exit;

  for Antibanding := Low(TAntibanding) to High(TAntibanding) do
    if AntibandingNames[Antibanding] = ComboBoxAntibanding.Items[ComboBoxAntibanding.ItemIndex] then
    begin
      FormMain.ACamera.Antibanding := Antibanding;
      Break;
    end;
end;

procedure TFormSettings.ComboBoxWhiteBalanceChange(Sender: TObject);
var WhiteBalance: TWhiteBalance;
begin
  if ChangesDisabled or (ComboBoxWhiteBalance.ItemIndex = -1) then
    Exit;

  for WhiteBalance := Low(TWhiteBalance) to High(TWhiteBalance) do
    if WhiteBalanceNames[WhiteBalance] = ComboBoxWhiteBalance.Items[ComboBoxWhiteBalance.ItemIndex] then
    begin
      FormMain.ACamera.WhiteBalance := WhiteBalance;
      Break;
    end;
end;

procedure TFormSettings.ApplySettings;
begin
  ComboBoxSceneModeChange(nil);
  ComboBoxPreviewSizeChange(nil);
  ComboBoxPictureSizeChange(nil);
  ComboBoxFocusModeChange(nil);
  ComboBoxFlashModeChange(nil);
  ComboBoxColorEffectChange(nil);
  ComboBoxAntibandingChange(nil);
  ComboBoxWhiteBalanceChange(nil);
end;

procedure TFormSettings.FormDeactivate(Sender: TObject);
begin
  FormMain.Start;
end;

procedure TFormSettings.FormShow(Sender: TObject);
var
  I: Integer;
  CameraText: string;
begin
  if not Initialized then
  begin
    Initialized := True;
    for I := 0 to FormMain.ACamera.CameraCount - 1 do
    begin
      CameraText := 'Camera ' + IntToStr(I);

      if FormMain.ACamera.CameraInfo[I].Facing = cfBack then
        CameraText := CameraText + ' (Back)'
      else
        CameraText := CameraText + ' (Front)';

      ComboBoxCamera.Items.Add(CameraText);
    end;

    ComboBoxCamera.ItemIndex := 0;
  end;
end;

end.
