📄 clayoutmgr_new.cpp
字号:
// $Id: CLayoutMgr_New.cpp,v 1.24 2004/08/18 14:03:05 genta Exp $
/*! @file
@brief テキストのレイアウト情報管理
@author Norio Nakatani
$Revision: 1.24 $
*/
/*
Copyright (C) 1998-2001, Norio Nakatani
Copyright (C) 2001, MIK
Copyright (C) 2002, MIK
Copyright (C) 2004, Moca
This source code is designed for sakura editor.
Please contact the copyright holder to use this code for other purpose.
*/
#include <mbstring.h>
#include "CLayoutMgr.h"
#include "charcode.h"
#include "etc_uty.h"
#include "debug.h"
#include <commctrl.h>
#include "CRunningTimer.h"
#include "CLayout.h"/// 2002/2/10 aroka
#include "CDocLine.h"/// 2002/2/10 aroka
#include "CDocLineMgr.h"// 2002/2/10 aroka
#include "CMemory.h"/// 2002/2/10 aroka
#include "CMemoryIterator.h"
#include "CEditDoc.h" /// 2003/07/20 genta
//レイアウト中の禁則タイプ //@@@ 2002.04.20 MIK
#define KINSOKU_TYPE_NONE 0 //なし
#define KINSOKU_TYPE_WORDWRAP 1 //ワードラップ中
#define KINSOKU_TYPE_KINSOKU_HEAD 2 //行頭禁則中
#define KINSOKU_TYPE_KINSOKU_TAIL 3 //行末禁則中
#define KINSOKU_TYPE_KINSOKU_KUTO 4 //句読点ぶら下げ中
/*!
現在の折り返し文字数に合わせて全データのレイアウト情報を再生成します
@date 2004.04.03 Moca TABが使われると折り返し位置がずれるのを防ぐため,
nPosXがインデントを含む幅を保持するように変更.nMaxLineSizeは
固定値となったが,既存コードの置き換えは避けて最初に値を代入するようにした.
*/
void CLayoutMgr::DoLayout(
HWND hwndProgress,
BOOL bDispSSTRING, /* シングルクォーテーション文字列を表示する */
BOOL bDispWSTRING /* ダブルクォーテーション文字列を表示する */
)
{
MY_RUNNINGTIMER( cRunningTimer, "CLayoutMgr::DoLayout" );
int nLineNum;
int nLineLen;
CDocLine* pCDocLine;
const char* pLine;
int nBgn;
//! メモリ上の位置(offset)
int nPos;
/* 表示上のX位置
2004.03.28 Moca nPosXはインデント幅を含むように変更(TAB位置調整のため)
*/
int nPosX;
int nCharChars;
int nCharChars2;
int nCOMMENTMODE;
int nCOMMENTMODE_Prev;
int nCOMMENTEND;
int nWordBgn;
int nWordLen;
int nAllLineNum;
bool bKinsokuFlag; //@@@ 2002.04.08 MIK
int nCharChars3; //@@@ 2002.04.17 MIK
int nKinsokuType; //@@@ 2002.04.20 MIK
int nIndent; // インデント幅
CLayout* pLayoutCalculated; // インデント幅計算済みのCLayout.
int nMaxLineSize;
// 2002/03/13 novice
nCOMMENTMODE = COLORIDX_TEXT;
nCOMMENTMODE_Prev = COLORIDX_TEXT;
if( NULL != hwndProgress ){
::PostMessage( hwndProgress, PBM_SETRANGE, 0, MAKELPARAM( 0, 100 ) );
::PostMessage( hwndProgress, PBM_SETPOS, 0, 0 );
/* 処理中のユーザー操作を可能にする */
if( !::BlockingHook( NULL ) ){
return;
}
}
Empty();
Init();
nLineNum = 0;
// Nov. 16, 2002 genta
// 折り返し幅 <= TAB幅のとき無限ループするのを避けるため,
// TABが折り返し幅以上の時はTAB=4としてしまう
// 折り返し幅の最小値=10なのでこの値は問題ない
if( m_nTabSpace >= m_nMaxLineSize ){
m_nTabSpace = 4;
}
// pLine = m_pcDocLineMgr->GetFirstLinrStr( &nLineLen );
pCDocLine = m_pcDocLineMgr->GetDocLineTop(); // 2002/2/10 aroka CDocLineMgr変更
// 2002/03/13 novice
if( nCOMMENTMODE_Prev == COLORIDX_COMMENT ){ /* 行コメントである */
nCOMMENTMODE_Prev = COLORIDX_TEXT;
}
nCOMMENTMODE = nCOMMENTMODE_Prev;
nCOMMENTEND = 0;
nAllLineNum = m_pcDocLineMgr->GetLineCount();
/*
2004.03.28 Moca TAB計算を正しくするためにインデントを幅で調整することはしない
nMaxLineSizeは変更しないので,ここでm_nMaxLineSizeを設定する.
*/
nMaxLineSize = m_nMaxLineSize;
while( NULL != pCDocLine ){
pLine = pCDocLine->m_pLine->GetPtr( &nLineLen );
nPosX = 0;
nCharChars = 0;
nBgn = 0;
nPos = 0;
nWordBgn = 0;
nWordLen = 0;
nKinsokuType = KINSOKU_TYPE_NONE; //@@@ 2002.04.20 MIK
int nEol = pCDocLine->m_cEol.GetLen();
int nEol_1 = nEol - 1;
if( 0 > nEol_1 ){
nEol_1 = 0;
}
nIndent = 0; // インデント幅
pLayoutCalculated = NULL; // インデント幅計算済みのCLayout.
while( nPos < nLineLen - nEol_1 ){
// インデント幅の計算コストを下げるための方策
if ( m_pLayoutBot &&
m_pLayoutBot != pLayoutCalculated &&
nBgn ){
// 計算
// Oct, 1, 2002 genta Indentサイズを取得するように変更
nIndent = (this->*getIndentOffset)( m_pLayoutBot );
// 2004.03.28 Moca nMaxLineSizeを引く方法だと、タブ幅の計算が合わないので、nPosXの初期値をnIndentにする
// nMaxLineSize = m_nMaxLineSize - nIndent;
// 計算済み
pLayoutCalculated = m_pLayoutBot;
}
nCharChars = CMemory::MemCharNext( pLine, nLineLen, &pLine[nPos] ) - &pLine[nPos];
if( 0 == nCharChars ){
nCharChars = 1;
}
SEARCH_START:;
//禁則処理中ならスキップする @@@ 2002.04.20 MIK
if( KINSOKU_TYPE_NONE != nKinsokuType )
{
//禁則処理の最後尾に達したら禁則処理中を解除する
if( nPos >= nWordBgn + nWordLen )
{
if( nKinsokuType == KINSOKU_TYPE_KINSOKU_KUTO
&& nPos == nWordBgn + nWordLen )
{
if( ! (m_bKinsokuRet && (nPos == nLineLen - nEol) && nEol ) ) //改行文字をぶら下げる //@@@ 2002.04.14 MIK
{
AddLineBottom( CreateLayout(pCDocLine, nLineNum, nBgn, nPos - nBgn, nCOMMENTMODE_Prev, nIndent) );
m_nLineTypeBot = nCOMMENTMODE;
nCOMMENTMODE_Prev = nCOMMENTMODE;
nBgn = nPos;
// 2004.03.28 Moca nPosXはインデント幅を含むように変更(TAB位置調整のため)
nPosX = nIndent = (this->*getIndentOffset)( m_pLayoutBot );
pLayoutCalculated = m_pLayoutBot;
}
}
nWordLen = 0;
nKinsokuType = KINSOKU_TYPE_NONE; //@@@ 2002.04.20 MIK
}
}
else
{
/* ワードラップ処理 */
if( m_bWordWrap /* 英文ワードラップをする */
&& nKinsokuType == KINSOKU_TYPE_NONE )
{
// if( 0 == nWordLen ){
/* 英単語の先頭か */
if( nPos >= nBgn &&
nCharChars == 1 &&
// ( pLine[nPos] == '#' || __iscsym( pLine[nPos] ) )
IS_KEYWORD_CHAR( pLine[nPos] )
){
/* キーワード文字列の終端を探す */
int i;
for( i = nPos + 1; i <= nLineLen - 1; ){
nCharChars2 = CMemory::MemCharNext( pLine, nLineLen, &pLine[i] ) - &pLine[i];
if( 0 == nCharChars2 ){
nCharChars2 = 1;
}
if( nCharChars2 == 1 &&
// ( pLine[i] == '#' || __iscsym( pLine[i] ) )
IS_KEYWORD_CHAR( pLine[i] )
){
}else{
break;
}
i += nCharChars2;
}
nWordBgn = nPos;
nWordLen = i - nPos;
nKinsokuType = KINSOKU_TYPE_WORDWRAP; //@@@ 2002.04.20 MIK
if( nPosX + i - nPos >= nMaxLineSize
&& nPos - nBgn > 0
){
AddLineBottom( CreateLayout(pCDocLine, nLineNum, nBgn, nPos - nBgn, nCOMMENTMODE_Prev, nIndent) );
m_nLineTypeBot = nCOMMENTMODE;
nCOMMENTMODE_Prev = nCOMMENTMODE;
nBgn = nPos;
// 2004.03.28 Moca nPosXはインデント幅を含むように変更(TAB位置調整のため)
nPosX = nIndent = (this->*getIndentOffset)( m_pLayoutBot );
pLayoutCalculated = m_pLayoutBot;
//? continue;
}
}
// }else{
// if( nPos == nWordBgn + nWordLen ){
// nWordLen = 0;
// }
// }
}
//@@@ 2002.04.07 MIK start
/* 句読点のぶらさげ */
if( m_bKinsokuKuto
&& (nMaxLineSize - nPosX < 2)
&& (nKinsokuType == KINSOKU_TYPE_NONE) )
{
bKinsokuFlag = false;
nCharChars2 = CMemory::MemCharNext( pLine, nLineLen, &pLine[nPos] ) - &pLine[nPos];
switch( nMaxLineSize - nPosX )
{
case 1: // 1文字前
if( nCharChars2 == 2 )
{
bKinsokuFlag = true;
}
break;
case 0: //
if( nCharChars2 == 1 || nCharChars2 == 2 )
{
bKinsokuFlag = true;
}
break;
}
if( bKinsokuFlag && IsKinsokuKuto( &pLine[nPos], nCharChars2 ) )
{
//nPos += nCharChars2; nPosX += nCharChars2;
nWordBgn = nPos;
nWordLen = nCharChars2;
nKinsokuType = KINSOKU_TYPE_KINSOKU_KUTO;
}
}
/* 行頭禁則 */
if( m_bKinsokuHead
&& (nMaxLineSize - nPosX < 4)
&& ( nPosX > nIndent ) // 2004.04.09 nPosXの解釈変更のため,行頭チェックも変更
&& (nKinsokuType == KINSOKU_TYPE_NONE) )
{
bKinsokuFlag = false;
nCharChars2 = CMemory::MemCharNext( pLine, nLineLen, &pLine[nPos] ) - &pLine[nPos];
nCharChars3 = CMemory::MemCharNext( pLine, nLineLen, &pLine[nPos+nCharChars2] ) - &pLine[nPos+nCharChars2];
switch( nMaxLineSize - nPosX )
{
// 321012 ↓マジックナンバー
// 3 "る)" : 22 ")"の2バイト目で折り返しのとき
// 2 "Z)" : 12 ")"の2バイト目で折り返しのとき
// 2 "る)": 22 ")"で折り返しのとき
// 2 "る)" : 21 ")"で折り返しのとき
// 1 "Z)": 12 ")"で折り返しのとき
// 1 "Z)" : 11 ")"で折り返しのとき
//↑何文字前か?
// ※ただし、"るZ"部分が禁則なら処理しない。
case 3: // 3文字前
if( nCharChars2 == 2 && nCharChars3 == 2 )
{
bKinsokuFlag = true;
}
break;
case 2: // 2文字前
if( 2 == nCharChars2 /*&& nCharChars3 > 0*/ )
{
bKinsokuFlag = true;
}
else if( nCharChars2 == 1 )
{
if( nCharChars3 == 2 )
{
bKinsokuFlag = true;
}
}
break;
case 1: // 1文字前
if( nCharChars2 == 1 /*&& nCharChars3 > 0*/ )
{
bKinsokuFlag = true;
}
break;
}
if( bKinsokuFlag
&& IsKinsokuHead( &pLine[nPos+nCharChars2], nCharChars3 )
&& ! IsKinsokuHead( &pLine[nPos], nCharChars2 ) //1文字前が行頭禁則でない
&& ! IsKinsokuKuto( &pLine[nPos], nCharChars2 ) ) //句読点でない
{
//nPos += nCharChars2 + nCharChars3; nPosX += nCharChars2 + nCharChars3;
nWordBgn = nPos;
nWordLen = nCharChars2 + nCharChars3;
nKinsokuType = KINSOKU_TYPE_KINSOKU_HEAD;
AddLineBottom( CreateLayout(pCDocLine, nLineNum, nBgn, nPos - nBgn, nCOMMENTMODE_Prev, nIndent) );
m_nLineTypeBot = nCOMMENTMODE;
nCOMMENTMODE_Prev = nCOMMENTMODE;
nBgn = nPos;
// 2004.03.28 Moca nPosXはインデント幅を含むように変更(TAB位置調整のため)
nPosX = nIndent = (this->*getIndentOffset)( m_pLayoutBot );
pLayoutCalculated = m_pLayoutBot;
}
}
/* 行末禁則 */
if( m_bKinsokuTail
&& (nMaxLineSize - nPosX < 4)
&& ( nPosX > nIndent ) // 2004.04.09 nPosXの解釈変更のため,行頭チェックも変更
&& (nKinsokuType == KINSOKU_TYPE_NONE) )
{ /* 行末禁則する && 行末付近 && 行頭でないこと(無限に禁則してしまいそう) */
bKinsokuFlag = false;
nCharChars2 = CMemory::MemCharNext( pLine, nLineLen, &pLine[nPos] ) - &pLine[nPos];
switch( nMaxLineSize - nPosX )
{
case 3: // 3文字前
if( nCharChars2 == 2 )
{
if( CMemory::MemCharNext( pLine, nLineLen, &pLine[nPos+nCharChars2] ) - &pLine[nPos+nCharChars2] == 2 )
{
// "(あ": "あ"の2バイト目で折り返しのとき
bKinsokuFlag = true;
}
}
break;
case 2: // 2文字前
if( nCharChars2 == 2 )
{
// "(あ": "あ"で折り返しのとき
bKinsokuFlag = true;
}
else if( nCharChars2 == 1 )
{
if( CMemory::MemCharNext( pLine, nLineLen, &pLine[nPos+nCharChars2] ) - &pLine[nPos+nCharChars2] == 2 )
{
// "(あ": "あ"の2バイト目で折り返しのとき
bKinsokuFlag = true;
}
}
break;
case 1: // 1文字前
if( nCharChars2 == 1 )
{
// "(あ": "あ"で折り返しのとき
bKinsokuFlag = true;
}
break;
}
if( bKinsokuFlag && IsKinsokuTail( &pLine[nPos], nCharChars2 ) )
{
//nPos += nCharChars2; nPosX += nCharChars2;
nWordBgn = nPos;
nWordLen = nCharChars2;
nKinsokuType = KINSOKU_TYPE_KINSOKU_TAIL;
AddLineBottom( CreateLayout(pCDocLine, nLineNum, nBgn, nPos - nBgn, nCOMMENTMODE_Prev, nIndent) );
m_nLineTypeBot = nCOMMENTMODE;
nCOMMENTMODE_Prev = nCOMMENTMODE;
nBgn = nPos;
// 2004.03.28 Moca nPosXはインデント幅を含むように変更(TAB位置調整のため)
nPosX = nIndent = (this->*getIndentOffset)( m_pLayoutBot );
pLayoutCalculated = m_pLayoutBot;
}
}
//@@@ 2002.04.08 MIK end
} //if( KINSOKU_TYPE_NONE != nKinsokuTyoe ) 禁則処理中
//@@@ 2002.09.22 YAZAKI
bool bGotoSEARCH_START = CheckColorMODE( nCOMMENTMODE, nCOMMENTEND, nPos, nLineLen, pLine, bDispSSTRING, bDispWSTRING );
if ( bGotoSEARCH_START )
goto SEARCH_START;
if( pLine[nPos] == TAB ){
// Sep. 23, 2002 genta せっかく作ったので関数を使う
nCharChars = GetActualTabSpace( nPosX );
if( nPosX + nCharChars > nMaxLineSize ){
AddLineBottom( CreateLayout(pCDocLine, nLineNum, nBgn, nPos - nBgn, nCOMMENTMODE_Prev, nIndent) );
m_nLineTypeBot = nCOMMENTMODE;
nCOMMENTMODE_Prev = nCOMMENTMODE;
nBgn = nPos;
// 2004.03.28 Moca nPosXはインデント幅を含むように変更(TAB位置調整のため)
nPosX = nIndent = (this->*getIndentOffset)( m_pLayoutBot );
pLayoutCalculated = m_pLayoutBot;
continue;
}
nPosX += nCharChars;
nCharChars = 1;
nPos+= nCharChars;
}else{
nCharChars = CMemory::MemCharNext( pLine, nLineLen, &pLine[nPos] ) - &pLine[nPos];
if( 0 == nCharChars ){
nCharChars = 1;
break; //@@@ 2002.04.16 MIK
}
if( nPosX + nCharChars > nMaxLineSize ){
if( nKinsokuType != KINSOKU_TYPE_KINSOKU_KUTO )
{
if( ! (m_bKinsokuRet && (nPos == nLineLen - nEol) && nEol) ) //改行文字をぶら下げる //@@@ 2002.04.14 MIK
{ //@@@ 2002.04.14 MIK
AddLineBottom( CreateLayout(pCDocLine, nLineNum, nBgn, nPos - nBgn, nCOMMENTMODE_Prev, nIndent) );
m_nLineTypeBot = nCOMMENTMODE;
nCOMMENTMODE_Prev = nCOMMENTMODE;
nBgn = nPos;
// 2004.03.28 Moca nPosXはインデント幅を含むように変更(TAB位置調整のため)
nPosX = nIndent = (this->*getIndentOffset)( m_pLayoutBot );
pLayoutCalculated = m_pLayoutBot;
continue;
} //@@@ 2002.04.14 MIK
}
}
nPos+= nCharChars;
nPosX += nCharChars;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -