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

#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;
}
//---------------------------------------------------------------------------

