457 lines
10 KiB
C++
457 lines
10 KiB
C++
//// Style - simple character styles for formatted text
|
|
//
|
|
// Provides a simple style selection mechanism for demostrating
|
|
// formatted text.
|
|
|
|
|
|
#include "precomp.hxx"
|
|
#include "global.h"
|
|
#include <tchar.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
void SetLogFont(
|
|
PLOGFONTA plf,
|
|
int iHeight,
|
|
int iWeight,
|
|
int iItalic,
|
|
int iUnderline,
|
|
char *pcFaceName) {
|
|
|
|
memset(plf, 0, sizeof(LOGFONTA));
|
|
plf->lfCharSet = DEFAULT_CHARSET;
|
|
plf->lfHeight = iHeight;
|
|
plf->lfWeight = iWeight;
|
|
plf->lfItalic = (BYTE) iItalic;
|
|
plf->lfUnderline = (BYTE) iUnderline;
|
|
lstrcpy(plf->lfFaceName, pcFaceName);
|
|
plf->lfOutPrecision = OUT_STROKE_PRECIS;
|
|
plf->lfClipPrecision = CLIP_STROKE_PRECIS;
|
|
plf->lfQuality = DRAFT_QUALITY;
|
|
plf->lfPitchAndFamily = VARIABLE_PITCH;
|
|
plf->lfEscapement = 0;
|
|
plf->lfOrientation = 0;
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
void FreeStyle(int iStyle) {
|
|
|
|
/*
|
|
if (g_style[iStyle].hf) {
|
|
DeleteObject(g_style[iStyle].hf);
|
|
}
|
|
|
|
if (g_style[iStyle].sc) {
|
|
ScriptFreeCache(&g_style[iStyle].sc);
|
|
}
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SetStyle(
|
|
int iStyle,
|
|
int iHeight,
|
|
int iWeight,
|
|
int iItalic,
|
|
int iUnderline,
|
|
int iStrikeout,
|
|
TCHAR *pcFaceName) {
|
|
|
|
LOGFONTA lf;
|
|
|
|
FreeStyle(iStyle);
|
|
|
|
//SetLogFont(&lf, iHeight, iWeight, iItalic, iUnderline, pcFaceName);
|
|
//g_style[iStyle].hf = CreateFontIndirect(&lf);
|
|
//g_style[iStyle].sc = NULL;
|
|
|
|
g_style[iStyle].emSize = REAL(iHeight);
|
|
for (UINT i=0; i<_tcslen(pcFaceName); i++)
|
|
{
|
|
g_style[iStyle].faceName[i] = pcFaceName[i];
|
|
}
|
|
g_style[iStyle].faceName[_tcslen(pcFaceName)] = 0;
|
|
g_style[iStyle].style =
|
|
(iWeight >= 700 ? FontStyleBold : 0)
|
|
+ (iItalic ? FontStyleItalic : 0)
|
|
+ (iUnderline ? FontStyleUnderline : 0)
|
|
+ (iStrikeout ? FontStyleStrikeout : 0);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void InitStyles() {
|
|
|
|
memset(g_style, 0, sizeof(g_style));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FreeStyles() {
|
|
int i;
|
|
for (i=0; i<5; i++) {
|
|
FreeStyle(i);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//// StyleCheckRange - dir use in ASSERTs
|
|
//
|
|
// Returns TRUE if style length matches text length
|
|
|
|
|
|
BOOL StyleCheckRange() {
|
|
|
|
int iFormatPos;
|
|
RUN *pFormatRider;
|
|
|
|
// Check that style length is same as text length
|
|
|
|
pFormatRider = g_pFirstFormatRun;
|
|
iFormatPos = 0;
|
|
while (pFormatRider != NULL) {
|
|
|
|
iFormatPos += pFormatRider->iLen;
|
|
pFormatRider = pFormatRider->pNext;
|
|
}
|
|
|
|
return iFormatPos == g_iTextLen;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///// Style range manipulation
|
|
//
|
|
// StyleDeleteRange
|
|
// StyleExtendRange
|
|
// StyleSetRange
|
|
//
|
|
// The style list is a linked list of RUNs (see global.h) that
|
|
// covers the entire text buffer.
|
|
//
|
|
// Each run has a length, and a style number (an index to g_Style[])
|
|
// (The analysis field in the run is not used by the style list.)
|
|
//
|
|
// StyleDeleteRange and StyleExtendRange are called as part of text
|
|
// insertion/deletion to maintain the style list.
|
|
//
|
|
// StyleSetRange is called to change the style of the current selection
|
|
// when the user clicks on one the of the numbered style buttons.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// StyleDeleteRange - delete range of style information
|
|
//
|
|
//
|
|
|
|
|
|
void StyleDeleteRange(
|
|
int iDelPos,
|
|
int iDelLen) {
|
|
|
|
|
|
int iFormatPos;
|
|
RUN *pFormatRider;
|
|
RUN *pPrevRun;
|
|
RUN *pDelRun; // Run to be deleted
|
|
|
|
|
|
if (iDelLen <= 0) return;
|
|
|
|
|
|
// Find first run affected by the deletion
|
|
|
|
iFormatPos = 0;
|
|
pFormatRider = g_pFirstFormatRun;
|
|
pPrevRun = NULL;
|
|
while (iFormatPos + pFormatRider->iLen <= iDelPos) {
|
|
iFormatPos += pFormatRider->iLen;
|
|
pPrevRun = pFormatRider;
|
|
pFormatRider = pFormatRider->pNext;
|
|
ASSERT(pFormatRider);
|
|
}
|
|
|
|
|
|
|
|
// Delete from end of first run
|
|
|
|
if (iDelPos + iDelLen > iFormatPos + pFormatRider->iLen) {
|
|
|
|
// Delete all the way from iDelPos to the end of the first affected run
|
|
|
|
iDelLen = iDelPos + iDelLen - (iFormatPos + pFormatRider->iLen); // Amount that will remain to be deleted
|
|
pFormatRider->iLen = iDelPos - iFormatPos;
|
|
|
|
} else {
|
|
|
|
// Deletion is entirely in the first affected run
|
|
|
|
pFormatRider->iLen -= iDelLen;
|
|
iDelLen = 0;
|
|
}
|
|
|
|
|
|
// First affected run now contains no range to be deleted
|
|
// If it's empty, remove it, otherwise step over it
|
|
|
|
if (pFormatRider->iLen == 0) {
|
|
|
|
// Remove redundant run
|
|
|
|
if (pFormatRider->pNext) {
|
|
|
|
// Replace this run by the next one
|
|
|
|
pDelRun = pFormatRider->pNext;
|
|
*pFormatRider = *pDelRun; // Copy content of next run over this one
|
|
delete pDelRun;
|
|
|
|
} else {
|
|
|
|
// No runs following this one
|
|
|
|
if (pPrevRun) {
|
|
|
|
ASSERT(iDelLen == 0);
|
|
delete pFormatRider;
|
|
pPrevRun->pNext = NULL;
|
|
|
|
} else {
|
|
|
|
// No runs left at all
|
|
|
|
ASSERT(iDelLen == 0);
|
|
delete pFormatRider;
|
|
g_pFirstFormatRun = NULL;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
// Current run now contains no text to be deleted, so advance to next run
|
|
|
|
iFormatPos += pFormatRider->iLen;
|
|
pPrevRun = pFormatRider;
|
|
pFormatRider = pFormatRider->pNext;
|
|
}
|
|
|
|
|
|
// Delete from start of any remaining runs
|
|
|
|
while (iDelLen > 0) {
|
|
|
|
if (pFormatRider->iLen <= iDelLen) {
|
|
|
|
// This entire run must go
|
|
|
|
ASSERT(pFormatRider->pNext);
|
|
iDelLen -= pFormatRider->iLen;
|
|
pDelRun = pFormatRider->pNext;
|
|
*pFormatRider = *pDelRun;
|
|
delete pDelRun;
|
|
|
|
} else {
|
|
|
|
// Last run is deleted in part only
|
|
|
|
pFormatRider->iLen -= iDelLen;
|
|
iDelLen = 0;
|
|
}
|
|
}
|
|
|
|
|
|
// Check whether current run (which immediately follows deletion) can
|
|
// now be collapsed into the previous run
|
|
|
|
if (pPrevRun && pFormatRider && pPrevRun->iStyle == pFormatRider->iStyle) {
|
|
|
|
pPrevRun->iLen += pFormatRider->iLen;
|
|
pPrevRun->pNext = pFormatRider->pNext;
|
|
delete pFormatRider;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// StyleExtendRange - Extend style immediately preceeding iPos by iLen characters
|
|
//
|
|
//
|
|
|
|
|
|
void StyleExtendRange(
|
|
int iExtPos,
|
|
int iExtLen) {
|
|
|
|
int iFormatPos;
|
|
RUN *pFormatRider;
|
|
|
|
const SCRIPT_ANALYSIS nullAnalysis = {0};
|
|
|
|
|
|
if (g_pFirstFormatRun == NULL) {
|
|
|
|
// Starting from no text at all
|
|
|
|
ASSERT(iExtPos == 0);
|
|
|
|
g_pFirstFormatRun = new RUN;
|
|
g_pFirstFormatRun->iLen = iExtLen;
|
|
g_pFirstFormatRun->iStyle = 1;
|
|
g_pFirstFormatRun->pNext = NULL;
|
|
g_pFirstFormatRun->analysis = nullAnalysis;
|
|
|
|
} else {
|
|
|
|
// Find run containing character immediately prior to iExtPos
|
|
|
|
iFormatPos = 0;
|
|
pFormatRider = g_pFirstFormatRun;
|
|
|
|
while (iFormatPos + pFormatRider->iLen < iExtPos) {
|
|
iFormatPos += pFormatRider->iLen;
|
|
pFormatRider = pFormatRider->pNext;
|
|
}
|
|
|
|
pFormatRider->iLen += iExtLen;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//// StyleSetRange - Change style for a given range
|
|
//
|
|
//
|
|
|
|
|
|
void StyleSetRange(
|
|
int iSetStyle,
|
|
int iSetPos,
|
|
int iSetLen) {
|
|
|
|
int iFormatPos;
|
|
RUN *pFormatRider;
|
|
RUN *pNewRun;
|
|
|
|
|
|
if (iSetLen <= 0) return;
|
|
|
|
|
|
// Remove existing style for the range
|
|
|
|
StyleDeleteRange(iSetPos, iSetLen);
|
|
|
|
|
|
if (g_pFirstFormatRun == NULL) {
|
|
|
|
// Replace style on entire text
|
|
|
|
g_pFirstFormatRun = new RUN;
|
|
g_pFirstFormatRun->pNext = NULL;
|
|
g_pFirstFormatRun->iLen = iSetLen;
|
|
g_pFirstFormatRun->iStyle = iSetStyle;
|
|
|
|
} else {
|
|
|
|
// Find first run affected by the change
|
|
|
|
iFormatPos = 0;
|
|
pFormatRider = g_pFirstFormatRun;
|
|
while (iFormatPos + pFormatRider->iLen < iSetPos) {
|
|
iFormatPos += pFormatRider->iLen;
|
|
pFormatRider = pFormatRider->pNext;
|
|
ASSERT(pFormatRider);
|
|
}
|
|
|
|
|
|
// New style starts after beginning of this run or at beginning of next run
|
|
|
|
|
|
if (pFormatRider->iStyle == iSetStyle) {
|
|
|
|
// Already the same style - just increase length
|
|
|
|
pFormatRider->iLen += iSetLen;
|
|
|
|
} else {
|
|
|
|
if (iFormatPos + pFormatRider->iLen > iSetPos) {
|
|
|
|
// New style is within this run
|
|
// Split this run around the new run
|
|
|
|
pNewRun = new RUN; // Create second part of existing run
|
|
*pNewRun = *pFormatRider;
|
|
pNewRun->iLen -= iSetPos - iFormatPos;
|
|
pFormatRider->iLen = iSetPos - iFormatPos;
|
|
pFormatRider->pNext = pNewRun;
|
|
|
|
pNewRun = new RUN; // Create inserted run
|
|
*pNewRun = *pFormatRider;
|
|
pNewRun->iLen = iSetLen;
|
|
pNewRun->iStyle = iSetStyle;
|
|
pFormatRider->pNext = pNewRun;
|
|
|
|
} else {
|
|
|
|
// New style is between this run and the next run
|
|
|
|
if ( pFormatRider->pNext
|
|
&& pFormatRider->pNext->iStyle == iSetStyle) {
|
|
|
|
// New style is same as adjacent following run
|
|
|
|
pFormatRider->pNext->iLen += iSetLen;
|
|
|
|
} else {
|
|
|
|
// Create new run between current run and next run
|
|
|
|
pNewRun = new RUN;
|
|
*pNewRun = *pFormatRider;
|
|
pNewRun->iStyle = iSetStyle;
|
|
pNewRun->iLen = iSetLen;
|
|
pFormatRider->pNext = pNewRun;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|