//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "MainForm.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TfrmMain *frmMain;
//---------------------------------------------------------------------------
__fastcall TfrmMain::TfrmMain(TComponent* Owner) : TForm(Owner)
{
}
//---------------------------------------------------------------------------

/*
  Redraws the list by re-populating it.
*/
void TfrmMain::RedrawList(void)
{
    // This is an expensive way to force the list to be redrawn for word wrap.
  if (chkFontsOwnerDraw->Checked)
    btnGetFonts->Click();
}

/*
  Sets the 'DoubleBuffered' property recursively on the control and all
  of its child controls.
*/
void TfrmMain::RecurseDoubleBuffer(TWinControl *control, bool onoff)
{
  for (int i = 0; i < control->ControlCount; i++)
  {
      // Only descendants of TWinControl have a DoubleBuffered property
    TWinControl *c = dynamic_cast<TWinControl *>(control->Controls[i]);
    if (c)
    {
      c->DoubleBuffered = onoff;
      RecurseDoubleBuffer(c, onoff); // Set the control's children
    }
  }
}

/*
  Wraps a string within the width (pixels) given. Puts each wrapped line
  into the TStringList parameter.
*/
int TfrmMain::WrapText(const AnsiString& text, int width, TStringList* thelines)
{
    // Must use new for VCL classes
  TStringList *lines = new TStringList(); // The list of 'wrapped' lines
  TStringList *words = new TStringList(); // The list of words in the text

    // Break up the line into individual words. Nice!
  words->DelimitedText = text;
  words->Delimiter = ' ';

  AnsiString line;
  AnsiString temp;
  int size = 0;
  int count = 0;

    /*
        For each word in the text, concatenate it onto the existing line.
        If it's still withing 'width' pixels, continue. Otherwise, it's
        too long and we've found where the line should break.
    */
  for (int i = 0; i < words->Count; i++)
  {
      // Separate existing words with a single space
    if (line.Length() > 0)
      temp = line + " " + (*words)[i];
    else
      temp = line + (*words)[i];

      // Calculate the exact width of the string so far
    size = lstFonts->Canvas->TextWidth(temp);

      // Too big? Break the line here.
    if (size > width)
    {
      lines->Add(line); // Add the 'wrapped' line
      count++;
      line = (*words)[i]; // The 'overflow' is the start of the next line
      temp = "";
    }
    else // just add it to the line
    {
      if (line.Length() > 0)
        line += " " + (*words)[i];
      else
        line += (*words)[i];
    }
  }

    // Add the last line
  lines->Add(line);
  count++;

    // Copy the lines back to the caller
  if (thelines)
    thelines->Assign(lines);

  delete lines;
  delete words;

  return count; // The number of 'wrapped' lines in the list
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
// Event Handlers
//
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

/*
  Fills the list box with font names.
*/
void __fastcall TfrmMain::btnGetFontsClick(TObject *Sender)
{
    // The lhs filters the Intellisense on the rhs.
  lstFonts->Items = Screen->Fonts;
}
//---------------------------------------------------------------------------

void __fastcall TfrmMain::FormCreate(TObject *Sender)
{
  pgeMain->Align = alClient;
  pnlFontsRight->Align = alClient;
  pnlFontsRight->BevelOuter = bvNone;
  lblFontName->Caption = "";

    // Disable owner draw options
  chkFontsOwnerDrawClick(this);

    // Put some text in the preview
  mmoPreview->Lines->Add("abcdefghijklmnopqrstuvwxyz");
  mmoPreview->Lines->Add("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
  mmoPreview->Lines->Add("0123456789.:,;(*!?'/\\\")");
  mmoPreview->Lines->Add("The quick brown fox jumps over the lazy dog. SIR!");

  Width = 620;
  Height = 550;
}
//---------------------------------------------------------------------------

/*
  Event handler for clicking on the "Owner draw" checkbox.
  If checked, enable the group box's components. If unchecked,
  disable them.
*/
void __fastcall TfrmMain::chkFontsOwnerDrawClick(TObject *Sender)
{
    // Set each control in the group box to enabled/disabled
  for (int i = 0; i < grpOwnerDrawOptions->ControlCount; i++)
  {
    TControl *c = grpOwnerDrawOptions->Controls[i];
    c->Enabled = chkFontsOwnerDraw->Checked;
  }

    // Set the list's style appropriately
  if (chkFontsOwnerDraw->Checked)
  {
    lstFonts->Style = lbOwnerDrawVariable; // Each line may have a different height
  }
  else
    lstFonts->Style = lbStandard;
}
//---------------------------------------------------------------------------

void __fastcall TfrmMain::btnFontsClick(TObject *Sender)
{
  dlgFonts->Execute();
}
//---------------------------------------------------------------------------

/*
  Event handler for the OnMeasureItem event of the list box. It will be called
  for each item in the list box that needs to be drawn. (It first needs to be
  measured so it can be drawn in the correct area.) The height of the item
  is returned in the Height reference parameter.
*/
void __fastcall TfrmMain::lstFontsMeasureItem(TWinControl *Control, int Index, int &Height)
{
    // Get the text at Index
  AnsiString text = lstFonts->Items->Strings[Index];

    // Set the font properties because they affect the height of the text.
  lstFonts->Canvas->Font->Name = text;
  lstFonts->Canvas->Font->Size = spnFontSize->Position;

    // Kind of shortcut. W is the tallest and g is the lowest, so this
    // gives us a good value regardless of the actual text. The +1 gives
    // us room for the focus rectangle. Experiment with this code and
    // you'll see how it looks.
  Height = lstFonts->Canvas->TextHeight("Wg") + 2;

    // If we're wrapping, we could end up with multiple lines, which will
    // cause the height to be greater.
  if (chkWordWrap->Checked)
  {
      // ClientWidth accounts for the fact that there may be a scroll bar
      // that is visible. The ClientWidth may be less than the control's Width.
    int h = WrapText(text, lstFonts->ClientWidth, 0);

      // Make each line the same height. This can be adjusted so that each
      // line is a different height. This may be desirable.
    Height *= h;
  }
}
//---------------------------------------------------------------------------

/*
  Event handler for the OnDrawItem message of the list box. It will be called
  for each item when it needs to be drawn. This is where you do your custom
  drawing. Rect is the rectangle boundary to draw.
*/
void __fastcall TfrmMain::lstFontsDrawItem(TWinControl *Control, int Index, TRect &Rect, TOwnerDrawState State)
{
  AnsiString text = lstFonts->Items->Strings[Index];

    // Erase current item
  lstFonts->Canvas->FillRect(Rect);

    // Set font properties
  lstFonts->Canvas->Font->Name = text;
  lstFonts->Canvas->Font->Size = spnFontSize->Position;

    // Drawing with colors/styles? This is a contrived example!!!
  if (chkFontStyles->Checked)
  {
      // If the item is selected, draw in normal colors
    if (State.Contains(odSelected))
      lstFonts->Canvas->Font->Color = clWhite;
    else
    {
        // Fonts with second character 'a' or 'e' are in red
      char letter = lstFonts->Canvas->Font->Name[2];
      if (letter == 'a' || letter == 'e')
        lstFonts->Canvas->Font->Color = clRed;
      else
        lstFonts->Canvas->Font->Color = clBlue;
    }

      // If the third character is 'n' or 't', make it italic
    char letter = lstFonts->Canvas->Font->Name[3];
    if (letter == 'n' || letter == 't')
      lstFonts->Canvas->Font->Style = TFontStyles() << fsItalic;
    else
      lstFonts->Canvas->Font->Style = TFontStyles();
  }

    // Get the number of lines required for this string
  if (!chkWordWrap->Checked)
  {
    lstFonts->Canvas->TextOut(Rect.Left + 1, Rect.top + 1, text);
  }
  else
  {
    TStringList *p = new TStringList;
    int h = WrapText(text, lstFonts->ClientWidth, p);

      // Draw each wrapped line of the string
    int top = 0;
    for (int i = 0; i < h; i++)
    {
      lstFonts->Canvas->TextOut(Rect.Left + 1, Rect.top + top, (*p)[i].c_str());
      top += lstFonts->Canvas->TextHeight("Wg");
    }
    delete p;
  }
}
//---------------------------------------------------------------------------

/*
  When a font has been clicked on in the list, update some UI components
*/
void __fastcall TfrmMain::lstFontsClick(TObject *Sender)
{
    // Get the text of the selected item
  AnsiString text = lstFonts->Items->Strings[lstFonts->ItemIndex].c_str();

    // Label
  lblFontName->Caption = text;

    // Status bar
  barStatus->Panels->Items[0]->Text = " " + text;
  barStatus->Panels->Items[1]->Text = text;
  barStatus->Panels->Items[2]->Text = text;

    // Preview memo
  mmoPreview->Font->Name = text;
}
//---------------------------------------------------------------------------

void __fastcall TfrmMain::splitVerticalMoved(TObject *Sender)
{
  RedrawList();
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::chkFontStylesClick(TObject *Sender)
{
  lstFonts->Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::edtFontSizeChange(TObject *Sender)
{
  lstFonts->Font->Size = spnFontSize->Position;
  mmoPreview->Font->Size = spnFontSize->Position;
  RedrawList();
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::shtFontsResize(TObject *Sender)
{
  RedrawList();
}
//---------------------------------------------------------------------------

void __fastcall TfrmMain::chkDoubleBufferedClick(TObject *Sender)
{
  RecurseDoubleBuffer(shtFonts, chkDoubleBuffered->Checked);
}
//---------------------------------------------------------------------------

void __fastcall TfrmMain::chkWordWrapClick(TObject *Sender)
{
  RedrawList();
}
//---------------------------------------------------------------------------

/*
  When the status bar (panels) need to be redrawn, this handles the event.
  Rect is the rectangle boundary to draw.
*/
void __fastcall TfrmMain::barStatusDrawPanel(TStatusBar *StatusBar, TStatusPanel *Panel, const TRect &Rect)
{
    // If nothing is selected in the list box, do nothing
  int index = lstFonts->ItemIndex;
  if (index == -1)
    return;

    // Get the selected text from the list box
  AnsiString text = lstFonts->Items->Strings[index];

    // Set the Font property of the status bar to this text (Font)
  barStatus->Canvas->Font->Name = text;

    // Paint the second panel with white text on a red background
    //   Items[1] is the same as this: barStatus->Panels->operator[](1)
  if (Panel == barStatus->Panels->Items[1])
  {
    barStatus->Canvas->Font->Color = clWhite;
    barStatus->Canvas->Brush->Color = clRed;
  }
  else
  {
    // If you want other panels drawn differently, add code here.
  }

    // Erase current item (fills with the current brush)
  barStatus->Canvas->FillRect(Rect);

    // Draw text
  barStatus->Canvas->TextOut(Rect.Left + 4, Rect.top, text);

    // Reset back to "normal"
  barStatus->Canvas->Font->Color = clBlack;
  barStatus->Canvas->Brush->Color = clBtnFace;
}
//---------------------------------------------------------------------------