2708 lines
90 KiB
C++
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);
|
|
}
|