2025-04-27 07:49:33 -04:00

2708 lines
90 KiB
C++

/******************************************************************************
Source File: Font Viewer.CPP
This implements the various classes that make up the font editor for the
studio. The editor is basically a property sheet with a sizable collection
of pages.
Copyright (c) 1997 by Microsoft Corporation. All Rights Reserved.
A Pretty Penny Enterprises Production.
Change History:
03-05-1997 Bob_Kjelgaard@Prodigy.Net
******************************************************************************/
#include "StdAfx.H"
#if defined(LONG_NAMES)
#include "MiniDriver Developer Studio.H"
#include "Child Frame.H" // Definition of Tool Tips Property Page class
#include "Font Viewer.H"
#else
#include "MiniDev.H"
#include "ChildFrm.H"
#include "FontView.H"
#endif
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/******************************************************************************
CFontViewer class- this is the guy who owns the overall control of the view,
although he wisely delegates the work to the MFC Property Sheet class and the
other view classes. I should be so wise.
******************************************************************************/
IMPLEMENT_DYNCREATE(CFontViewer, CView)
CFontViewer::CFontViewer() {
}
CFontViewer::~CFontViewer() {
}
BEGIN_MESSAGE_MAP(CFontViewer, CView)
//{{AFX_MSG_MAP(CFontViewer)
ON_WM_DESTROY()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFontViewer drawing
void CFontViewer::OnDraw(CDC* pDC) {
CDocument* pDoc = GetDocument();
}
/////////////////////////////////////////////////////////////////////////////
// CFontViewer diagnostics
#ifdef _DEBUG
void CFontViewer::AssertValid() const {
CView::AssertValid();
}
void CFontViewer::Dump(CDumpContext& dc) const {
CView::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CFontViewer message handlers
/******************************************************************************
CFontViewer::OnInitialUpdate
This handles the initial update of the view, meaning all of the background
noise of creation is essentially complete.
I initialize the property pages by pointing each to the underlying CFontInfo,
add them to the property sheet as needed, then create the sheet, position it
so it aligns with the view, then adjust the owning frame's size and style so
that everything looks like it really belongs where it is.
******************************************************************************/
void CFontViewer::OnInitialUpdate() {
CFontInfo *pcfi = GetDocument() -> Font();
if (pcfi -> Name().IsEmpty()) {
pcfi -> Rename(GetDocument() -> GetTitle());
GetDocument() -> SetModifiedFlag(FALSE); // Rename sets it
}
m_cps.Construct(IDR_MAINFRAME, this);
m_cfgp.Init(pcfi);
m_cfgp2.Init(pcfi);
m_cfhp.Init(pcfi);
m_cfsp.Init(pcfi);
m_cfdp.Init(pcfi);
m_cfcp.Init(pcfi);
m_cfwp.Init(pcfi);
m_cfkp.Init(pcfi);
m_cps.AddPage(&m_cfgp);
m_cps.AddPage(&m_cfgp2);
m_cps.AddPage(&m_cfhp);
m_cps.AddPage(&m_cfcp);
m_cps.AddPage(&m_cfdp);
m_cps.AddPage(&m_cfsp);
m_cps.AddPage(&m_cfwp);
m_cps.AddPage(&m_cfkp);
// Create the property sheet
m_cps.Create(this, WS_CHILD, WS_EX_CLIENTEDGE);
// Get the bounding rectangle, and use it to set the frame size,
// after first using it to align the origin with this view.
CRect crPropertySheet;
m_cps.GetWindowRect(crPropertySheet);
crPropertySheet -= crPropertySheet.TopLeft();
m_cps.MoveWindow(crPropertySheet, FALSE);
GetParentFrame() -> CalcWindowRect(crPropertySheet);
GetParentFrame() -> SetWindowPos(NULL, 0, 0, crPropertySheet.Width(),
crPropertySheet.Height(),
SWP_NOZORDER | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
CView::OnInitialUpdate();
m_cps.ShowWindow(SW_SHOWNA);
GetParentFrame() -> ShowWindow(SW_SHOW);
}
/******************************************************************************
CFontViewer::OnActivateView
For some reason, the property sheet does not get the focus when the frame is
activated (probably the view class takes it away from us). This little gem
makes sure keyboard users don't get miffed by this.
******************************************************************************/
void CFontViewer::OnActivateView(BOOL bActivate, CView* pcvActivate,
CView* pcvDeactivate) {
// In case the base class does anything else of value, pass it on...
CView::OnActivateView(bActivate, pcvActivate, pcvDeactivate);
if (bActivate)
m_cps.SetFocus();
}
/******************************************************************************
CFontViewer::OnDestroy
This override is used to inform the embedded font that we are being
destroyed. If we were created by the font, then it will NULL its pointer
to us, and won't try to detroy us when it is destroyed.
******************************************************************************/
void CFontViewer::OnDestroy() {
CView::OnDestroy();
if (GetDocument() -> Font())
GetDocument() -> Font() -> OnEditorDestroyed();
}
/******************************************************************************
CFontGeneralPage class
This implements the class that handles the General information page for the
font viewer/editor.
Even this page is an incredibly busy one, with about 20 controls on it.
******************************************************************************/
CFontGeneralPage::CFontGeneralPage() : CToolTipPage(CFontGeneralPage::IDD) {
//{{AFX_DATA_INIT(CFontGeneralPage)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
CFontGeneralPage::~CFontGeneralPage() {
}
void CFontGeneralPage::DoDataExchange(CDataExchange* pDX){
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFontGeneralPage)
DDX_Control(pDX, IDC_UniqueName, m_ceUnique);
DDX_Control(pDX, IDC_StyleName, m_ceStyle);
DDX_Control(pDX, IDC_FaceName, m_ceFace);
DDX_Control(pDX, IDC_RemoveFamily, m_cbRemoveFamily);
DDX_Control(pDX, IDC_AddFamily, m_cbAddFamily);
DDX_Control(pDX, IDC_FamilyNames, m_ccbFamilies);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CFontGeneralPage, CToolTipPage)
//{{AFX_MSG_MAP(CFontGeneralPage)
ON_CBN_EDITCHANGE(IDC_FamilyNames, OnEditchangeFamilyNames)
ON_BN_CLICKED(IDC_AddFamily, OnAddFamily)
ON_BN_CLICKED(IDC_RemoveFamily, OnRemoveFamily)
ON_EN_KILLFOCUS(IDC_FaceName, OnKillfocusFaceName)
ON_EN_KILLFOCUS(IDC_StyleName, OnKillfocusStyleName)
ON_EN_KILLFOCUS(IDC_UniqueName, OnKillfocusUniqueName)
ON_BN_CLICKED(IDC_VariablePitch, OnVariablePitch)
ON_BN_CLICKED(IDC_FixedPitch, OnFixedPitch)
ON_BN_CLICKED(IDC_Scalable, OnScalable)
//}}AFX_MSG_MAP
ON_CONTROL_RANGE(BN_CLICKED, IDC_Italic, IDC_StrikeOut, OnStyleClicked)
END_MESSAGE_MAP()
/******************************************************************************
CFontGeneralPage::OnInitDialog
This is an override which is used to initialize the controls on the property
page. Since there are a lot of controls, there's a bit of substance to this
one.
******************************************************************************/
BOOL CFontGeneralPage::OnInitDialog() {
CToolTipPage::OnInitDialog();
// Fill in the various name controls
SetDlgItemText(IDC_FaceName, m_pcfi -> FaceName());
SetDlgItemText(IDC_StyleName, m_pcfi -> StyleName());
SetDlgItemText(IDC_UniqueName, m_pcfi -> UniqueName());
for (unsigned u = 0; u < m_pcfi -> Families(); u++)
m_ccbFamilies.AddString(m_pcfi -> Family(u));
m_ccbFamilies.SetCurSel(0);
m_cbRemoveFamily.EnableWindow(m_pcfi -> Families() > 1);
m_cbAddFamily.EnableWindow(FALSE);
// Character Styles group box
CheckDlgButton(IDC_Italic, m_pcfi -> GetStyle() & CFontInfo::Italic);
CheckDlgButton(IDC_Underline,
m_pcfi -> GetStyle() & CFontInfo::Underscore);
CheckDlgButton(IDC_StrikeOut,
m_pcfi -> GetStyle() & CFontInfo::StrikeOut);
// Pitch Buttons
CheckRadioButton(IDC_FixedPitch, IDC_VariablePitch,
IDC_FixedPitch + m_pcfi -> IsVariableWidth());
CheckDlgButton(IDC_Scalable, m_pcfi -> IsScalable());
return TRUE; // return TRUE unless you set the focus to a control
}
/******************************************************************************
CFontGeneralPage::OnEditChangeFamilyNames
When the name in the edit control changes, compare the contents to the list
of names currently in the control. If it is new, enable the Add Family
button.
******************************************************************************/
void CFontGeneralPage::OnEditchangeFamilyNames() {
CString csContents;
m_ccbFamilies.GetWindowText(csContents);
for (unsigned u = 0; u < m_pcfi -> Families(); u++)
if (!csContents.CompareNoCase(m_pcfi -> Family(u)))
break;
// Handle the button enabling- we can either add or delete, or neither,
// but we can never do both!
m_cbAddFamily.EnableWindow(u >= m_pcfi -> Families());
m_cbRemoveFamily.EnableWindow(m_pcfi -> Families() > 1 &&
u < m_pcfi -> Families());
}
/******************************************************************************
CFontGeneralPage::OnAddFamily
This handles presses of the Add Family button, by adding the name in the edit
control to the list in the box (as well as to the real list), and then making
it the current selection.
******************************************************************************/
void CFontGeneralPage::OnAddFamily() {
CString csNew;
m_ccbFamilies.GetWindowText(csNew);
if (!m_pcfi -> AddFamily(csNew)) {
m_ccbFamilies.SelectString(-1, csNew);
return;
}
int id = m_ccbFamilies.AddString(csNew);
m_ccbFamilies.SetCurSel(id);
// Disable the Add button, and set focus to the family list
m_ccbFamilies.SetFocus();
m_cbAddFamily.EnableWindow(FALSE);
}
/******************************************************************************
CFontGeneralPage::OnRemoveFamily
This function removes the family name currently in the edit control from the
list. This may or may not be the current selection, but if this function is
entered, then it was recognized as an existing name.
******************************************************************************/
void CFontGeneralPage::OnRemoveFamily() {
CString csDead;
m_ccbFamilies.GetWindowText(csDead);
int id = m_ccbFamilies.SelectString(-1, csDead);
if (id != CB_ERR) {
m_ccbFamilies.DeleteString(id);
m_ccbFamilies.SetCurSel(id - (id >= m_ccbFamilies.GetCount()));
}
else
m_ccbFamilies.SetCurSel(0);
m_pcfi -> RemoveFamily(csDead);
}
/******************************************************************************
CFontGeneralPage::OnKillfocusFaceName
CFontGeneralPage::OnKillfocusStyleName
CFontGeneralPage::OnKillfocusUniqueName
These functions get called when the associated control loses focus. I check
and see if the text has been changed. If it has, then I update the related
name. This is more effective and less intervention than updating the name
every time the user strikes a key (not to mention it makes cut, paste, and
undo features of the control transparent to this UI function).
******************************************************************************/
void CFontGeneralPage::OnKillfocusFaceName() {
if (!m_ceFace.GetModify())
return;
CString csFace;
m_ceFace.GetWindowText(csFace);
m_pcfi -> SetFaceName(csFace);
m_ceFace.SetModify(FALSE);
}
void CFontGeneralPage::OnKillfocusStyleName() {
if (!m_ceStyle.GetModify())
return;
CString csStyle;
m_ceStyle.GetWindowText(csStyle);
m_pcfi -> SetStyleName(csStyle);
m_ceStyle.SetModify(FALSE);
}
void CFontGeneralPage::OnKillfocusUniqueName() {
if (!m_ceUnique.GetModify())
return;
CString csUnique;
m_ceUnique.GetWindowText(csUnique);
m_pcfi -> SetUniqueName(csUnique);
m_ceUnique.SetModify(FALSE);
}
/******************************************************************************
CFontGeneralPage::OnStyleClicked
This is our final control range handler, called whenever any of the font
style flags is modified. We assemble the current settings, and pass the
info on to the CFontInfo class for processing.
******************************************************************************/
void CFontGeneralPage::OnStyleClicked(unsigned uid) {
unsigned uStyle = 0;
if (IsDlgButtonChecked(IDC_Italic))
uStyle |= CFontInfo::Italic;
if (IsDlgButtonChecked(IDC_Underline))
uStyle |= CFontInfo::Underscore;
if (IsDlgButtonChecked(IDC_StrikeOut))
uStyle |= CFontInfo::StrikeOut;
m_pcfi -> SetStyle(uStyle);
}
/******************************************************************************
CFontGeneralPage::OnVariablePitch
CFontGeneralPage::OnFixedPitch
These handle the user pressing the radio buttons for variable/fixed pitch.
This gets passed to the font to handle.
******************************************************************************/
void CFontGeneralPage::OnVariablePitch() {
m_pcfi -> ChangePitch();
}
void CFontGeneralPage::OnFixedPitch() {
m_pcfi -> ChangePitch(TRUE);
}
/******************************************************************************
CFontGeneralPage::OnScalable
This will be called whwnever the font scalability button is clicked. Since
it is a check box, it will toggle, but all we need do is pass its value back
to the font.
******************************************************************************/
void CFontGeneralPage::OnScalable() {
m_pcfi -> SetScalability(IsDlgButtonChecked(IDC_Scalable));
}
/******************************************************************************
CFontHeightPage class
This class defines the page which shows the bounding box for the font along
with the height subdivisions (leading, ascender, etc.)
******************************************************************************/
static WORD awFamilies[] = {FF_MODERN, FF_ROMAN, FF_SWISS, FF_SCRIPT,
FF_DECORATIVE},
awCharSets[] = {ANSI_CHARSET, SYMBOL_CHARSET, SHIFTJIS_CHARSET,
HANGEUL_CHARSET, CHINESEBIG5_CHARSET,
GB2312_CHARSET, OEM_CHARSET},
awSpecial[] = {IDS_CapH, IDS_LowerX, IDS_SuperSizeX,
IDS_SuperSizeY, IDS_SubSizeX, IDS_SubSizeY,
IDS_SuperMoveX, IDS_SuperMoveY, IDS_SubMoveX,
IDS_SubMoveY, IDS_ItalicAngle, IDS_UnderSize,
IDS_UnderOffset, IDS_StrikeSize, IDS_StrikeOffset,
IDS_Baseline, IDS_InterlineGap, IDS_Lowerp,
IDS_Lowerd, IDS_InternalLeading};
/******************************************************************************
CFontHeightPage::ShowCharacters
This fills in the special character edit controls with either the byte or
WORD values, as specified by the radio buttons on the sheet.
******************************************************************************/
void CFontHeightPage::ShowCharacters() {
for (unsigned u = CFontInfo::First; u <= CFontInfo::Break; u++) {
CString csWork;
csWork.Format(_T("%X"), m_pcfi -> SignificantChar(u,
IsDlgButtonChecked(IDC_UnicodeShown)));
SetDlgItemText(IDC_FirstCharacter + u, csWork);
SendDlgItemMessage(IDC_FirstCharacter + u, EM_LIMITTEXT,
2 << IsDlgButtonChecked(IDC_UnicodeShown), 0);
}
}
/******************************************************************************
CFontHeightPage::Demonstrate
This private member demonstrates the specified font metric
******************************************************************************/
void CFontHeightPage::Demonstrate(unsigned uMetric) {
CWnd *pcwDemo = GetDlgItem(IDC_FontAnimation);
pcwDemo -> RedrawWindow();
CDC *pcdc = pcwDemo -> GetDC();
if (!pcdc)
return;
CRect crWindow, crDemo;
pcwDemo -> GetClientRect(crWindow);
crDemo.SetRectEmpty(); // Unless it is needed later.
CHAR cDisplayMain = 'A';
int iPenWidth = 1, iWidth, iHeight;
CPoint cptStart(5, m_pcfi -> SpecialMetric(uMetric)),
cptEnd(-6 + 2 * m_pcfi -> MaxWidth(),
m_pcfi -> SpecialMetric(uMetric));
BOOL bMoreText = FALSE;
switch (uMetric) {
case CFontInfo::CapH:
cptStart.y = cptEnd.y = m_pcfi -> SpecialMetric(CFontInfo::Baseline) -
cptEnd.y;
cDisplayMain = 'H';
break;
case CFontInfo::LowerX:
cptStart.y = cptEnd.y = m_pcfi -> SpecialMetric(CFontInfo::Baseline) -
cptEnd.y;
cDisplayMain = 'x';
break;
case CFontInfo::Lowerp:
cptStart.y = cptEnd.y = m_pcfi -> SpecialMetric(CFontInfo::Baseline) +
cptEnd.y;
cDisplayMain = 'p';
break;
case CFontInfo::Lowerd:
cptStart.y = cptEnd.y = m_pcfi -> SpecialMetric(CFontInfo::Baseline) -
cptEnd.y;
cDisplayMain = 'd';
break;
case CFontInfo::SuperSizeX:
case CFontInfo::SuperSizeY:
case CFontInfo::SuperMoveX:
case CFontInfo::SuperMoveY:
cptStart.x += m_pcfi -> SpecialMetric(CFontInfo::SuperMoveX);
cptStart.y = m_pcfi -> SpecialMetric(CFontInfo::Baseline) -
m_pcfi -> SpecialMetric(CFontInfo::SuperMoveY);
iWidth = m_pcfi -> SpecialMetric(CFontInfo::SuperSizeX);
iHeight = m_pcfi -> SpecialMetric(CFontInfo::SuperSizeY);
iPenWidth = 0; // No pen!
bMoreText = TRUE;
break;
case CFontInfo::SubSizeX:
case CFontInfo::SubSizeY:
case CFontInfo::SubMoveX:
case CFontInfo::SubMoveY:
cptStart.x += m_pcfi -> SpecialMetric(CFontInfo::SubMoveX);
cptStart.y = m_pcfi -> SpecialMetric(CFontInfo::Baseline) -
m_pcfi -> SpecialMetric(CFontInfo::SubMoveY);
iWidth = m_pcfi -> SpecialMetric(CFontInfo::SubSizeX);
iHeight = m_pcfi -> SpecialMetric(CFontInfo::SubSizeY);
iPenWidth = 0; // No pen!
bMoreText = TRUE;
break;
case CFontInfo::InterlineGap:
iPenWidth = 0; // No pen!
crDemo.right = -10 + m_pcfi -> MaxWidth() * 2;
crDemo.bottom = m_pcfi -> SpecialMetric(uMetric);
crDemo.OffsetRect(5, m_pcfi -> Height());
break;
case CFontInfo::InternalLeading:
iPenWidth = 0; // No pen!
crDemo.right = -10 + m_pcfi -> MaxWidth() * 2;
crDemo.bottom = m_pcfi -> SpecialMetric(uMetric);
crDemo.OffsetRect(5, 0);
break;
case CFontInfo::UnderOffset:
case CFontInfo::UnderSize:
iPenWidth = m_pcfi -> SpecialMetric(CFontInfo::UnderSize);
cptStart.y = cptEnd.y =
m_pcfi -> SpecialMetric(CFontInfo::Baseline) -
m_pcfi -> SpecialMetric(CFontInfo::UnderOffset);
break;
case CFontInfo::StrikeOffset:
case CFontInfo::StrikeSize:
iPenWidth = m_pcfi -> SpecialMetric(CFontInfo::StrikeSize);
cptStart.y = cptEnd.y =
m_pcfi -> SpecialMetric(CFontInfo::Baseline) -
m_pcfi -> SpecialMetric(CFontInfo::StrikeOffset);
break;
case CFontInfo::ItalicAngle:
cptStart.y = m_pcfi -> SpecialMetric(CFontInfo::Baseline);
m_pcfi -> InterceptItalic(cptEnd);
break;
}
// All of the fonts requested should resemble the printer font as far
// as serifs, weight, italics, etc. The face name is not used, and as
// much as possible, we demand a TrueType font so the image looks good.
CFont cfDemo;
cfDemo.CreateFont(m_pcfi -> Height(), m_pcfi -> AverageWidth(), 0, 0,
m_pcfi -> Weight(), m_pcfi -> GetStyle() & CFontInfo::Italic, 0, 0,
(BYTE) m_pcfi -> CharSet(), OUT_TT_PRECIS, CLIP_TT_ALWAYS,
DEFAULT_QUALITY, m_pcfi -> Family() | TMPF_TRUETYPE, NULL);
// Use an Anisotropic mapping so we can use font units directly in the
// animation, and let GDI do any needed transforms. Then clip everything
// to the area we really want to draw in. This keeps things less messy.
// The device space is the size of one line plus any interline gap in
// height, and twice the maximum character width. It scales as these
// valuse do.
pcdc -> SetMapMode(MM_ANISOTROPIC);
pcdc -> SetWindowExt(m_pcfi -> MaxWidth() * 2,
m_pcfi -> Height() + m_pcfi -> SpecialMetric(CFontInfo::InterlineGap));
pcdc -> SetViewportExt(crWindow.Width(), crWindow.Height());
pcdc -> IntersectClipRect(5, 0, -6 + 2 * m_pcfi -> MaxWidth(),
m_pcfi -> Height() + m_pcfi -> SpecialMetric(CFontInfo::InterlineGap));
// Output the main character
CFont *pcfOld = pcdc -> SelectObject(&cfDemo);
pcdc -> SetBkMode(TRANSPARENT);
pcdc -> TextOut(5, 0, &cDisplayMain, 1);
pcdc -> SelectObject(pcfOld);
// Output any other characters
if (bMoreText) {
CFont cfDemo;
cfDemo.CreateFont(iHeight, iWidth, 0, 0, m_pcfi -> Weight(),
m_pcfi -> GetStyle() & CFontInfo::Italic, 0, 0,
(BYTE) m_pcfi -> CharSet(), OUT_TT_PRECIS, CLIP_TT_ALWAYS,
DEFAULT_QUALITY, m_pcfi -> Family() | TMPF_TRUETYPE, NULL);
// Output the main character
CString csWork(_T("Sample"));
CFont *pcfOld = pcdc -> SelectObject(&cfDemo);
pcdc -> SetBkMode(TRANSPARENT);
pcdc -> TextOut(cptStart.x, cptStart.y, csWork);
pcdc -> SelectObject(pcfOld);
}
// Draw any lines that were requested
if (iPenWidth) {
CPen cpen;
cpen.CreatePen(PS_SOLID, iPenWidth, RGB(0,0,0));
CPen *pcpOld = pcdc -> SelectObject(&cpen);
pcdc -> MoveTo(cptStart);
pcdc -> LineTo(cptEnd);
pcdc -> SelectObject(pcpOld);
}
// Draw any filled areas that might need it.
if (!crDemo.IsRectEmpty()) {
CGdiObject* cpOld = pcdc -> SelectStockObject(BLACK_PEN);
CGdiObject* cbOld = pcdc -> SelectStockObject(LTGRAY_BRUSH);
pcdc -> Rectangle(crDemo);
pcdc -> SelectObject(cpOld);
pcdc -> SelectObject(cbOld);
}
pcwDemo -> ReleaseDC(pcdc);
}
/******************************************************************************
CFontHeightPage constructor, destructor, et al.
******************************************************************************/
CFontHeightPage::CFontHeightPage() : CToolTipPage(CFontHeightPage::IDD) {
//{{AFX_DATA_INIT(CFontHeightPage)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_bSpun = FALSE;
m_uTimer = 0;
}
CFontHeightPage::~CFontHeightPage() {
}
/******************************************************************************
CFontHeightPage::OnSetActive
When the page is made active, we have to update the Maximum and average
character widths, as changes elsewhere could have affected them.
******************************************************************************/
BOOL CFontHeightPage::OnSetActive() {
// Show the current maximum width. It can only be altered if the font is
// fixed pitch.
SetDlgItemInt(IDC_FontWidth, m_pcfi -> MaxWidth());
m_ceMaxWidth.EnableWindow(!m_pcfi -> IsVariableWidth());
CString csWork;
csWork.Format("Average: %d", m_pcfi -> AverageWidth());
SetDlgItemText(IDC_AverageWidth, csWork);
// If scalability has changed, then the EXTTEXTMETRIC metrics may need
// to be added or removed.
if (m_pcfi -> IsScalable() &&
m_ccbSpecial.GetCount() < CFontInfo::InternalLeading) {
csWork.LoadString(awSpecial[CFontInfo::Lowerd]);
int id = m_ccbSpecial.AddString(csWork);
m_ccbSpecial.SetItemData(id, CFontInfo::Lowerd);
csWork.LoadString(awSpecial[CFontInfo::Lowerp]);
id = m_ccbSpecial.AddString(csWork);
m_ccbSpecial.SetItemData(id, CFontInfo::Lowerp);
}
if (!m_pcfi -> IsScalable() &&
m_ccbSpecial.GetCount() > CFontInfo::InternalLeading) {
for (int i = m_ccbSpecial.GetCount(); i--; )
switch (m_ccbSpecial.GetItemData(i)) {
case CFontInfo::Lowerd:
case CFontInfo::Lowerp:
m_ccbSpecial.DeleteString(i);
continue;
}
}
// Hack- set a timer so we can animate after the dialog is painted
m_uTimer = SetTimer(IDD, 200, NULL);
return TRUE;
}
void CFontHeightPage::DoDataExchange(CDataExchange* pDX) {
CToolTipPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFontHeightPage)
DDX_Control(pDX, IDC_FontWeight, m_ceMaxWidth);
DDX_Control(pDX, IDC_FontSpecialValue, m_ceSpecial);
DDX_Control(pDX, IDC_SpecialMetric, m_ccbSpecial);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CFontHeightPage, CToolTipPage)
//{{AFX_MSG_MAP(CFontHeightPage)
ON_CBN_SELCHANGE(IDC_SpecialMetric, OnSelchangeSpecialMetric)
ON_EN_KILLFOCUS(IDC_FontSpecialValue, OnKillfocusFontSpecialValue)
ON_NOTIFY(UDN_DELTAPOS, IDC_SpinFontSpecial, OnDeltaposSpinFontSpecial)
ON_EN_KILLFOCUS(IDC_FontWidth, OnKillfocusFontWidth)
ON_EN_KILLFOCUS(IDC_FontHeight, OnKillfocusFontHeight)
ON_EN_KILLFOCUS(IDC_FontWeight, OnKillfocusFontWeight)
ON_CBN_SELCHANGE(IDC_FamilyBits, OnSelchangeFamilyBits)
ON_CBN_SELCHANGE(IDC_CharSet, OnSelchangeCharSet)
ON_WM_TIMER()
//}}AFX_MSG_MAP
ON_CONTROL_RANGE(BN_CLICKED, IDC_ShowANSI, IDC_UnicodeShown, OnEncoding)
ON_CONTROL_RANGE(EN_KILLFOCUS, IDC_DefaultCharacter, IDC_BreakCharacter,
OnKillfocusSignificant)
END_MESSAGE_MAP()
/******************************************************************************
CFontHeightPage::OnInitDialog
This handles the WM_INITDIALOG message. We fill the controls with their
initial values.
******************************************************************************/
BOOL CFontHeightPage::OnInitDialog() {
CToolTipPage::OnInitDialog();
// Family control
for (unsigned u = 0; u < sizeof awFamilies / sizeof awFamilies[0]; u++)
if (m_pcfi -> Family() == awFamilies[u])
break;
SendDlgItemMessage(IDC_FamilyBits,CB_SETCURSEL, u, 0);
// CharSet Control
for (u = 0; u < sizeof awCharSets / sizeof awCharSets[0]; u++)
if (m_pcfi -> CharSet() == awCharSets[u])
break;
SendDlgItemMessage(IDC_CharSet,CB_SETCURSEL, u, 0);
// Simple numerics
SetDlgItemInt(IDC_FontWeight, m_pcfi -> Weight());
SetDlgItemInt(IDC_FontHeight, m_pcfi -> Height());
// Character codes- default to Unicode
CheckRadioButton(IDC_ShowANSI, IDC_UnicodeShown, IDC_UnicodeShown);
ShowCharacters();
// Fill in the special metrics controls
CString csWork;
for (u = 0; u <= CFontInfo::InternalLeading; u++) {
if (!m_pcfi -> IsScalable() && (u == CFontInfo::Lowerd ||
u == CFontInfo::Lowerp))
continue;
csWork.LoadString(awSpecial[u]);
int id = m_ccbSpecial.AddString(csWork);
m_ccbSpecial.SetItemData(id, u);
}
m_ccbSpecial.SetCurSel(0);
OnSelchangeSpecialMetric(); // Reflect the selected item!
return TRUE;
}
/******************************************************************************
CFontHeightPage::OnSelchangeSpecialMetric
This is called whwnever a new special metric is selected. The value is
loaded into the edit control, the new range is set in the spic control, and
the animation is updated.
******************************************************************************/
void CFontHeightPage::OnSelchangeSpecialMetric() {
int id = m_ccbSpecial.GetCurSel();
if (id < 0)
return; // Can't do anything if nothing is selected
unsigned uMetric = m_ccbSpecial.GetItemData(id);
SetDlgItemInt(IDC_FontSpecialValue, m_pcfi -> SpecialMetric(uMetric));
SendDlgItemMessage(IDC_FontSpecialValue, EM_SETMODIFY, FALSE, 0);
short sMax = m_pcfi -> Height(), sMin = 0;
switch (uMetric) {
case CFontInfo::SuperSizeX:
case CFontInfo::SubSizeX:
sMax = m_pcfi -> MaxWidth();
sMin = 1;
break;
case CFontInfo::StrikeSize:
sMax = m_pcfi -> SpecialMetric(CFontInfo::Baseline);
sMin = 1;
break;
case CFontInfo::UnderSize:
sMax -= m_pcfi -> SpecialMetric(CFontInfo::Baseline);
sMin = 1;
break;
case CFontInfo::Lowerp:
sMax -= m_pcfi -> SpecialMetric(CFontInfo::Baseline);
break;
case CFontInfo::Lowerd:
case CFontInfo::LowerX:
if (m_pcfi -> SpecialMetric(CFontInfo::CapH))
sMax = m_pcfi -> SpecialMetric(CFontInfo::CapH);
break;
case CFontInfo::InterlineGap:
sMax <<= 1; // Should be overkill!
break;
case CFontInfo::ItalicAngle:
sMax = 800; // Should be more than enough, really.
break;
case CFontInfo::UnderOffset:
case CFontInfo::SubMoveY:
sMax = 0;
sMin = m_pcfi -> SpecialMetric(CFontInfo::Baseline) -
m_pcfi -> Height();
}
SendDlgItemMessage(IDC_SpinFontSpecial, UDM_SETRANGE, 0,
MAKELONG(sMax, sMin));
Demonstrate(uMetric);
}
/******************************************************************************
CFontHeightPage::OnKillfocusFontSpecialValue
This is called when the edit control for the special metric loses focus. The
updated value, if any, is read from the control, and the animation updated to
reflect this.
******************************************************************************/
void CFontHeightPage::OnKillfocusFontSpecialValue() {
if ((!m_bSpun && !m_ceSpecial.GetModify()) ||
m_ccbSpecial.GetCurSel() < 0)
return; // Nothing changed, or nothing to change
short sSpecial = GetDlgItemInt(IDC_FontSpecialValue);
m_pcfi -> SetSpecial(m_ccbSpecial.GetItemData(m_ccbSpecial.GetCurSel()),
sSpecial);
m_ceSpecial.SetModify(FALSE);
m_bSpun = FALSE;
Demonstrate(m_ccbSpecial.GetItemData(m_ccbSpecial.GetCurSel()));
}
/******************************************************************************
CFontHeightPage::OnDeltaposSpinFontSpecial
This is called when the spinnrer is used to change the value in the font
special value box. We set the modify flag, as this doesn't happen when the
spin control sets the value using SetWindowText.
******************************************************************************/
void CFontHeightPage::OnDeltaposSpinFontSpecial(NMHDR* pnmh, LRESULT* plr) {
m_bSpun = TRUE;
if (m_uTimer)
KillTimer(m_uTimer);
m_uTimer = SetTimer(IDD, 50, NULL);
*plr = 0;
}
/******************************************************************************
CFontHeightPage::OnEncoding
This member is called when either of the character encoding buttons is
selected. It simply calls ShowCharacters to do its thing.
******************************************************************************/
void CFontHeightPage::OnEncoding(unsigned uid) {
ShowCharacters();
}
/******************************************************************************
CFontHeightPage::OnKillfocusFontWidth
This is called when the font width control loses the input focus. If the
width has been modified, we pass that information on to the font, then
use other functions to update the various affected controls.
******************************************************************************/
void CFontHeightPage::OnKillfocusFontWidth() {
m_pcfi -> SetMaxWidth(GetDlgItemInt(IDC_FontWidth));
OnSetActive(); // Update the display as needed
}
/******************************************************************************
CFontHeightPage::OnKillfocusFontHeight
This member gets called when the focus leaves the font height control.
Update the font with the latest info is all that's necessary.
******************************************************************************/
void CFontHeightPage::OnKillfocusFontHeight() {
if (m_pcfi -> SetHeight(GetDlgItemInt(IDC_FontHeight)))
OnSelchangeSpecialMetric(); // Just in case the current one did
else
SetDlgItemInt(IDC_FontHeight, m_pcfi -> Height());
}
/******************************************************************************
CFontHeightPage::OnKillfocusFontWeight
This member will be called when the font weight control is exited. If it has
changed, it will be limit checked, and passed to the font if it is OK.
******************************************************************************/
void CFontHeightPage::OnKillfocusFontWeight() {
WORD wWeight = GetDlgItemInt(IDC_FontWeight, NULL, FALSE);
if (wWeight == m_pcfi -> Weight())
return; // Nothing to change
if (wWeight > 1000) {
AfxMessageBox(IDS_Overweight);
GetDlgItem(IDC_FontWeight) -> SetFocus();
SendDlgItemMessage(IDC_FontWeight, EM_SETSEL, 0, -1);
return;
}
m_pcfi -> SetWeight(wWeight);
}
/******************************************************************************
CFontHeightPage::OnSelchangeFamilyBits
This member will get called when the selection changes in the font family
combo box. This one is pretty simple, but I probably should be hard-nosed
about Modern being fixed pitch, while Swiss and Roman are not.
******************************************************************************/
void CFontHeightPage::OnSelchangeFamilyBits() {
switch (SendDlgItemMessage(IDC_FamilyBits, CB_GETCURSEL, 0, 0)) {
case sizeof awFamilies / sizeof awFamilies[0]:
m_pcfi -> SetFamily(FF_DONTCARE);
case LB_ERR:
case LB_ERRSPACE:
return; // Nothing selected
default:
m_pcfi -> SetFamily((BYTE) awFamilies[
SendDlgItemMessage(IDC_FamilyBits, CB_GETCURSEL, 0, 0)]);
}
}
/******************************************************************************
CFontHeightPage::OnSelchangeCharSet
This is another fairly simple one- we tell the font to use the selected
character set. However, it must validate it with the font, as otherwise,
some rather nasty invalid combinations could result.
******************************************************************************/
void CFontHeightPage::OnSelchangeCharSet() {
if (0 > SendDlgItemMessage(IDC_CharSet, CB_GETCURSEL, 0, 0))
return; // Nothing has changed
if (!m_pcfi -> SetCharacterSet((BYTE) awCharSets[
SendDlgItemMessage(IDC_CharSet, CB_GETCURSEL, 0, 0)])) {
AfxMessageBox(IDS_InvalidCharSet);
for (unsigned u = 0; u < sizeof awCharSets / sizeof awCharSets[0]; u++)
if (m_pcfi -> CharSet() == awCharSets[u])
break;
SendDlgItemMessage(IDC_CharSet,CB_SETCURSEL, u, 0);
}
}
/******************************************************************************
CFontHeightPage::OnKillfocusSignificant
This is called whenever we losr focus on one of the editable significant
character controls (break or default). We let the font decide if the new
value is OK, but we display any requisite error messages ourselves.
******************************************************************************/
void CFontHeightPage::OnKillfocusSignificant(unsigned uid) {
CString csWork;
WORD wChar;
GetDlgItemText(uid, csWork);
if (1 == _stscanf(csWork, " %x ", &wChar))
switch (m_pcfi -> SetSignificant(uid - IDC_FirstCharacter, wChar,
IsDlgButtonChecked(IDC_UnicodeShown))) {
case CFontInfo::OK:
return;
case CFontInfo::InvalidChar:
AfxMessageBox(IDS_InvalidCharacter);
break;
case CFontInfo::DoubleByte:
AfxMessageBox(IDS_NoDBCS);
}
else
AfxMessageBox(IDS_InvalidNumberFormat);
GetDlgItem(uid) -> SetFocus();
SendDlgItemMessage(uid, EM_SETSEL, 0, -1);
}
/******************************************************************************
CFontHeightPage::OnTimer
This is a bit of a hack. It it is our timer, go ahead and animate the
current settings.
******************************************************************************/
void CFontHeightPage::OnTimer(UINT nIDEvent) {
if (nIDEvent != m_uTimer)
CToolTipPage::OnTimer(nIDEvent);
KillTimer(m_uTimer);
// Cause a demonstration!
if (m_bSpun)
OnKillfocusFontSpecialValue(); // Pick up the altered value!
else
OnSelchangeSpecialMetric();
}
/******************************************************************************
CFontWidthsPage property page class
This class handles the UFM editor Character Widths page. It is derived from
the Tool Tip Page class. The page consists of a list view control in which
the code points and their associated widths are displayed.
******************************************************************************/
/******************************************************************************
CFontWidthsPage::Sort(LPARAM lp1, LPARAM lp2, LPARAM lp3)
This is a private static member function- a callback for sorting the list.
The first two parameters are the LPARAM members of two list view items- in
this case, the indices of two code points. The final one is supplied by the
caller of the sort routine. In this case, it is a pointer to the caller.
Handling it is trivial- dereference the this pointer, and let the private
member function for sorting handle it.
******************************************************************************/
int CALLBACK CFontWidthsPage::Sort(LPARAM lp1, LPARAM lp2, LPARAM lp3) {
CFontWidthsPage *pcfwp = (CFontWidthsPage *) lp3;
_ASSERT(pcfwp);
return pcfwp -> Sort(lp1, lp2);
}
/******************************************************************************
CFontWidthsPage::Sort(unsigned id1, unsigned id2)
This is a private member function which compares the two glyph handles at the
two indices given by the established sort criteria.
It returns negative for 1 < 2, positive for 1 > 2, and 0 for 1 = 2- pretty
standard stuff.
The sort column member determines the order of precedence in which the
sorting is to be done, while the SortDescending member is a bitfield showing
the sort direction in each column.
*******************************************************************************/
int CFontWidthsPage::Sort(unsigned id1, unsigned id2) {
// If the Primnary sort is by widths- weed it out first.
if (!m_iSortColumn)
switch (m_pcfi -> CompareWidths(id1, id2)) {
case CFontInfo::More:
return (m_bSortDescending & 1) ? -1 : 1;
case CFontInfo::Less:
return (m_bSortDescending & 1) ? 1 : -1;
}
// Sort is by Unicode point- this is always well-ordered
// Furthermore, the glyph handles are always in ascending order, making
// This test trivial.
return (!(m_bSortDescending & 2) ^ (id1 < id2)) ? 1 : -1;
}
CFontWidthsPage::CFontWidthsPage() : CToolTipPage(CFontWidthsPage::IDD) {
//{{AFX_DATA_INIT(CFontWidthsPage)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_bSortDescending = 0;
m_iSortColumn = 1;
}
CFontWidthsPage::~CFontWidthsPage() {
}
void CFontWidthsPage::DoDataExchange(CDataExchange* pDX) {
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFontWidthsPage)
DDX_Control(pDX, IDC_CharacterWidths, m_clcView);
//}}AFX_DATA_MAP
}
/******************************************************************************
CFontWidthsPage::OnSetActive
This member will be called by the framework when the page is made active.
The base class gets this first, and it will initialize everything the first
time.
This is here to update the view on subsequent activations, so we can
seamlessly handle changes from fixed to variable pitch and back.
******************************************************************************/
BOOL CFontWidthsPage::OnSetActive() {
if (!CToolTipPage::OnSetActive())
return FALSE;
// IsVariableWidth is either 0 or 1, so == is safe, here
if (m_pcfi -> IsVariableWidth() == !!m_clcView.GetItemCount())
return TRUE; // Everything is copacetic
if (m_clcView.GetItemCount())
m_clcView.DeleteAllItems();
else
m_pcfi -> FillWidths(m_clcView);
m_clcView.EnableWindow(m_pcfi -> IsVariableWidth());
return TRUE;
}
BEGIN_MESSAGE_MAP(CFontWidthsPage, CToolTipPage)
//{{AFX_MSG_MAP(CFontWidthsPage)
ON_NOTIFY(LVN_ENDLABELEDIT, IDC_CharacterWidths, OnEndlabeleditCharacterWidths)
ON_NOTIFY(LVN_COLUMNCLICK, IDC_CharacterWidths, OnColumnclickCharacterWidths)
ON_NOTIFY(LVN_KEYDOWN, IDC_CharacterWidths, OnKeydownCharacterWidths)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFontWidthsPage message handlers
/******************************************************************************
CFontWidthsPage::OnInitDialog
This member function fills initializes the list view and fills it with the
font width information.
******************************************************************************/
BOOL CFontWidthsPage::OnInitDialog() {
CToolTipPage::OnInitDialog();
CString csWork;
csWork.LoadString(IDS_WidthColumn0);
m_clcView.InsertColumn(0, csWork, LVCFMT_CENTER,
m_clcView.GetStringWidth(csWork) << 1, 0);
csWork.LoadString(IDS_WidthColumn1);
m_clcView.InsertColumn(1, csWork, LVCFMT_CENTER,
m_clcView.GetStringWidth(csWork) << 1, 1);
m_pcfi -> FillWidths(m_clcView);
m_clcView.SetItemState(0, LVIS_SELECTED | LVIS_FOCUSED,
LVIS_SELECTED | LVIS_FOCUSED);
return TRUE;
}
/******************************************************************************
CFontWidthsPage::OnEndlabeleditCharacterWidths
This is where we find out the user actually wanted to change the width of a
character. So, not too surprisingly, we do just that (and also update the
maximum and average widths if this isn't a DBCS font).
******************************************************************************/
void CFontWidthsPage::OnEndlabeleditCharacterWidths(NMHDR* pnmh, LRESULT* plr){
LV_DISPINFO* plvdi = (LV_DISPINFO*) pnmh;
*plr = 0; // Assume failure
if (!plvdi -> item.pszText) // Editing canceled?
return;
CString csNew(plvdi -> item.pszText);
csNew.TrimRight();
csNew.TrimLeft();
if (csNew.SpanIncluding("1234567890").GetLength() != csNew.GetLength()) {
AfxMessageBox(IDS_InvalidNumberFormat);
return;
}
m_pcfi -> SetWidth(plvdi -> item.iItem, (WORD) atoi(csNew));
*plr = TRUE;
}
/******************************************************************************
CFontWidthsPage::OnColumnClickCharacterWidths
This little ditty tells us one of the column headers was clicked. We
obligingly either change sort direction or precednce to match, and then sort
the list.
******************************************************************************/
void CFontWidthsPage::OnColumnclickCharacterWidths(NMHDR* pnmh, LRESULT* plr) {
NM_LISTVIEW* pnmlv = (NM_LISTVIEW*) pnmh;
if (m_iSortColumn == pnmlv -> iSubItem)
m_bSortDescending ^= 1 << m_iSortColumn; // Flip sort direction
else
m_iSortColumn = pnmlv -> iSubItem;
m_clcView.SortItems(Sort, (LPARAM) this); // Sort the list!
*plr = 0;
}
/******************************************************************************
CFontWidthsPage::OnKeydownCharacterWidths
I'd hoped to do thiw when ENTER was pressed, but finding out which class is
eating the keystroke took too long. Here, we look for F2 as the key to
signal the need to edit the width of interest.
Pretty straightforward- find out who has the focus and is selected, and edit
their label.
******************************************************************************/
void CFontWidthsPage::OnKeydownCharacterWidths(NMHDR* pnmh, LRESULT* plr) {
LV_KEYDOWN * plvkd = (LV_KEYDOWN *) pnmh;
*plr = 0;
if (plvkd -> wVKey != VK_F2)
return;
int idItem = m_clcView.GetNextItem(-1, LVIS_FOCUSED | LVIS_SELECTED);
if (idItem == -1)
return;
CEdit *pce = m_clcView.EditLabel(idItem);
if (pce)
pce -> ModifyStyle(0, ES_NUMBER);
}
/******************************************************************************
CAddKernPair dialog class
This class handles the dialog displayed when the user wishes to add a kern
pair to the kern pair array.
This class is used by the CFontKerningPage class
******************************************************************************/
class CAddKernPair : public CDialog {
CSafeMapWordToOb &m_csmw2oFirst, &m_csmw2oSecond;
CWordArray &m_cwaPoints;
WORD m_wFirst, m_wSecond;
// Construction
public:
CAddKernPair(CSafeMapWordToOb& cmsw2o1, CSafeMapWordToOb& cmsw2o2,
CWordArray& cwaPoints, CWnd* pParent);
WORD First() const { return m_wFirst; }
WORD Second() const { return m_wSecond; }
// Dialog Data
//{{AFX_DATA(CAddKernPair)
enum { IDD = IDD_AddKernPair };
CButton m_cbOK;
CComboBox m_ccbSecond;
CComboBox m_ccbFirst;
short m_sAmount;
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAddKernPair)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CAddKernPair)
virtual BOOL OnInitDialog();
afx_msg void OnSelchangeKernFirst();
afx_msg void OnSelchangeKernSecond();
afx_msg void OnChangeKernAmount();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAddKernPair::CAddKernPair(CSafeMapWordToOb& csmw2o1,
CSafeMapWordToOb& csmw2o2, CWordArray& cwaPoints,
CWnd* pParent)
: CDialog(CAddKernPair::IDD, pParent), m_csmw2oFirst(csmw2o1),
m_csmw2oSecond(csmw2o2), m_cwaPoints(cwaPoints) {
//{{AFX_DATA_INIT(CAddKernPair)
m_sAmount = 0;
//}}AFX_DATA_INIT
m_wFirst = m_wSecond = 0;
}
void CAddKernPair::DoDataExchange(CDataExchange* pDX) {
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAddKernPair)
DDX_Control(pDX, IDOK, m_cbOK);
DDX_Control(pDX, IDC_KernSecond, m_ccbSecond);
DDX_Control(pDX, IDC_KernFirst, m_ccbFirst);
DDX_Text(pDX, IDC_KernAmount, m_sAmount);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAddKernPair, CDialog)
//{{AFX_MSG_MAP(CAddKernPair)
ON_CBN_SELCHANGE(IDC_KernFirst, OnSelchangeKernFirst)
ON_CBN_SELCHANGE(IDC_KernSecond, OnSelchangeKernSecond)
ON_EN_CHANGE(IDC_KernAmount, OnChangeKernAmount)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CAddKernPair message handlers
/******************************************************************************
CAddKernPair::OnInitDialog
This member function initializes the dialog box, by filling both combo boxes,
and disabling the OK button.
******************************************************************************/
BOOL CAddKernPair::OnInitDialog() {
CDialog::OnInitDialog(); // Initialize everything
// Fill in the first combo box
CString csWork;
for (int i = 0; i < m_cwaPoints.GetSize(); i++) {
csWork.Format("%4.4X", m_cwaPoints[i]);
int id = m_ccbFirst.AddString(csWork);
m_ccbFirst.SetItemData(id, m_cwaPoints[i]);
}
m_ccbFirst.SetCurSel(0);
OnSelchangeKernFirst(); // Fill the second box with this code.
m_cbOK.EnableWindow(FALSE);
return TRUE;
}
/******************************************************************************
CAddKernPair::OnSelchangeKernFirst
This member is called whenever the selection changes in the first character
combo box. It screens out any already paired characters from the second
character combo box, while preserving the currently selected character (if
possible).
******************************************************************************/
void CAddKernPair::OnSelchangeKernFirst() {
int id = m_ccbFirst.GetCurSel();
if (id < 0)
return;
m_wFirst = (WORD) m_ccbFirst.GetItemData(id);
// See which character is selected in the second box, so we can keep it
// if it is still valid.
id = m_ccbSecond.GetCurSel();
m_wSecond = (id > -1) ? (WORD) m_ccbSecond.GetItemData(id) : 0;
m_ccbSecond.ResetContent();
CString csWork;
for (id = 0; id < m_cwaPoints.GetSize(); id++) {
union {
CObject *pco;
CMapWordToDWord *pcmw2dFirst;
};
DWORD dwIgnore;
if (m_csmw2oFirst.Lookup(m_wFirst, pco) &&
pcmw2dFirst -> Lookup(m_cwaPoints[id], dwIgnore)) {
// There is already a kern pair for this second point
// Don't include it in the list, and drop it if it is
// the currently selected second point.
if (m_wSecond == m_cwaPoints[id])
m_wSecond = 0;
continue;
}
csWork.Format("%4.4X", m_cwaPoints[id]);
int id2 = m_ccbSecond.AddString(csWork);
m_ccbSecond.SetItemData(id2, m_cwaPoints[id]);
if (m_wSecond == m_cwaPoints[id])
m_ccbSecond.SetCurSel(id2);
}
if (!m_wSecond) {
m_ccbSecond.SetCurSel(0);
m_wSecond = (WORD) m_ccbSecond.GetItemData(0);
}
}
/******************************************************************************
CAddKernPair::OnSelchangeKernSecond
This member is called whenever the selection changes in the second character
combo box. It screens out any already paired characters from the first
character combo box, while preserving the currently selected character (if
possible).
******************************************************************************/
void CAddKernPair::OnSelchangeKernSecond() {
int id = m_ccbSecond.GetCurSel();
if (id < 0)
return;
m_wSecond = (WORD) m_ccbSecond.GetItemData(id);
// See which character is selected in the first box, so we can keep it
// if it is still valid.
id = m_ccbFirst.GetCurSel();
m_wFirst = (id > -1) ? (WORD) m_ccbFirst.GetItemData(id) : 0;
m_ccbFirst.ResetContent();
CString csWork;
for (id = 0; id < m_cwaPoints.GetSize(); id++) {
union {
CObject *pco;
CMapWordToDWord *pcmw2dSecond;
};
DWORD dwIgnore;
if (m_csmw2oSecond.Lookup(m_wSecond, pco) &&
pcmw2dSecond -> Lookup(m_cwaPoints[id], dwIgnore)) {
// There is already a kern pair for this first point
// Don't include it in the list, and drop it if it is
// the currently selected first point.
if (m_wFirst == m_cwaPoints[id])
m_wFirst = 0;
continue;
}
csWork.Format("%4.4X", m_cwaPoints[id]);
int id2 = m_ccbFirst.AddString(csWork);
m_ccbFirst.SetItemData(id2, m_cwaPoints[id]);
if (m_wFirst == m_cwaPoints[id])
m_ccbFirst.SetCurSel(id2);
}
if (!m_wFirst) {
m_ccbFirst.SetCurSel(0);
m_wFirst = (WORD) m_ccbFirst.GetItemData(0);
}
}
/******************************************************************************
CAddKernPair::OnChangeKernAmount
This member gets called when a change is made to the amount edit box. It
enables the OK button if a non-zero amount seems to be there. The DDX/DDV
functions called from OnOK (by default) will handle any garbage that may
have been entered, so this needn't be a complete screen.
******************************************************************************/
void CAddKernPair::OnChangeKernAmount() {
// Don't use DDX/DDV, as it will complain if the user's just typed a
// minus sign. All we care about is the amount is non-zero, so we can
// enable/disable the OK button, as needed.
m_cbOK.EnableWindow(!!GetDlgItemInt(IDC_KernAmount));
}
/******************************************************************************
CFontKerningPage class
This class handles the font kerning page- the UI here consists of a list view
showing the pairs- the view can be sorted several ways, and pairs can be
added or deleted.
******************************************************************************/
/******************************************************************************
CFontKerningPage::Sort(LPARAM lp1, LPARAM lp2, LPARAM lpThis)
This is a static private function used to interface the listview's sort
callback requirements (to which this adheres) to the classes sort routine,
which follows.
******************************************************************************/
int CALLBACK CFontKerningPage::Sort(LPARAM lp1, LPARAM lp2, LPARAM lpThis) {
CFontKerningPage *pcfkp = (CFontKerningPage *) lpThis;
return pcfkp -> Sort(lp1, lp2);
}
/******************************************************************************
CFontKerningPage::Sort(unsigned u1, unsigned u2)
This member returns -1, 0, 0r 1 to indiciate if the kern pair at index u1 is
less than, equal to, or greater than the pair at u2, respectively. The sort
criteria are based on the internal control members.
******************************************************************************/
int CFontKerningPage::Sort(unsigned u1, unsigned u2) {
for (unsigned u = 0; u < 3; u++) {
switch (m_uPrecedence[u]) {
case Amount:
switch (m_pcfi -> CompareKernAmount(u1, u2)) {
case CFontInfo::Less:
return (m_ufDescending & 1) ? 1 : -1;
case CFontInfo::More:
return (m_ufDescending & 1) ? -1 : 1;
}
continue; // If they are equal
case First:
switch (m_pcfi -> CompareKernFirst(u1, u2)) {
case CFontInfo::Less:
return (m_ufDescending & 2) ? 1 : -1;
case CFontInfo::More:
return (m_ufDescending & 2) ? -1 : 1;
}
continue; // If they are equal
default: // Assume this is always second
switch (m_pcfi -> CompareKernSecond(u1, u2)) {
case CFontInfo::Less:
return (m_ufDescending & 4) ? 1 : -1;
case CFontInfo::More:
return (m_ufDescending & 4) ? -1 : 1;
}
continue; // If they are equal
}
}
_ASSERT(FALSE);
return 0; // This should never happen- two items can never be equal
}
/******************************************************************************
CFontKerningPage Constructor, destructor, message map, and DDX/DDV.
Except for some trivial construction, all of this is pretty standard MFC
wizard-maintained stuff.
******************************************************************************/
CFontKerningPage::CFontKerningPage() : CToolTipPage(CFontKerningPage::IDD) {
//{{AFX_DATA_INIT(CFontKerningPage)
//}}AFX_DATA_INIT
m_idSelected = -1;
m_ufDescending = 0;
m_uPrecedence[0] = Second; // This is the default precedence in UFM
m_uPrecedence[1] = First;
m_uPrecedence[2] = Amount;
}
CFontKerningPage::~CFontKerningPage() {
}
void CFontKerningPage::DoDataExchange(CDataExchange* pDX) {
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFontKerningPage)
DDX_Control(pDX, IDC_KerningTree, m_clcView);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CFontKerningPage, CToolTipPage)
//{{AFX_MSG_MAP(CFontKerningPage)
ON_WM_CONTEXTMENU()
ON_NOTIFY(LVN_KEYDOWN, IDC_KerningTree, OnKeydownKerningTree)
ON_NOTIFY(LVN_ENDLABELEDIT, IDC_KerningTree, OnEndlabeleditKerningTree)
ON_NOTIFY(LVN_COLUMNCLICK, IDC_KerningTree, OnColumnclickKerningTree)
//}}AFX_MSG_MAP
ON_COMMAND(ID_AddItem, OnAddItem)
ON_COMMAND(ID_DeleteItem, OnDeleteItem)
ON_COMMAND(ID_ChangeAmount, OnChangeAmount)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFontKerningPage message handlers
/******************************************************************************
CFontKerningPage::OnSetActive
Kerning only makes sense for variable pitch fonts, sio if this font has
changed, we will enable/disable, and change what we display accordingly.
******************************************************************************/
BOOL CFontKerningPage::OnSetActive() {
if (!CToolTipPage::OnSetActive())
return FALSE;
// IsVariableWidth is either 0 or 1, so == is safe, here
if (m_pcfi -> IsVariableWidth() == !!m_clcView.GetItemCount())
return TRUE; // Everything is copacetic
m_clcView.EnableWindow(m_pcfi -> IsVariableWidth());
if (m_clcView.GetItemCount())
m_clcView.DeleteAllItems();
else {
m_pcfi -> FillKern(m_clcView);
m_clcView.SortItems(Sort, (LPARAM) this);
}
return TRUE;
}
/******************************************************************************
CFontKerningPage::OnInitDialog
This member handles initialization of the dialog. In this case, we format
and fill in the kerning tree, if there is one to fill in.
******************************************************************************/
BOOL CFontKerningPage::OnInitDialog() {
CToolTipPage::OnInitDialog();
CString csWork;
csWork.LoadString(IDS_KernColumn0);
m_clcView.InsertColumn(0, csWork, LVCFMT_CENTER,
(3 * m_clcView.GetStringWidth(csWork)) >>
1, 0);
csWork.LoadString(IDS_KernColumn1);
m_clcView.InsertColumn(1, csWork, LVCFMT_CENTER,
m_clcView.GetStringWidth(csWork) << 1, 1);
csWork.LoadString(IDS_KernColumn2);
m_clcView.InsertColumn(2, csWork, LVCFMT_CENTER,
m_clcView.GetStringWidth(csWork) << 1, 2);
m_pcfi -> FillKern(m_clcView);
return TRUE;
}
/******************************************************************************
CFontKerningPage::OnContextMenu
This member function is called whenever the user right-clicks the mouse
anywhere within the dialog. If it turns out not to have been within the list
control, we ignore it. Otherwise, we put up an appropriate context menu.
******************************************************************************/
void CFontKerningPage::OnContextMenu(CWnd* pcwnd, CPoint cpt) {
if (pcwnd -> m_hWnd != m_clcView.m_hWnd) { // Clicked with in the list?
CToolTipPage::OnContextMenu(pcwnd, cpt);
return;
}
CPoint cptThis(cpt); // For hit test purposes, we will adjust this.
m_clcView.ScreenToClient(&cptThis);
cptThis.x = 5; // An arbitrary point sure to be within the label.
m_idSelected = m_clcView.HitTest(cptThis);
if (m_idSelected == -1) { // Nothing selected, allow the "Add" item
CMenu cmThis;
CString csWork;
cmThis.CreatePopupMenu();
csWork.LoadString(ID_AddItem);
cmThis.AppendMenu(MF_STRING | MF_ENABLED, ID_AddItem, csWork);
cmThis.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, cpt.x, cpt.y,
this);
return;
}
// We'll draw our own selection rectangle covering the entire item
CRect crItem;
m_clcView.GetItemRect(m_idSelected, crItem, LVIR_BOUNDS);
CDC *pcdc = m_clcView.GetDC();
pcdc -> InvertRect(crItem);
m_clcView.ReleaseDC(pcdc);
CMenu cmThis;
CString csWork;
cmThis.CreatePopupMenu();
csWork.LoadString(ID_ChangeAmount);
cmThis.AppendMenu(MF_STRING | MF_ENABLED, ID_ChangeAmount, csWork);
cmThis.AppendMenu(MF_SEPARATOR);
csWork.LoadString(ID_AddItem);
cmThis.AppendMenu(MF_STRING | MF_ENABLED, ID_AddItem, csWork);
csWork.LoadString(ID_DeleteItem);
cmThis.AppendMenu(MF_STRING | MF_ENABLED, ID_DeleteItem,
csWork);
cmThis.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, cpt.x, cpt.y,
this);
// Undo the selection rectangle
pcdc = m_clcView.GetDC();
pcdc -> InvertRect(crItem);
m_clcView.ReleaseDC(pcdc);
}
/******************************************************************************
CFontKerningPage::OnAddItem
This member will be called whenever the user asks to add an additional
kerning pair to the list.
******************************************************************************/
void CFontKerningPage::OnAddItem() {
CSafeMapWordToOb csmw2oFirst, csmw2oSecond;
CWordArray cwaPoints;
m_pcfi -> MapKerning(csmw2oFirst, csmw2oSecond, cwaPoints);
CAddKernPair cakp(csmw2oFirst, csmw2oSecond, cwaPoints, this);
if (cakp.DoModal() == IDOK) {
m_pcfi -> AddKern(cakp.First(), cakp.Second(), cakp.m_sAmount,
m_clcView);
}
}
/******************************************************************************
CFontKerningPage::OnDeleteItem
This will be called if we try to delete an item from the context menu.
******************************************************************************/
void CFontKerningPage::OnDeleteItem() {
if (m_idSelected < 0)
return; // Nothing to delete?
m_pcfi -> RemoveKern(m_clcView.GetItemData(m_idSelected));
m_clcView.DeleteItem(m_idSelected);
m_idSelected = -1;
}
/******************************************************************************
CFontKerningPage::OnChangeAmount
This is called when the user selects the menu item stating they wish to
change the kerning amount. It just needs to initiate a label edit.
******************************************************************************/
void CFontKerningPage::OnChangeAmount() {
if (m_idSelected < 0)
return;
m_clcView.EditLabel(m_idSelected);
m_idSelected = -1;
}
/******************************************************************************
CFontKerningPage::OnKeydownKerningTree
This is called most of the time when a key is pressed while the list control
has the keyboard focus. Unfortunately, the enter key is one of those we do
not get to see.
Currently, the F2, F10, and delete keys get special processing. F2 opens
an edit label on the current item, while F10 displays the context menu, and
the delete key deletes it.
******************************************************************************/
void CFontKerningPage::OnKeydownKerningTree(NMHDR* pnmh, LRESULT* plr) {
LV_KEYDOWN *plvkd = (LV_KEYDOWN *) pnmh;
*plr = 0;
m_idSelected = m_clcView.GetNextItem(-1, LVIS_FOCUSED | LVIS_SELECTED);
if (m_idSelected < 0) {
if (plvkd -> wVKey == VK_F10) // Do an add item, in this case.
OnAddItem();
return;
}
switch (plvkd -> wVKey) {
case VK_F2:
m_clcView.EditLabel(m_idSelected);
break;
case VK_DELETE:
OnDeleteItem();
break;
case VK_F10:
{
CRect crItem;
m_clcView.GetItemRect(m_idSelected, crItem, LVIR_LABEL);
m_clcView.ClientToScreen(crItem);
OnContextMenu(&m_clcView, crItem.CenterPoint());
break;
}
}
}
/******************************************************************************
CFontKerningPage::OnEndLabelEdit
This method gets called when the user finishes editing a kern amount, either
by canceling it or pressing the enter key.
******************************************************************************/
void CFontKerningPage::OnEndlabeleditKerningTree(NMHDR* pnmh, LRESULT* plr){
LV_DISPINFO *plvdi = (LV_DISPINFO*) pnmh;
*plr = 0; // Assume failure
if (!plvdi -> item.pszText) // Editing canceled?
return;
CString csNew(plvdi -> item.pszText);
csNew.TrimRight();
csNew.TrimLeft();
CString csTemp = (csNew[1] == _T('-')) ? csNew.Mid(1) : csNew;
if (csTemp.SpanIncluding("1234567890").GetLength() !=
csTemp.GetLength()) {
AfxMessageBox(IDS_InvalidNumberFormat);
return;
}
m_pcfi -> SetKernAmount(plvdi -> item.lParam, (WORD) atoi(csNew));
*plr = TRUE;
}
/******************************************************************************
CFontKerningPage::OnColumnclikKerningTree
This member gets called whn one of the sort headers is clicked. If it is
already the primary column, we revers the sort order fot that column.
Otherwise, we retain the current order, and make this column the primary
column, moving the other columns down in precedence.
******************************************************************************/
void CFontKerningPage::OnColumnclickKerningTree(NMHDR* pnmh, LRESULT* plr) {
NM_LISTVIEW *pnmlv = (NM_LISTVIEW*) pnmh;
*plr = 0;
if (m_uPrecedence[0] == (unsigned) pnmlv -> iSubItem)
m_ufDescending ^= (1 << pnmlv -> iSubItem);
else {
if (m_uPrecedence[2] == (unsigned) pnmlv -> iSubItem)
m_uPrecedence[2] = m_uPrecedence[1];
m_uPrecedence[1] = m_uPrecedence[0];
m_uPrecedence[0] = pnmlv -> iSubItem;
}
m_clcView.SortItems(Sort, (LPARAM) this);
}
/******************************************************************************
CFontScalingPage property page
******************************************************************************/
CFontScalingPage::CFontScalingPage() : CToolTipPage(CFontScalingPage::IDD) {
//{{AFX_DATA_INIT(CFontScalingPage)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
CFontScalingPage::~CFontScalingPage() {
}
void CFontScalingPage::DoDataExchange(CDataExchange* pDX) {
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFontScalingPage)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CFontScalingPage, CToolTipPage)
//{{AFX_MSG_MAP(CFontScalingPage)
ON_EN_KILLFOCUS(IDC_MasterDevice, OnKillfocusMasterDevice)
//}}AFX_MSG_MAP
ON_CONTROL_RANGE(BN_CLICKED, IDC_ScalePoints, IDC_ScaleDevice,
OnUnitChange)
ON_CONTROL_RANGE(EN_KILLFOCUS, IDC_MinimumScale, IDC_MaximumScale,
OnRangeChange)
ON_CONTROL_RANGE(BN_CLICKED, IDC_PortraitFont, IDC_LandscapeFont,
OnClickOrientation)
END_MESSAGE_MAP()
/******************************************************************************
CFontScalingPage::OnSetActive
This is called whenever the sheet becomes active. We enable or disable the
controls as appropriate. Then the controls are filled in.
******************************************************************************/
BOOL CFontScalingPage::OnSetActive() {
GetDlgItem(IDC_PortraitFont) -> EnableWindow(m_pcfi -> IsScalable());
GetDlgItem(IDC_LandscapeFont) -> EnableWindow(m_pcfi -> IsScalable());
GetDlgItem(IDC_MasterDevice) -> EnableWindow(m_pcfi -> IsScalable());
GetDlgItem(IDC_MasterFont) -> EnableWindow(m_pcfi -> IsScalable());
GetDlgItem(IDC_MinimumScale) -> EnableWindow(m_pcfi -> IsScalable());
GetDlgItem(IDC_MaximumScale) -> EnableWindow(m_pcfi -> IsScalable());
GetDlgItem(IDC_ScalePoints) -> EnableWindow(m_pcfi -> IsScalable());
GetDlgItem(IDC_ScaleDevice) -> EnableWindow(m_pcfi -> IsScalable());
// Orientation Flags
CheckDlgButton(IDC_PortraitFont, !(m_pcfi -> ScaleOrientation() & 2));
CheckDlgButton(IDC_LandscapeFont, !(m_pcfi -> ScaleOrientation() & 1));
// Device-to-font unit mapping stuff
SetDlgItemInt(IDC_MasterDevice, m_pcfi -> ScaleUnits());
SetDlgItemInt(IDC_MasterFont, m_pcfi -> ScaleUnits(FALSE));
// Scaling range controls
if (IsDlgButtonChecked(IDC_ScaleDevice)) { // Show Device Units
SetDlgItemInt(IDC_MinimumScale, m_pcfi -> ScaleLimit(FALSE));
SetDlgItemInt(IDC_MaximumScale, m_pcfi -> ScaleLimit());
}
else { // Show Points
SetDlgItemInt(IDC_MinimumScale,
(72 * m_pcfi -> ScaleLimit(FALSE)) / m_pcfi -> Resolution(FALSE));
SetDlgItemInt(IDC_MaximumScale,
(72 * m_pcfi -> ScaleLimit()) / m_pcfi -> Resolution(FALSE));
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CFontScalingPage message handlers
/******************************************************************************
CFontScalingPage::OnInitDialog
This performs the necessary one-time initialization of the dialog. Since
most of it is done in OnSetActive, only the one-time only things get done
here.
******************************************************************************/
BOOL CFontScalingPage::OnInitDialog() {
CToolTipPage::OnInitDialog();
CheckRadioButton(IDC_ScalePoints, IDC_ScaleDevice, IDC_ScaleDevice);
return TRUE;
}
/******************************************************************************
CFontScalingPage::OnUnitChange
This gets called when either device units or font units get clicked. Just
recalculate the affected fields, and proceed.
******************************************************************************/
void CFontScalingPage::OnUnitChange(unsigned uid) {
if (IsDlgButtonChecked(IDC_ScaleDevice)) { // Show Device Units
SetDlgItemInt(IDC_MinimumScale, m_pcfi -> ScaleLimit(FALSE));
SetDlgItemInt(IDC_MaximumScale, m_pcfi -> ScaleLimit());
}
else { // Show Points
SetDlgItemInt(IDC_MinimumScale,
(72 * m_pcfi -> ScaleLimit(FALSE)) / m_pcfi -> Resolution(FALSE));
SetDlgItemInt(IDC_MaximumScale,
(72 * m_pcfi -> ScaleLimit()) / m_pcfi -> Resolution(FALSE));
}
}
/******************************************************************************
CFontScalingPage::OnRangeChange
This is called when the focus leaves either of the scale controls. We
attempt to set the new value, and if it is refused, provide some feedback as
to why.
******************************************************************************/
void CFontScalingPage::OnRangeChange(unsigned uid) {
WORD wValue = GetDlgItemInt(uid, NULL, FALSE);
if (IsDlgButtonChecked(IDC_ScalePoints)) {
wValue *= m_pcfi -> Resolution(FALSE);
wValue /= 72;
}
switch (m_pcfi -> SetScaleLimit(uid - IDC_MinimumScale, wValue)) {
case CFontInfo::ScaleOK:
return;
case CFontInfo::Reversed:
AfxMessageBox(IDS_LimitsSwapped);
break;
case CFontInfo::NotWindowed:
AfxMessageBox(IDS_NotWindowed);
break;
}
SendDlgItemMessage(uid, EM_SETSEL, 0, -1);
GetDlgItem(uid) -> SetFocus();
}
/******************************************************************************
CFontScalingPage::OnClickOrientation
This will be called if either of the orientation buttons gets clicked. Just
collect the new flags, and pass them to the font. Pretty straightforward,
except that if interpreted as a bitfield, the bits are negative in sense.
******************************************************************************/
void CFontScalingPage::OnClickOrientation(unsigned uid) {
BYTE bFlags = IsDlgButtonChecked(IDC_PortraitFont) ? 0 : 2;
bFlags |= IsDlgButtonChecked(IDC_LandscapeFont) ? 0 : 1;
m_pcfi -> SetScaleOrientation(bFlags);
}
/******************************************************************************
CFontScalingPage::OnKillfocusMasterDevice
This is called when the edit control for the device scaling units loses
focus. It passes the new values to the font, which validates them and
reports back any problems. If there are any, we provide the feedback here.
******************************************************************************/
void CFontScalingPage::OnKillfocusMasterDevice() {
WORD wNew = GetDlgItemInt(IDC_MasterDevice, NULL, FALSE);
switch (m_pcfi -> SetDeviceEmHeight(wNew)) {
case CFontInfo::ScaleOK:
return;
case CFontInfo::NotWindowed:
AfxMessageBox(IDS_NotWindowed);
break;
case CFontInfo::Reversed:
AfxMessageBox(IDS_ScaleReversed);
break;
}
SendDlgItemMessage(IDC_MasterDevice, EM_SETSEL, 0, -1);
GetDlgItem(IDC_MasterDevice) -> SetFocus();
}
/******************************************************************************
CFontDifferencePage property page class
This page is rather complex- it allows specification of changed values for
italic, bold, or both simulations on a font.
******************************************************************************/
CFontDifferencePage::CFontDifferencePage() :
CToolTipPage(CFontDifferencePage::IDD) {
//{{AFX_DATA_INIT(CFontDifferencePage)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_pcfdBold = m_pcfdItalic = m_pcfdBoth = NULL;
}
CFontDifferencePage::~CFontDifferencePage() {
// Discard any cached but unused data
if (m_pcfdBold && !m_pcfi -> Diff(CFontInfo::BoldDiff))
delete m_pcfdBold;
if (m_pcfdItalic && !m_pcfi -> Diff(CFontInfo::ItalicDiff))
delete m_pcfdItalic;
if (m_pcfdBoth && m_pcfi -> Diff(CFontInfo::BothDiff))
delete m_pcfdBoth;
}
void CFontDifferencePage::DoDataExchange(CDataExchange* pDX) {
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFontDifferencePage)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CFontDifferencePage, CToolTipPage)
//{{AFX_MSG_MAP(CFontDifferencePage)
//}}AFX_MSG_MAP
ON_CONTROL_RANGE(BN_CLICKED, IDC_EnableItalicSim, IDC_EnableBISim,
OnEnableAnySim)
ON_CONTROL_RANGE(EN_KILLFOCUS, IDC_ItalicWeight, IDC_BoldItalicSlant,
OnKillFocusAnyNumber)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFontDifferencePage message handlers
/******************************************************************************
CFontDifferencePage::OnInitDialog
This initializes the sheet's controls based upon the current font structure.
******************************************************************************/
BOOL CFontDifferencePage::OnInitDialog() {
CToolTipPage::OnInitDialog();
// Enable the check boxes based upon what the font has, then let the UI
// update procedures do the rest of the work for us
for (unsigned u = CFontInfo::ItalicDiff; u <= CFontInfo::BothDiff; u++) {
CheckDlgButton(IDC_EnableItalicSim + u, !!m_pcfi -> Diff(u));
OnEnableAnySim(IDC_EnableItalicSim + u);
}
return TRUE;
}
static WORD awBaseDiff[] = {IDC_ItalicWeight, IDC_BoldWeight, IDC_BIWeight};
/******************************************************************************
CFontDifferencePage::OnEnableAnySim
Called when any simulation is enabled or disabled. Updates the font and UI
appropriately. We decode which simulation it is, and init any values we
ought to.
******************************************************************************/
void CFontDifferencePage::OnEnableAnySim(unsigned uid) {
BOOL bEnable = IsDlgButtonChecked(uid);
WORD wDiff = uid - IDC_EnableItalicSim;
CFontDifference*& pcfdTarget = wDiff ? wDiff ==CFontInfo::BothDiff ?
m_pcfdBoth : m_pcfdBold : m_pcfdItalic;
m_pcfi -> EnableSim(wDiff, bEnable, pcfdTarget);
for (unsigned u = CFontDifference::Weight;
u <= CFontDifference::Angle;
u++) {
if (!GetDlgItem(awBaseDiff[wDiff] + u))
break;
GetDlgItem(awBaseDiff[wDiff] + u) -> EnableWindow(bEnable);
if (bEnable)
SetDlgItemInt(awBaseDiff[wDiff] + u, pcfdTarget -> Metric(u));
}
}
/******************************************************************************
CFontDifferencePage::OnKillFocusAnyNumber
This is called whenever any of the numeric values in the sheet loses focus.
We just pull it out of the control and shoot it off to the font.
******************************************************************************/
void CFontDifferencePage::OnKillFocusAnyNumber(unsigned uid) {
WORD wDiff = (uid > IDC_BAverage) + (uid > IDC_ItalicSlant);
WORD wItem = uid - awBaseDiff[wDiff];
switch (m_pcfi -> Diff(wDiff) ->
SetMetric(wItem, GetDlgItemInt(uid, NULL, FALSE))) {
case CFontDifference::OK:
return; // It worked!
case CFontDifference::Reversed:
AfxMessageBox(IDS_WidthReversed);
break;
case CFontDifference::TooBig:
AfxMessageBox(wItem ? IDS_Overweight : IDS_AngleTooBig);
}
GetDlgItem(uid) -> SetFocus();
SendDlgItemMessage(uid, EM_SETSEL, 0, -1);
}
/******************************************************************************
CFontCommandPage property page class
One of the simpler classes- the sheet has two edit controls and a set of
check boxes, and the check boxes can be handled by a single routine.
******************************************************************************/
CFontCommandPage::CFontCommandPage() : CToolTipPage(CFontCommandPage::IDD) {
//{{AFX_DATA_INIT(CFontCommandPage)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
CFontCommandPage::~CFontCommandPage() {
}
void CFontCommandPage::DoDataExchange(CDataExchange* pDX) {
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFontCommandPage)
DDX_Control(pDX, IDC_FontUnselector, m_ceDeselect);
DDX_Control(pDX, IDC_FontSelector, m_ceSelect);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CFontCommandPage, CToolTipPage)
//{{AFX_MSG_MAP(CFontCommandPage)
ON_EN_KILLFOCUS(IDC_FontSelector, OnKillfocusFontSelector)
ON_EN_KILLFOCUS(IDC_FontUnselector, OnKillfocusFontUnselector)
//}}AFX_MSG_MAP
ON_CONTROL_RANGE(BN_CLICKED, IDC_ItalicSim, IDC_Backspace, OnFlagChange)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFontCommandPage message handlers
/******************************************************************************
CFFontCommandPage::OnInitDialog
This initializes the dialog. It does so by letting the base class do its
thing, after which we copy the invocation strings into the controls, and set
the check boxes to reflect the other flags.
******************************************************************************/
BOOL CFontCommandPage::OnInitDialog() {
CToolTipPage::OnInitDialog();
CString csCommand;
m_pcfi -> Selector().GetInvocation(csCommand);
m_ceSelect.SetWindowText(csCommand);
m_pcfi -> Selector(FALSE).GetInvocation(csCommand);
m_ceDeselect.SetWindowText(csCommand);
// Now just set up theflags, and we're done!
for (WORD w = CFontInfo::ItalicSim; w <= CFontInfo::UseBKSP; w++)
CheckDlgButton(IDC_ItalicSim + w, m_pcfi -> SimFlag(w));
return TRUE;
}
/******************************************************************************
CFontCommandPage::OnKillFocusFontSelector
This will be called whenever the control with the selector string loses
focus. If the contents have changed, the necessary updates will take place.
******************************************************************************/
void CFontCommandPage::OnKillfocusFontSelector() {
if (!m_ceSelect.GetModify())
return; // Nothing to deal with!
// Retrieve the current text
CString csCommand;
m_ceSelect.GetWindowText(csCommand);
// Pass it on to the underlying font info.
m_pcfi -> Selector().SetInvocation(csCommand);
// Update the control to refelect the new setting
m_pcfi -> Selector().GetInvocation(csCommand);
m_ceSelect.SetWindowText(csCommand);
m_ceSelect.SetModify(FALSE);
}
/******************************************************************************
CFontCommandPage::OnKillFocusFontUnselector
This will be called whenever the control with the unselector string loses
focus. If the contents have changed, the necessary updates will take place.
******************************************************************************/
void CFontCommandPage::OnKillfocusFontUnselector() {
if (!m_ceDeselect.GetModify())
return; // Nothing to deal with!
// Retrieve the current text
CString csCommand;
m_ceDeselect.GetWindowText(csCommand);
// Pass it on to the underlying font info.
m_pcfi -> Selector(FALSE).SetInvocation(csCommand);
// Update the control to reflect the new setting
m_pcfi -> Selector(FALSE).GetInvocation(csCommand);
m_ceDeselect.SetWindowText(csCommand);
m_ceDeselect.SetModify(FALSE);
}
/******************************************************************************
CFontCommandPage::OnFlagChange
This member function handles the clicking of any of the check boxes used for
flags. The control IDs are purposely in flag order, so a simple XOR of the
appropriate bit is all of the action that's required.
******************************************************************************/
void CFontCommandPage::OnFlagChange(unsigned uid) {
m_pcfi -> ToggleSimFlag(uid - IDC_ItalicSim);
}
/******************************************************************************
CFontGeneralPage2 property page class
******************************************************************************/
CFontGeneralPage2::CFontGeneralPage2() : CToolTipPage(CFontGeneralPage2::IDD) {
//{{AFX_DATA_INIT(CFontGeneralPage2)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
CFontGeneralPage2::~CFontGeneralPage2() {
}
void CFontGeneralPage2::DoDataExchange(CDataExchange* pDX) {
CPropertyPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFontGeneralPage2)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CFontGeneralPage2, CToolTipPage)
//{{AFX_MSG_MAP(CFontGeneralPage2)
ON_EN_KILLFOCUS(IDC_CenteringAdjustment, OnKillfocusCenteringAdjustment)
ON_CBN_SELCHANGE(IDC_FontLocation, OnSelchangeFontLocation)
ON_CBN_SELCHANGE(IDC_FontTechnology, OnSelchangeFontTechnology)
ON_EN_KILLFOCUS(IDC_PrivateData, OnKillfocusPrivateData)
//}}AFX_MSG_MAP
ON_CONTROL_RANGE(EN_KILLFOCUS, IDC_PreAdjustY, IDC_PostAdjustY,
OnKillfocusBaselineAdjustment)
ON_CONTROL_RANGE(EN_KILLFOCUS, IDC_HorizontalResolution,
IDC_VerticalResolution, OnKillfocusResolution)
END_MESSAGE_MAP()
/******************************************************************************
CFontGeneralPage::OnSetActive
This handles the page activation. The only real work is that just in case
the scalability has changed, the enabling of the technology control may need
to be changed.
******************************************************************************/
BOOL CFontGeneralPage2::OnSetActive() {
if (!CToolTipPage::OnSetActive())
return FALSE;
if (m_pcfi -> IsScalable())
SendDlgItemMessage(IDC_FontTechnology, CB_SETCURSEL,
m_pcfi -> Technology(), 0);
GetDlgItem(IDC_FontTechnology) -> EnableWindow(m_pcfi -> IsScalable());
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CFontGeneralPage2 message handlers
/******************************************************************************
CFontGeneralPage::OnInitDialog
This handler the page initialization. The controls are set up to reflect the
current font settings.
******************************************************************************/
BOOL CFontGeneralPage2::OnInitDialog() {
CToolTipPage::OnInitDialog();
SendDlgItemMessage(IDC_FontLocation, CB_SETCURSEL, m_pcfi -> Location(),
0);
if (m_pcfi -> IsScalable())
SendDlgItemMessage(IDC_FontTechnology, CB_SETCURSEL,
m_pcfi -> Technology(), 0);
else
GetDlgItem(IDC_FontTechnology) -> EnableWindow(FALSE);
SetDlgItemInt(IDC_HorizontalResolution, m_pcfi -> Resolution(), FALSE);
SetDlgItemInt(IDC_VerticalResolution, m_pcfi -> Resolution(FALSE), FALSE);
SetDlgItemInt(IDC_PreAdjustY, m_pcfi -> BaselineAdjustment());
SetDlgItemInt(IDC_PostAdjustY, m_pcfi -> BaselineAdjustment(FALSE));
SetDlgItemInt(IDC_CenteringAdjustment, m_pcfi -> CenterAdjustment());
SetDlgItemInt(IDC_PrivateData, m_pcfi -> PrivateData());
SetDlgItemText(IDC_GTTDescription, m_pcfi -> GTTDescription());
return TRUE;
}
/******************************************************************************
CFontGeneralPage Edit control focus loss handlers
These all work basically the same way. If the control's contents have
changed, the contents are translated, passed to the underlying font, and then
updated with the value the font has stored- this let's the font object do any
validation, etc., it deems necessary.
******************************************************************************/
void CFontGeneralPage2::OnKillfocusCenteringAdjustment() {
if (!SendDlgItemMessage(IDC_CenteringAdjustment, EM_GETMODIFY, 0, 0))
return;
m_pcfi -> SetCenterAdjustment(GetDlgItemInt(IDC_CenteringAdjustment));
SetDlgItemInt(IDC_CenteringAdjustment, m_pcfi -> CenterAdjustment());
}
/******************************************************************************
CFontGeneralPage2::OnSelchangeFontLocation
This handles changes in the selection which specifies the font location
(firmware / cartridge / downloadable). Thye get passed on rather directly
to the font.
******************************************************************************/
void CFontGeneralPage2::OnSelchangeFontLocation() {
int id = SendDlgItemMessage(IDC_FontLocation, CB_GETCURSEL, 0, 0);
if (id < 0)
return;
m_pcfi -> SetLocation(id);
}
/******************************************************************************
CFontGeneralPage2::OnSelchangeFontTechnology
This handles changes in the selection which specifies the font technology
This get handled directly by the font
******************************************************************************/
void CFontGeneralPage2::OnSelchangeFontTechnology() {
int id = SendDlgItemMessage(IDC_FontTechnology, CB_GETCURSEL, 0, 0);
if (id < 0)
return;
m_pcfi -> SetTechnology(id);
}
/******************************************************************************
CFontGeneralPAge2::OnKillfocusPrivateData
Reads the contents of the edit control out, and passes them back to the font.
******************************************************************************/
void CFontGeneralPage2::OnKillfocusPrivateData() {
short s = (short) GetDlgItemInt(IDC_PrivateData);
m_pcfi -> SetPrivateData(s);
SetDlgItemInt(IDC_PrivateData, m_pcfi -> PrivateData());
}
/******************************************************************************
CFontGeneralPAge2::OnKillfocusBaselineAdjustment
This is called when the focus leaves either of the baseline adjustment boxes.
Just read the number out, send it off to the font, then refresh the box with
the current setting.
******************************************************************************/
void CFontGeneralPage2::OnKillfocusBaselineAdjustment(unsigned uid) {
short sNew = GetDlgItemInt(uid);
BOOL bPre = uid == IDC_PreAdjustY;
m_pcfi -> SetBaselineAdjustment(bPre, sNew);
SetDlgItemInt(uid, m_pcfi -> BaselineAdjustment(bPre));
}
/******************************************************************************
CFontGeneralPAge2::OnKillfocusResolution
This is called when the focus leaves either of the resolution edit controls.
Just read the number out, send it off to the font, then refresh the box with
the current setting.
******************************************************************************/
void CFontGeneralPage2::OnKillfocusResolution(unsigned uid) {
WORD wNew = GetDlgItemInt(uid, NULL, FALSE);
BOOL bX = uid == IDC_HorizontalResolution;
m_pcfi -> SetResolution(bX, wNew);
SetDlgItemInt(uid, m_pcfi -> Resolution(bX), FALSE);
}