//
// Copyright (c) 1998 Colosseum Builders, Inc.
// All rights reserved.
//
// Colosseum Builders, Inc. makes no warranty, expressed or implied
// with regards to this software. It is provided as is.
//
// Permission to use, redistribute, and copy this file is granted
// without a fee so long as as the following conditions are adhered to:
//
// o The user assumes all risk for using this software. The authors of this
//   software shall be liable for no damages of any kind.
//
// o If the source code is distributed then this copyright notice must
//   remain unaltered and any modification must be noted.
//
// o If this code is shipped in binary format the accompanying documentation
//   should state that "this software is based, in part, on the work of
//   Colosseum Builders, Inc."
//

//
//  Title:  Sample Image Viewer/Format Conversion Application
//
//  Author:  John M. Miano miano@colosseumbuilders.com
//
//---------------------------------------------------------------------
#include <vcl.h>
#include <shellapi.h>
#include <clipbrd.hpp>
#include <fstream>
#pragma hdrstop

#include <cerrno>
using namespace std ;

#include "Main.h"
#include "About.h"
#include "JPEGConfig.h"
#include "gamma.h"
#include "pngconfig.h"
#include "alpha.h"
//---------------------------------------------------------------------
#pragma resource "*.dfm"

#include "jpgdecoder.h"
TMainForm *MainForm;

class TemporaryDisable
{
private:
  bool previous_state ;
  TControl *previous_control ;
public:
  TemporaryDisable (TControl *control)
  : previous_state (control->Enabled),
    previous_control (control)
  {
    control->Enabled = false ;
  }
  ~TemporaryDisable ()
  {
    previous_control->Enabled = previous_state ;
  }
} ;

//
//  Encoding Progress Function
//
void ProgressFunction (Colosseum::BitmapImageCoder &coder,
                              void *data,
                              unsigned int currentpass,
                              unsigned int passcount,
                              unsigned int progress,
                              bool &cancel)
{
  unsigned int value = (100 * (currentpass - 1) + progress)
                               / passcount ;

  MainForm->ProgressBar->Position = value ;
  Application->ProcessMessages () ;
  return ;
}
//---------------------------------------------------------------------
__fastcall TMainForm::TMainForm(TComponent *Owner)
	: TForm(Owner)
{
  show_progressive = false ;
  return ;
}
//---------------------------------------------------------------------
void __fastcall TMainForm::FormCreate(TObject *Sender)
{
	Application->OnHint = ShowHint;
	Screen->OnActiveFormChange = UpdateMenuItems;

  // Allow the user to drop files.
  DragAcceptFiles (Handle, true) ;

  // Here we remove the shading along the bottom and right from the
  // progress bar.
  LONG style = GetWindowLong (ProgressBar->Handle, GWL_EXSTYLE) ;
  style &= ~WS_EX_STATICEDGE ;
  SetWindowLong (ProgressBar->Handle, GWL_EXSTYLE, style) ;

  return ;
}
//---------------------------------------------------------------------
void __fastcall TMainForm::ShowHint(TObject *Sender)
{
	StatusBar->SimpleText = Application->Hint;
}
//---------------------------------------------------------------------
void __fastcall TMainForm::CreateMDIChild(String Name)
{
  TemporaryDisable disable (this) ;

  //--- create a new MDI child window ----
  TMDIChild *Child = new TMDIChild(Application);
  try
  {
    Child->ReadImage (Name) ;
  }
  catch (...)
  {
//    delete Child ;
    throw ;
  }
  if (Child->GetImageType () == Colosseum::UnknownImage)
  {
//    delete Child ;
    throw Exception ("Unknown or Invalid Image Format") ;
  }
  return ;
}
//---------------------------------------------------------------------
void __fastcall TMainForm::FileNewItemClick(TObject *Sender)
{
	CreateMDIChild("NONAME" + IntToStr(MDIChildCount + 1));
}
//---------------------------------------------------------------------
void __fastcall TMainForm::FileOpenItemClick(TObject *Sender)
{
	if (OpenDialog->Execute())
		CreateMDIChild(OpenDialog->FileName);
}
//---------------------------------------------------------------------
void __fastcall TMainForm::FileCloseItemClick(TObject *Sender)
{
	if (ActiveMDIChild)
		ActiveMDIChild->Close();
}
//---------------------------------------------------------------------
void __fastcall TMainForm::FileSaveItemClick(TObject *Sender)
{
  TMDIChild *child = dynamic_cast<TMDIChild *>(ActiveMDIChild) ;
  if (child == NULL)
    return ;

  TemporaryDisable disable (this) ;

  String filename = child->Caption ;
  String ext = ExtractFileExt (filename).UpperCase () ;

  MainForm->ShowProgressBar () ;
  Cursor = crHourGlass ;
  Colosseum::BitmapImageEncoder *encoder ;
  if (ext == ".JPG")
    encoder = &jpeg_encoder ;
  else if (ext == ".PNG")
    encoder = &png_encoder ;
  else if (ext == ".BMP")
    encoder = &bmp_encoder ;
  encoder->setProgressFunction (ProgressFunction, NULL) ;
  try
  {
    encoder->writeImageFile (filename.c_str (), child->GetImage ()) ;
  }
  catch (std::exception &ee)
  {
    ProgressBar->Visible = false ;
    Cursor = crDefault ;
    throw Exception (ee.what ()) ;
  }
  ProgressBar->Visible = false ;
  Cursor = crDefault ;
  return ;
}
//---------------------------------------------------------------------
void __fastcall TMainForm::FileSaveAsItemClick(TObject *Sender)
{
  TMDIChild *child = dynamic_cast<TMDIChild *>(ActiveMDIChild) ;
  if (child == NULL)
    return ;

  TemporaryDisable disable (this) ;

  String filename = child->Caption ;
  String ext = ExtractFileExt (filename).UpperCase () ;
  filename = filename.SubString (1, filename.Length () - ext.Length ()) ;
  SaveDialog->FileName = filename ;
  if (!SaveDialog->Execute ())
    return ;

  filename = SaveDialog->FileName ;
  ext = ExtractFileExt (filename) ;
  if (ext == "")
  {
    switch (SaveDialog->FilterIndex)
    {
    case 1: filename += ".JPG" ; break ;
    case 2: filename += ".PNG" ; break ;
    case 3: filename += ".BMP" ; break ;
    }
  }
  MainForm->ShowProgressBar () ;
  Cursor = crHourGlass ;
  Colosseum::BitmapImageEncoder *encoder ;
  switch (SaveDialog->FilterIndex)
  {
  case 1:
    encoder = &jpeg_encoder ;
    break ;
  case 2:
    encoder = &png_encoder ;
    break ;
  case 3:
    encoder = &bmp_encoder ;
    break ;
  }
  encoder->setProgressFunction (ProgressFunction, NULL) ;
  try
  {
    encoder->writeImageFile (filename.c_str (), child->GetImage ()) ;
  }
  catch (std::exception &ee)
  {
    ProgressBar->Visible = false ;
    Cursor = crDefault ;
    throw Exception (ee.what ()) ;
  }
  ProgressBar->Visible = false ;
  Cursor = crDefault ;
  child->Caption = filename ;
  return ;
}
//---------------------------------------------------------------------
void __fastcall TMainForm::FileExitItemClick(TObject *Sender)
{
	Close();
}
//---------------------------------------------------------------------
void __fastcall TMainForm::CutItemClick(TObject *Sender)
{
	//---- cut selection to clipboard ----
}
//---------------------------------------------------------------------
void __fastcall TMainForm::CopyItemClick(TObject *Sender)
{
	//---- copy selection to clipboard ----
  TMDIChild *child = dynamic_cast<TMDIChild *>(ActiveMDIChild) ;
  if (child == NULL)
    return ;

  TemporaryDisable disable (this) ;

  child->CopyToClipboard () ;
  return ;
}
//---------------------------------------------------------------------
void __fastcall TMainForm::PasteItemClick(TObject *Sender)
{
  TemporaryDisable disable (this) ;

	//---- paste from clipboard ----
  TMDIChild *Child = new TMDIChild(Application);
  try
  {
    Child->CopyFromClipboard () ;
  }
  catch (...)
  {
    delete Child ;
    throw ;
  }
  if (Child->GetImageType () == Colosseum::UnknownImage)
  {
    delete Child ;
    throw Exception ("Unknown or Invalid Image Format") ;
  }
  return ;
}
//---------------------------------------------------------------------
void __fastcall TMainForm::WindowCascadeItemClick(TObject *Sender)
{
	Cascade();
}
//---------------------------------------------------------------------
void __fastcall TMainForm::WindowTileItemClick(TObject *Sender)
{
	Tile();
}
//---------------------------------------------------------------------
void __fastcall TMainForm::WindowArrangeItemClick(TObject *Sender)
{
	ArrangeIcons();
}
//---------------------------------------------------------------------
void __fastcall TMainForm::WindowMinimizeItemClick(TObject *Sender)
{
	int i;

	//---- Must be done backwards through the MDIChildren array ----
	for (i=MDIChildCount-1; i >= 0; i--)
		MDIChildren[i]->WindowState = wsMinimized;
}
//---------------------------------------------------------------------
void __fastcall TMainForm::UpdateMenuItems(TObject *Sender)
{
	FileCloseItem->Enabled = MDIChildCount > 0;
	FileSaveAsItem->Enabled = MDIChildCount > 0;
	CopyItem->Enabled = MDIChildCount > 0;
	PasteItem->Enabled = Clipboard ()->HasFormat (CF_DIB) ;
	SaveBtn->Enabled = MDIChildCount > 0;
	CopyBtn->Enabled = MDIChildCount > 0;
	PasteBtn->Enabled = Clipboard ()->HasFormat (CF_DIB) ;
	WindowCascadeItem->Enabled = MDIChildCount > 0;
	WindowTileItem->Enabled = MDIChildCount > 0;
	WindowArrangeItem->Enabled = MDIChildCount > 0;
	WindowMinimizeItem->Enabled = MDIChildCount > 0;
  GammaItem->Enabled = MDIChildCount > 0 ;
  GrayscaleItem->Enabled = MDIChildCount > 0 ;
  AlphaChannelMenu->Enabled = MDIChildCount > 0 ;
  MergeImageMenu->Enabled = MDIChildCount > 0 ;
  return ;
}
//---------------------------------------------------------------------
void __fastcall TMainForm::FormDestroy(TObject *Sender)
{
	Screen->OnActiveFormChange = NULL;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::HelpAboutItemClick(TObject *Sender)
{
  AboutBox->ShowModal();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::WMDropFiles (TMessage &msg)
{
  TemporaryDisable disable (this) ;

  HANDLE hdrop = (HANDLE) msg.WParam ;
  char buffer [FILENAME_MAX] ;
  UINT count = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0) ;
  for (unsigned int ii = 0 ; ii < count ; ++ ii)
  {
    DragQueryFile (hdrop, ii, buffer, FILENAME_MAX) ;
    CreateMDIChild (buffer) ;
  }
  DragFinish (hdrop) ;
  return ;
}

void __fastcall TMainForm::Options1Click(TObject *Sender)
{
  ShowProgressive1->Checked = ShowProgressive ;
  return ;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ShowProgressive1Click(TObject *Sender)
{
  show_progressive = ! show_progressive ;
  ShowProgressive1->Checked = show_progressive ;
  return ;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::GammaItemClick(TObject *Sender)
{
  TMDIChild *child = dynamic_cast<TMDIChild *>(ActiveMDIChild) ;
  if (child == NULL)
    return ;

  TemporaryDisable disable (this) ;

  GammaDlg->GammaValue = child->GammaValue ;
  GammaDlg->ShowModal () ;
  if (GammaDlg->ModalResult == mrOk)
    child->GammaValue = GammaDlg->GammaValue ;
  return ;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::GrayscaleItemClick(TObject *Sender)
{
  TMDIChild *child = dynamic_cast<TMDIChild *>(ActiveMDIChild) ;
  if (child == NULL)
    return ;

  TemporaryDisable disable (this) ;

  child->Grayscale() ;
  return ;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::JPEGOptionsItemClick(TObject *Sender)
{
  try
  {
    JPEGOptions->ShowModal (jpeg_encoder) ;
  }
  catch (std::exception &ee)
  {
    Application->MessageBox ((char *)ee.what (), (char*) "Image Viewer", 0) ;
  }
  return ;
}
//---------------------------------------------------------------------------
void TMainForm::ShowProgressBar ()
{
  // We use this function to dislay the progress bar.
  ProgressBar->Parent = MainForm->StatusBar ;
  ProgressBar->Left = MainForm->StatusBar->ClientRect.Left ;
  ProgressBar->Top = MainForm->StatusBar->ClientRect.Top ;
  ProgressBar->Width = MainForm->StatusBar->ClientRect.Right
                     - MainForm->StatusBar->ClientRect.Left ;
  ProgressBar->Height = MainForm->StatusBar->ClientRect.Bottom
                      - MainForm->StatusBar->ClientRect.Top ;
  ProgressBar->Visible = true ;
  return ;
}

void __fastcall TMainForm::PNGOptions1Click(TObject *Sender)
{
  PngConfiguration->ShowModal (png_encoder) ;
  return ;
}
//---------------------------------------------------------------------------


void __fastcall TMainForm::AlphaChannelMenuClick(TObject *Sender)
{
  TMDIChild *child = dynamic_cast<TMDIChild *>(ActiveMDIChild) ;
  if (child == NULL)
    return ;

  TemporaryDisable disable (this) ;

  AlphaChannelDialog->SetAlpha (0xFF) ;
  AlphaChannelDialog->ShowModal () ;
  if (AlphaChannelDialog->ModalResult == mrOk)
    child->SetAlpha (AlphaChannelDialog->GetAlpha ()) ;
  return ;

}
//---------------------------------------------------------------------------

void __fastcall TMainForm::MergeImageMenuClick(TObject *Sender)
{
  TMDIChild *child = dynamic_cast<TMDIChild *>(ActiveMDIChild) ;
  if (child == NULL)
    return ;
  if (OpenDialog->Execute ())
  {
    TemporaryDisable disable (this) ;

    child->MergeImage (OpenDialog->FileName) ;
  }
  return ;
}
//---------------------------------------------------------------------------


