/*! 対象行の、次の行を、対象行の末尾にくっつける。末端でDELETE操作 @param[in] dBsLine 対象の行番号・絶対0インデックス @return 特に意味はない @return HRESULT 終了状態コード */ HRESULT DocLineCombine( INT dBsLine ) { LETR_ITR vcLtrItr, vcLtrNxItr, vcLtrNxEnd; LINE_ITR itLine, itLineNx, ltLineItr; itLineNx = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLineNx, dBsLine+1 ); if( itLineNx == (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.end() ) return E_ACCESSDENIED; // 選択範囲ある時にアンドゥして、選択範囲が死んでる状態で切り取りするとここで落ちる vcLtrNxItr = itLineNx->vcLine.begin( ); // 次の行の先頭 vcLtrNxEnd = itLineNx->vcLine.end( ); // 次の行の尻尾 itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, dBsLine ); std::copy( vcLtrNxItr, vcLtrNxEnd, back_inserter( itLine->vcLine ) ); DocLineParamGet( dBsLine , NULL, NULL ); // 呼び出せば中で面倒みてくれる ltLineItr = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin( ); std::advance( ltLineItr, dBsLine+1 ); // 次の行 (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.erase( ltLineItr ); DocBadSpaceCheck( dBsLine ); // ついでに良くないスペースを調べておく return S_OK; }
/*! 指定行のドット位置(キャレット位置)に文字列を追加する・こっちが下位函数 @param[in] pNowDot 今のキャレットのドット位置のポインター @param[in] pdLine 対象の行番号・絶対0インデックスか @param[in] ptStr 追加したい文字列 @param[in] cchSize 文字列の文字数・ヌルターミネータ含まず @return INT 0改行無し 1〜改行した回数 */ INT DocStringAdd( PINT pNowDot, PINT pdLine, LPCTSTR ptStr, INT cchSize ) { INT i, insDot, dLn, dCrLf; assert( ptStr ); dCrLf = 0; dLn = *pdLine; insDot = *pNowDot; #ifdef DO_TRY_CATCH try{ #endif for( i = 0; cchSize > i; i++ ) { if( CC_CR == ptStr[i] && CC_LF == ptStr[i+1] ) // 改行であったら { DocInputReturn( insDot, *pdLine ); i++; // 0x0D,0x0Aだから、壱文字飛ばすのがポイント (*pdLine)++; // 改行したからFocusは次の行へ insDot = 0; // そして行の先頭である dCrLf++; // 改行した回数カウント } else if( CC_TAB == ptStr[i] ) { // タブは挿入しない } else { insDot += DocInputLetter( insDot, *pdLine, ptStr[i] ); } } #ifdef DO_TRY_CATCH } catch( exception &err ){ return (INT)ETC_MSG( err.what(), 0 ); } catch( ... ){ return (INT)ETC_MSG( ("etc error"), 0 ); } #endif #ifdef DO_TRY_CATCH try{ #endif // ここで空白チェキ・開始行から終了行までブンブンする for( i = dLn; *pdLine >= i; i++ ) { DocBadSpaceCheck( i ); } #ifdef DO_TRY_CATCH } catch( exception &err ){ return (INT)ETC_MSG( err.what(), 0 ); } catch( ... ){ return (INT)ETC_MSG( ("etc error"), 0 ); } #endif // アンドゥリドゥはここではなく呼んだほうで面倒見るほうがいい *pNowDot = insDot; return dCrLf; }
/*! 行末空白削除の面倒見る・選択行とか @param[in] pXdot 今のドット位置を受けて戻す・削除に巻き込まれた対応 @param[in] dLine 今の行数 @return HRESULT 終了状態コード */ HRESULT DocLastSpaceErase( PINT pXdot, INT dLine ) { UINT_PTR iLines; INT iTop, iBottom, i, xDelDot, xMotoDot; BOOLEAN bFirst = TRUE; LPTSTR ptBuffer = NULL; RECT rect; LINE_ITR itLine; TRACE( TEXT("行末空白削除") ); // 範囲確認 iLines = DocNowFilePageLineCount( ); iTop = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineTop; iBottom = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineBottom; if( 0 > iTop ) iTop = 0; if( 0 > iBottom ) iBottom = iLines - 1; ViewSelPageAll( -1 ); // 選択範囲無くなる itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, iTop ); // 位置合わせ for( i = iTop; iBottom >= i; i++, itLine++ ) { xMotoDot = itLine->iDotCnt; ptBuffer = DocLastSpDel( &(itLine->vcLine) ); xDelDot = DocLineParamGet( i, NULL, NULL ); // サクった後の行末端すなわち削除位置 if( ptBuffer ) { SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, ptBuffer, xDelDot, i , bFirst ); bFirst = FALSE; } FREE( ptBuffer ); DocBadSpaceCheck( i ); // 状態をリセット・中で行書換でいいか? rect.top = i * LINE_HEIGHT; rect.bottom = rect.top + LINE_HEIGHT; rect.left = xDelDot; // 削ったら左側になる rect.right = xMotoDot + 20; // 元長さ+改行マーク ViewRedrawSetRect( &rect ); // ViewRedrawSetLine( i ); // 再描画COMMANDO } // キャレット位置ずれてたら適当に調整 DocLetterPosGetAdjust( pXdot, dLine, 0 ); // キャレット位置適当に調整 ViewDrawCaret( *pXdot, dLine, 1 ); DocPageInfoRenew( -1, 1 ); return S_OK; }
/*! 指定行のドット位置(キャレット位置)でバックスペース押した @param[in] pdDot 今のキャレットのドット位置の値へのポインター @param[in] pdLine 対象の行番号・絶対0インデックスか @return INT 非0改行あった 0壱行のみ */ INT DocInputBkSpace( PINT pdDot, PINT pdLine ) { INT_PTR iLines; INT iLetter, width = 0, neDot, bCrLf = 0; INT dLine = *pdLine; // 函数内で使う行番号・調整に注意 TCHAR ch; LINE_ITR itLine; iLines = DocNowFilePageLineCount( ); if( iLines <= dLine ) return 0; // はみ出してたらアウツ! iLetter = DocLetterPosGetAdjust( pdDot, dLine, 0 ); // 今の文字位置を確認 neDot = *pdDot; // TRACE( TEXT("後空白[D%d C%d]"), neDot, iLetter ); if( 0 == iLetter && 0 == dLine ) return 0; // 先頭かつ最初の行なら、なにもしない // バックスペースとは、壱文字戻ってDELETEである if( 0 != iLetter ) // 行の先頭でないなら { iLetter--; // キャレット一つ戻す itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, dLine ); width = itLine->vcLine.at( iLetter ).rdWidth; ch = itLine->vcLine.at( iLetter ).cchMozi; *pdDot = neDot - width; // 文字幅分ドットも戻して bCrLf = 0; SqnAppendLetter( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, ch, *pdDot, dLine, TRUE ); } else // 行の先頭であるなら { dLine--; *pdLine = dLine; // 前の行に移動して neDot = DocLineParamGet( dLine, &iLetter, NULL ); *pdDot = neDot; // CARET位置調整 bCrLf = 1; // ここでやって問題無いはず SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, CH_CRLFW, *pdDot, dLine, TRUE ); } DocLetterErase( *pdDot, dLine, iLetter ); DocBadSpaceCheck( dLine ); // 良くないスペースを調べておく return bCrLf; }
/*! 指定行のドット位置(キャレット位置)に壱文字追加してアンドゥ記録する @param[in] pxDot 挿入するドット位置へのポインター @param[in] yLine 対象の行番号・絶対0インデックスか @param[in] ch 追加したい文字 @return INT 追加した文字のドット数 */ INT DocInsertLetter( PINT pxDot, INT yLine, TCHAR ch ) { INT width; SqnAppendLetter( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_INSERT, ch, *pxDot, yLine, TRUE ); width = DocInputLetter( *pxDot, yLine, ch ); *pxDot += width; // 途中でもいける DocBadSpaceCheck( yLine ); // ここで空白チェキ return width; }
/*! 指定行のドット位置(キャレット位置)でデリート押した @param[in] xDot 今のキャレットのドット位置 @param[in] yLine 対象の行番号・絶対0インデックスか @return INT 非0改行削除・0文字削除 */ INT DocInputDelete( INT xDot, INT yLine ) { INT_PTR iLines; INT iCount, iLetter, iCrLf; TCHAR ch; LINE_ITR itLine; iLines = DocNowFilePageLineCount( ); if( iLines <= yLine ) return 0; // はみ出してたらアウツ! iLetter = DocLetterPosGetAdjust( &xDot, yLine, 0 ); // 今の文字位置を確認 // TRACE( TEXT("削除[D%d C%d]"), xDot, iLetter ); DocLineParamGet( yLine, &iCount, NULL ); // この行の文字数を斗留 if( iCount <= iLetter ) { if( iLines <= (yLine+1) ) return 0; // 完全に末端なら何もしない ch = CC_LF; } else { itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, yLine ); ch = itLine->vcLine.at( iLetter ).cchMozi; } iCrLf = DocLetterErase( xDot, yLine, iLetter ); if( 0 > iCrLf ){ return -1; } DocBadSpaceCheck( yLine ); // 良くないスペースを調べておく if( 0 < iCrLf ) { SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, CH_CRLFW, xDot, yLine, TRUE ); } else { SqnAppendLetter( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, ch, xDot, yLine, TRUE ); } return iCrLf; }
/*! 行頭に、文字(主に空白)を追加 @param[in] ch 追加する文字 @param[in] pXdot 今のドット位置を受けて戻す・削除に巻き込まれた対応 @param[in] dLine 今の行数 @return HRESULT 終了状態コード */ HRESULT DocTopLetterInsert( TCHAR ch, PINT pXdot, INT dLine ) { UINT_PTR iLines; INT iTop, iBottom, i, xDot = 0; BOOLEAN bFirst = TRUE, bSeled = FALSE; TRACE( TEXT("行頭空白を追加") ); // 範囲確認 iLines = DocNowFilePageLineCount( ); iTop = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineTop; iBottom = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineBottom; if( 0 <= iTop && 0 <= iBottom ) bSeled = TRUE; if( 0 > iTop ) iTop = 0; if( 0 > iBottom ) iBottom = iLines - 1; // 選択範囲は、操作した行全体を選択状態にする for( i = iTop; iBottom >= i; i++ ) // 範囲内の各行について { // 先頭位置に文字桃得留。 xDot = DocInputLetter( 0, i, ch ); SqnAppendLetter( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_INSERT, ch, 0, i, bFirst ); bFirst = FALSE; if( bSeled ) { DocRangeSelStateToggle( -1, -1, i, 1 ); // 該当行全体を選択状態にする DocReturnSelStateToggle( i, 1 ); // 改行も選択で } DocBadSpaceCheck( i ); ViewRedrawSetLine( i ); } // キャレット位置ずれてたら適当に調整 *pXdot += xDot; DocLetterPosGetAdjust( pXdot, dLine, 0 ); // キャレット位置適当に調整 ViewDrawCaret( *pXdot, dLine, 1 ); DocPageInfoRenew( -1, 1 ); return S_OK; }
/*! 指定行の内容を削除する・改行はそのまま @param[in] yLine 対象の行番号 @param[in] pFirst アンドゥの非0初めてのグループ 0続きの処理 @return HRESULT 終了状態コード */ HRESULT DocLineErase( INT yLine, PBOOLEAN pFirst ) { INT dLines, iMozis, i; INT_PTR cbSize, cchSize; LPTSTR ptBuffer; wstring wsString; LINE_ITR itLine; wsString.clear( ); dLines = DocNowFilePageLineCount( );//DocPageParamGet( NULL, NULL ); // 行数確認 if( dLines <= yLine ) return E_OUTOFMEMORY; // はみ出し確認 DocLineParamGet( yLine, &iMozis, NULL ); // 指定行の文字数確保 if( 0 >= iMozis ) return E_ABORT; // 文字がないならすること無い itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, yLine ); for( i = 0; iMozis > i; i++ ) // 全文字を確保 { wsString += itLine->vcLine.at( i ).cchMozi; } cchSize = wsString.size( ) + 1; // NULLターミネータ分足す cbSize = cchSize * sizeof(TCHAR); // ユニコードなのでバイト数は2倍である ptBuffer = (LPTSTR)malloc( cbSize ); ZeroMemory( ptBuffer, cbSize ); StringCchCopy( ptBuffer, cchSize, wsString.c_str( ) ); SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, ptBuffer, 0, yLine, *pFirst ); *pFirst = FALSE; // 削除処理 itLine->vcLine.clear(); DocLineParamGet( yLine, NULL, NULL ); // 行内容の再計算 DocPageParamGet( NULL, NULL ); // 再計算 DocBadSpaceCheck( yLine ); // リセットに必要 ViewRedrawSetLine( yLine ); // 要らないかも return S_OK; }
/*! 指定行のドット位置で文字数分削除する・改行は弐文字占有 @param[in] xDot 今のキャレットのドット位置 @param[in] yLine 対象の行番号・絶対0インデックスか @param[in] ptDummy 未使用・NULLで @param[in] cchSize 削除する文字数 @return INT 0改行無し 1〜改行をサクった回数 */ INT DocStringErase( INT xDot, INT yLine, LPTSTR ptDummy, INT cchSize ) { INT i, iCrLf, iLetter, rdCnt; // 今の文字位置・キャレットより末尾方向に削除するので、この位置は変わらない iLetter = DocLetterPosGetAdjust( &xDot, yLine, 0 ); // 今の文字位置を確認 rdCnt = 0; for( i = 0; cchSize > i; i++ ) // DEL連打ってこと { iCrLf = DocLetterErase( xDot, yLine, iLetter ); if( 0 > iCrLf ) break; // 異常発生 if( iCrLf ){ i++; rdCnt++; } } DocBadSpaceCheck( yLine ); // 良くないスペースを調べておく return rdCnt; }
/*! 選択されているところを全削除しちゃう @param[in] pdDot キャレットドット位置・書き換える必要がある @param[in] pdLine 行番号・書き換える必要がある @param[in] bSqSel 矩形選択してるのかどうか・D_SQUARE @param[in] bFirst アンドゥ用・これが最初のアクションか @return 非0改行あった 0壱行のみ */ INT DocSelectedDelete( PINT pdDot, PINT pdLine, UINT bSqSel, BOOLEAN bFirst ) { // UINT_PTR iLines; UINT_PTR iMozis; INT i, j, dBeginX = 0, dBeginY = 0, cbSize; INT iLct, k, bCrLf; LPTSTR ptText; LPPOINT pstPt; LETR_ITR itLtr, itEnd, itHead, itTail; LINE_ITR itLine; #ifdef DO_TRY_CATCH try{ #endif bSqSel &= D_SQUARE; // 矩形ビットだけ残す // ページ全体の行数 // iLines = DocNowFilePageLineCount( ); i = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineTop; j = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineBottom; TRACE( TEXT("範囲削除[T%d - B%d]"), i, j ); if( 0 > i ){ return 0; } // 選択範囲が無かった //アンドゥバッファリングの準備 iLct = j - i + 1; // 含まれる行なので、数えるの注意 cbSize = DocSelectTextGetAlloc( D_UNI | bSqSel, (LPVOID *)(&ptText), NULL ); pstPt = (LPPOINT)malloc( iLct * sizeof(POINT) ); ZeroMemory( pstPt, iLct * sizeof(POINT) ); k = iLct - 1; bCrLf = iLct - 1; dBeginY = i; // 選択肢のある行 itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, j ); for( ; i <= j; j--, k--, itLine-- )//beginを超えたらアウツ! { // continueは使えない・ iMozis = itLine->vcLine.size( ); if( 0 < iMozis ) { itLtr = itLine->vcLine.begin( ); itEnd = itLine->vcLine.end( ); itHead = itEnd; itTail = itEnd; dBeginX = 0; // 最初の選択部分を検索 for( ; itLtr != itEnd; itLtr++ ) { if( CT_SELECT & itLtr->mzStyle ) { itHead = itLtr; break; } dBeginX += itLtr->rdWidth; // 意味があるのは最後のところなので、常時上書きでおk } // 選択されてない所まで検索 for( ; itLtr != itEnd; itLtr++ ) { if( !(CT_SELECT & itLtr->mzStyle) ) { itTail = itLtr; break; } } } pstPt[k].x = dBeginX; pstPt[k].y = j; if( 0 < iMozis ) { // 該当範囲を削除・末端は、該当部分の直前までが対象・末端自体は非対象 itLine->vcLine.erase( itHead, itTail ); } // 改行が含まれていたら if( CT_SELRTN & itLine->dStyle ){ DocLineCombine( j ); } DocLineParamGet( j, NULL, NULL ); // バイト数再計算 // 矩形の場合は、各行毎に面倒みないかん if( D_SQUARE & bSqSel ){ DocBadSpaceCheck( j ); } // 改行サクるとこれによりatが無効になる? // iLines = DocNowFilePageLineCount( ); // ページ全体の行数再設定? if( (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin() == itLine ) break; // 位置的に末端だったらループせずに終わる } ViewSelPageAll( -1 ); // 選択範囲無くなる // カーソル位置移動せないかん *pdDot = dBeginX; *pdLine = dBeginY; // 最終的に残っている行のチェックだけすればいい if( !(D_SQUARE & bSqSel) ){ DocBadSpaceCheck( dBeginY ); } if( bSqSel ){ SqnAppendSquare( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, ptText, pstPt, iLct , bFirst ); } else{ SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, ptText, dBeginX, dBeginY, bFirst ); } FREE( ptText ); FREE( pstPt ); #ifdef DO_TRY_CATCH } catch( exception &err ){ return (INT)ETC_MSG( err.what(), 0 ); } catch( ... ){ return (INT)ETC_MSG( ("etc error"), 0 ); } #endif return bCrLf; }
/*! 指定範囲に右揃え線を付ける @param[in] dTop 開始行・含む・−1で最初から @param[in] dBottom 終了行・含む・−1で最後まで @return HRESULT 終了状態コード */ HRESULT DocRightGuideSet( INT dTop, INT dBottom ) { // 処理が終わったら、呼んだ方で選択範囲の解除と画面更新すること UINT_PTR iLines, cchSize; INT baseDot, i, j, iMz, nDot, sDot, lDot, iUnt, iPadot; TCHAR ch, atBuffer[MAX_PATH]; LPTSTR ptBuffer; BOOLEAN bFirst; wstring wsBuffer; // 範囲確認 iLines = DocNowFilePageLineCount( ); if( 0 > dTop ) dTop = 0; if( 0 > dBottom ) dBottom = iLines - 1; // ZeroMemory( atBuffer, sizeof(atBuffer) ); atBuffer[0] = RIGHT_WALL; InitParamString( INIT_LOAD, VS_RGUIDE_MOZI, atBuffer ); // 一番長いとところを確認 baseDot = DocPageMaxDotGet( dTop, dBottom ); bFirst = TRUE; // 各行毎に追加する感じで for( i = dTop; dBottom >= i; i++ ) { nDot = DocLineParamGet( i , NULL, NULL ); // 呼び出せば中で面倒みてくれる sDot = baseDot - nDot; iUnt = sDot / SPACE_ZEN; // 埋める分 sDot = sDot % SPACE_ZEN; // はみ出しドット確認 // 変数使い回し注意 iPadot = nDot; wsBuffer.clear( ); // アンドゥバッファ用記録 for( j = 0; iUnt > j; j++ ) { ch = TEXT(' '); // 入れるのは全角空白確定 wsBuffer += ch; lDot = DocInputLetter( nDot, i, ch ); nDot += lDot; } // 20120315 ユニコードモードならゆにゆにっとする if( gbUniPad ){ iMz = lstrlen( gaatDotPtrnUnic[sDot] ); } else{ iMz = lstrlen( gaatDotPtrnPeriod[sDot] ); } // 揃え線までの空白を埋める for( j = 0; iMz > j; j++ ) { if( gbUniPad ){ ch = gaatDotPtrnUnic[sDot][j]; } // 20120315 else{ ch = gaatDotPtrnPeriod[sDot][j]; } wsBuffer += ch; lDot = DocInputLetter( nDot, i, ch ); nDot += lDot; } // 揃え末端文字入れ込む wsBuffer += atBuffer[0]; lDot = DocInputLetter( nDot, i, atBuffer[0] ); nDot += lDot; DocBadSpaceCheck( i ); // ここで空白チェキ // 入れた文字を統合してアンドゥバッファリング cchSize = wsBuffer.size( ) + 1; ptBuffer = (LPTSTR)malloc( cchSize * sizeof(TCHAR) ); StringCchCopy( ptBuffer, cchSize, wsBuffer.c_str( ) ); SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_INSERT, ptBuffer, iPadot, i, bFirst ); bFirst = FALSE; FREE( ptBuffer ); } return S_OK; }
/*! キャレット位置から、左右に1dotずつずらす。文字なら空白に置き換えながら @param[in] vk 方向・右か左か @param[in] pXdot 今のドット位置を受けて戻す @param[in] dLine 今の行数 @return HRESULT 終了状態コード */ HRESULT DocCentreWidthShift( UINT vk, PINT pXdot, INT dLine ) { UINT_PTR iLines, cchSz; UINT dRslt, dFirst; INT iBaseDot, iTop, iBottom, iBufDot; INT wid, iDot, iLin, iMzCnt; INT iFnlDot; BOOLEAN bSeled = FALSE; BOOLEAN bRight; // 非0右へ 0左へ LPTSTR ptRepl; TCHAR ch, chOneSp; LPUNDOBUFF pstUndoBuff; LETR_ITR vcLtrItr; LINE_ITR itLine; chOneSp = gaatPaddingSpDotW[1][0]; // 幅1dot・文字間に挿入 //中心部分が空白なら、その空白を伸び縮みさせる。 //文字と文字の間開けるなら、抽芯になってる字の左側を開けるようにする //潰すときは、抽芯字を空白に置き換えて、それを縮める pstUndoBuff = &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog); iBaseDot = *pXdot; // 基準点、なるべく動かないようにせないかん TRACE( TEXT("中間ずらし %dDOT"), iBaseDot ); iFnlDot = iBaseDot; if( VK_RIGHT == vk ) bRight = TRUE; else if( VK_LEFT == vk ) bRight = FALSE; else return E_INVALIDARG; if( 0 == iBaseDot ) // 基準が0なら、全体左右ずらしってこと { return DocPositionShift( vk, pXdot, dLine ); } // 範囲確認 iLines = DocNowFilePageLineCount( ); iTop = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineTop; iBottom = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineBottom; if( 0 <= iTop && 0 <= iBottom ) bSeled = TRUE; if( 0 > iTop ) iTop = 0; if( 0 > iBottom ) iBottom = iLines - 1; // そのままだと容量が狂う・一旦選択状態を解除して計算しなおす if( bSeled ){ DocPageSelStateToggle( -1 ); } // 壱行ずつ面倒見ていく itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, iTop ); // 位置合わせ //なんか時々連続空白ができる dFirst = TRUE; // 順番に処理していく for( iLin = iTop; iBottom >= iLin; iLin++, itLine++ ) { iDot = itLine->iDotCnt; if( iBaseDot >= iDot ){ continue; } // 操作位置に満たないのなら、何もする必要は無い // 操作開始 iDot = iBaseDot; // 調整位置確定 iMzCnt = DocLetterPosGetAdjust( &iDot, iLin, -1 ); // 常に左側をみる // 操作する位置の文字確認 // 該当位置が空白なら、伸び縮み兼用 iBufDot = iDot; // 値ズレるのでそのまま使うとイケない dRslt = DocSpaceDifference( vk, &iBufDot, iLin, dFirst ); // iBufDotはズラしたら使えない if( dRslt ) // ズラし成功 { if( iLin == dLine ){ iFnlDot = iBaseDot; } // ずらした後の位置の面倒見る dFirst = FALSE; } else // 返り値0なら、文字なので処理を { vcLtrItr = itLine->vcLine.begin( ); std::advance( vcLtrItr, iMzCnt ); // 注目位置の文字まで移動して ch = vcLtrItr->cchMozi; wid = vcLtrItr->rdWidth; // 該当の文字の幅を確認 if( bRight ) // 右に動かす { if( iswspace( ch ) ) // 右側の文字は空白であったら { iBufDot = iDot + wid; // その空白を延ばす DocSpaceDifference( vk, &iBufDot, iLin, dFirst ); // iBufDotは使えない if( iLin == dLine ){ iFnlDot = iBaseDot; } // ずらした後の位置の面倒見る } else { SqnAppendLetter( pstUndoBuff, DO_INSERT, chOneSp, iDot, iLin, dFirst ); DocInputLetter( iDot, iLin, chOneSp ); // その場所に1dotスペース足せばおk if( iLin == dLine ){ iFnlDot = iDot + 1; } // ずらした後の位置の面倒見る } dFirst = FALSE; } else // 左に動かす { if( iLin == dLine ){ iFnlDot = iDot; } // ずらす前の位置の面倒見る // 今の文字を削除 SqnAppendLetter( pstUndoBuff, DO_DELETE, ch, iDot, iLin, dFirst ); dFirst = FALSE; DocIterateDelete( vcLtrItr , iLin ); if( 2 <= wid ) // 幅が1なら、削除だけでおk { ptRepl = DocPaddingSpaceMake( wid-1 ); // 必要な空白確保 StringCchLength( ptRepl , STRSAFE_MAX_CCH, &cchSz ); // 文字数確認 SqnAppendString( pstUndoBuff, DO_INSERT, ptRepl, iDot, iLin, dFirst ); dFirst = FALSE; DocStringAdd( &iDot, &iLin, ptRepl, cchSz ); // そして先頭に空白をアッー! FREE(ptRepl); // 開放忘れないように } } } if( bSeled ) // 選択状態でヤッてたのなら、選択状態を維持する { if( iLin == iTop ) { iDot = iBaseDot; DocLetterPosGetAdjust( &iDot, iLin, 0 ); // キャレット位置適当に調整 DocRangeSelStateToggle( iDot, -1, iLin , 1 ); // 該当行全体を選択状態にする } else { DocRangeSelStateToggle( -1, -1, iLin , 1 ); // 該当行全体を選択状態にする } // 次の行があるなら改行も選択で if( iBottom > iLin ) DocReturnSelStateToggle( iLin, 1 ); } DocBadSpaceCheck( iLin ); // 状態をリセット ViewRedrawSetLine( iLin ); } if( bSeled ) // 選択範囲はり直し { (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineTop = iTop; (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineBottom = iBottom; } // キャレット位置調整 DocLetterPosGetAdjust( &iFnlDot, dLine, 0 ); // キャレット位置適当に調整 *pXdot = iFnlDot; // 位置を戻す ViewDrawCaret( iFnlDot, dLine, 1 ); // 再描画 DocPageByteCount( gitFileIt, gixFocusPage, NULL, NULL ); DocPageInfoRenew( -1, 1 ); return S_OK; }
/*! 行頭半角空白をユニコードに変換・ファイルコア函数 */ HRESULT DocHeadHalfSpaceExchange( HWND hWnd ) { UINT_PTR iLines; INT iTop, iBottom, i; INT xDot; BOOLEAN bFirst = TRUE, bSeled = FALSE; TCHAR ch; LETR_ITR vcLtrItr; LINE_ITR itLine; // 範囲確認 iLines = DocNowFilePageLineCount( ); iTop = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineTop; iBottom = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineBottom; if( 0 <= iTop && 0 <= iBottom ) bSeled = TRUE; if( 0 > iTop ) iTop = 0; if( 0 > iBottom ) iBottom = iLines - 1; TRACE( TEXT("行頭半角をユニコードに") ); ViewSelPageAll( -1 ); // 選択範囲無くなる // 容量計算、バッド空白の確認と再描画必要 itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, iTop ); // 行の位置合わせ for( i = iTop; iBottom >= i; i++, itLine++ ) // 範囲内の各行について { // 文字があるなら操作する if( 0 != itLine->vcLine.size( ) ) { vcLtrItr = itLine->vcLine.begin( ); ch = vcLtrItr->cchMozi; if( TEXT(' ') == ch ) // 半角なら { // 一旦削除して SqnAppendLetter( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, ch, 0, i, bFirst ); bFirst = FALSE; DocIterateDelete( vcLtrItr, i ); // 先頭位置に5dotユニコード空白をアッー!。 ch = (TCHAR)0x2004; xDot = DocInputLetter( 0, i, ch ); SqnAppendLetter( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_INSERT, ch, 0, i, bFirst ); } DocBadSpaceCheck( i ); // 状態をリセット ViewRedrawSetLine( i ); } } // キャレット位置はずれない DocPageInfoRenew( -1, 1 ); return S_OK; }
/*! AA全体を、1dotずつずらす。文字なら空白に置き換えながら @param[in] vk 方向・右か左か @param[in] pXdot 今のドット位置を受けて戻す @param[in] dLine 今の行数 @return HRESULT 終了状態コード */ HRESULT DocPositionShift( UINT vk, PINT pXdot, INT dLine ) { UINT_PTR iLines, cchSz; INT iTop, iBottom, i; INT wid, iDot, iLin, iMzCnt; INT iTgtWid, iLefDot, iRitDot; BOOLEAN bFirst = TRUE, bSeled = FALSE, bDone = FALSE; BOOLEAN bRight; // 非0右へ 0左へ BOOLEAN bIsSp; LPTSTR ptRepl; TCHAR ch, chOneSp; LPUNDOBUFF pstUndoBuff; LETR_ITR vcLtrItr; LINE_ITR itLine; chOneSp = gaatPaddingSpDotW[1][0]; pstUndoBuff = &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog); TRACE( TEXT("全体ずらし") ); if( VK_RIGHT == vk ) bRight = TRUE; else if( VK_LEFT == vk ) bRight = FALSE; else return E_INVALIDARG; // 範囲確認 iLines = DocNowFilePageLineCount( ); iTop = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineTop; iBottom = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineBottom; if( 0 <= iTop && 0 <= iBottom ) bSeled = TRUE; if( 0 > iTop ) iTop = 0; if( 0 > iBottom ) iBottom = iLines - 1; // そのままだと容量が狂う・一旦選択状態を解除して計算しなおす if( bSeled ){ DocPageSelStateToggle( -1 ); } // 壱行ずつ面倒見ていく itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, iTop ); // 位置合わせ for( i = iTop; iBottom >= i; i++, itLine++ ) { // 文字があるなら操作する if( 0 != itLine->vcLine.size( ) ) { // 先頭文字を確認 vcLtrItr = itLine->vcLine.begin( ); ch = vcLtrItr->cchMozi; wid = vcLtrItr->rdWidth; // 文字幅 bDone = FALSE; if( !(iswspace(ch)) ) // 空白ではなく { if( bRight ) // 右ずらしなら { // 先頭に1dotスペース足せばおk DocInputLetter( 0, i, chOneSp ); SqnAppendLetter( pstUndoBuff, DO_INSERT, chOneSp, 0, i, bFirst ); bFirst = FALSE; bDone = TRUE; // 処理しちゃった } else // 左イクなら、先頭文字を空白にして調整する { ptRepl = DocPaddingSpaceMake( wid ); // 必要な空白確保 StringCchLength( ptRepl, STRSAFE_MAX_CCH, &cchSz ); // 今の文字を削除 SqnAppendLetter( pstUndoBuff, DO_DELETE, ch, 0, i, bFirst ); bFirst = FALSE; DocIterateDelete( vcLtrItr, i ); // そして先頭に空白をアッー! iDot = 0; iLin = i; DocStringAdd( &iDot, &iLin, ptRepl, cchSz ); SqnAppendString( pstUndoBuff, DO_INSERT, ptRepl, 0, i, bFirst ); bFirst = FALSE; FREE(ptRepl); // 開放忘れないように } } // この先Beginイテレータ無効 if( !(bDone) ) // 未処理であるなら・この時点で、先頭文字は空白確定 { // 空白範囲を確認 iTgtWid = DocLineStateCheckWithDot( 0, i, &iLefDot, &iRitDot, NULL, &iMzCnt, &bIsSp ); if( bRight ) iTgtWid++; // 方向に合わせて else iTgtWid--; // ドット数を求める if( 0 > iTgtWid ) iTgtWid = 0; // マイナスは無いと思うけど念のため ptRepl = DocPaddingSpaceMake( iTgtWid ); // 必要な空白確保 // ターゲット幅が0ならNULLなので、先頭文字の削除だけでおk DocRangeDeleteByMozi( 0, i, 0, iMzCnt, &bFirst ); // 元の部分削除して if( ptRepl ) // 必要な文字を入れる { StringCchLength( ptRepl, STRSAFE_MAX_CCH, &cchSz ); iDot = 0; iLin = i; DocStringAdd( &iDot, &iLin, ptRepl, cchSz ); SqnAppendString( pstUndoBuff, DO_INSERT, ptRepl, 0, i, bFirst ); bFirst = FALSE; FREE(ptRepl); // 開放忘れないように } } if( bSeled ) // 選択状態でヤッてたのなら、選択状態を維持する { DocRangeSelStateToggle( -1, -1, i , 1 ); // 該当行全体を選択状態にする // 次の行があるなら改行も選択で if( iBottom > i ) DocReturnSelStateToggle( i, 1 ); } DocBadSpaceCheck( i ); // 状態をリセット ViewRedrawSetLine( i ); } } if( bSeled ) // 選択範囲はり直し { (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineTop = iTop; (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineBottom = iBottom; } // キャレット位置調整 iDot = 0; DocLetterPosGetAdjust( &iDot, dLine, 0 ); // キャレット位置適当に調整 ViewDrawCaret( iDot, dLine, 1 ); DocPageByteCount( gitFileIt, gixFocusPage, NULL, NULL ); DocPageInfoRenew( -1, 1 ); return S_OK; }
/*! 指定行のドット位置(キャレット位置)で改行する @param[in] nowDot 今のキャレットのドット位置 @param[in] rdLine 対象の行番号・絶対0インデックスか @return HRESULT 終了状態コード */ HRESULT DocInputReturn( INT nowDot, INT rdLine ) { INT_PTR iLetter, iLines, iCount; ONELINE stLine; LETR_ITR vcLtrItr, vcLtrEnd; LINE_ITR itLine, ltLineItr; #ifdef DO_TRY_CATCH try{ #endif iLines = DocNowFilePageLineCount( ); if( iLines <= rdLine ) return E_OUTOFMEMORY; ZeroONELINE( &stLine ); iLetter = DocLetterPosGetAdjust( &nowDot, rdLine, 0 ); // 今の文字位置を確認 // 文字数確認 itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, rdLine ); iCount = itLine->vcLine.size( ); if( iLetter < iCount ) // もし行の途中で改行したら? { ltLineItr = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin( ); std::advance( ltLineItr, (rdLine+1) ); // 今の行の次の場所に行のデータを挿入 (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.insert( ltLineItr, stLine ); // その行の、文字データの先頭をとる ltLineItr = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin( ); std::advance( ltLineItr, (rdLine+1) ); // 追加した行まで移動 // ぶった切った場所を設定しなおして itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, rdLine ); vcLtrItr = itLine->vcLine.begin( ); vcLtrItr += iLetter; // 今の文字位置を示した vcLtrEnd = itLine->vcLine.end( ); // 末端 // その部分を次の行にコピーする std::copy( vcLtrItr, vcLtrEnd, back_inserter(ltLineItr->vcLine) ); // 元の文字列を削除する itLine->vcLine.erase( vcLtrItr, vcLtrEnd ); // 総ドット数再計算 DocLineParamGet( rdLine, NULL, NULL ); DocLineParamGet( rdLine+1, NULL, NULL ); } else // 末端で改行した { if( (iLines - 1) == rdLine ) // EOF的なところ { (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.push_back( stLine ); } else { ltLineItr = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin( ); std::advance( ltLineItr, (rdLine+1) ); // 今の行を示した // 次の場所に行のデータを挿入 (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.insert( ltLineItr, stLine ); } } DocBadSpaceCheck( rdLine ); // ここで空白チェキ DocBadSpaceCheck( rdLine+1 ); // 空白チェキ・次の行も確認 #ifdef DO_TRY_CATCH } catch( exception &err ){ return (HRESULT)ETC_MSG( err.what(), E_UNEXPECTED ); } catch( ... ){ return (HRESULT)ETC_MSG( ("etc error") , E_UNEXPECTED ); } #endif return S_OK; }
/*! 行末文字を削除する。ただし空白だったら削除しない @param[in] pXdot 今のドット位置を受けて戻す・削除に巻き込まれた対応 @param[in] dLine 今の行数 @return HRESULT 終了状態コード */ HRESULT DocLastLetterErase( PINT pXdot, INT dLine ) { UINT_PTR iLines; INT iTop, iBottom, i, xDot = 0; TCHAR ch; BOOLEAN bFirst = TRUE, bSeled = FALSE; RECT rect; LETR_ITR vcLtrItr; LINE_ITR itLine; // 範囲確認 iLines = DocNowFilePageLineCount( ); iTop = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineTop; iBottom = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineBottom; if( 0 <= iTop && 0 <= iBottom ) bSeled = TRUE; if( 0 > iTop ) iTop = 0; if( 0 > iBottom ) iBottom = iLines - 1; TRACE( TEXT("行末文字削除") ); // 選択してる場合は、操作行を全選択状態にする itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, iTop ); // 位置合わせ for( i = iTop; iBottom >= i; i++, itLine++ ) // 範囲内の各行について { // 文字があるなら操作する if( 0 != itLine->vcLine.size( ) ) { vcLtrItr = itLine->vcLine.end( ); vcLtrItr--; // 終端の一個前が末端文字 ch = vcLtrItr->cchMozi; rect.top = i * LINE_HEIGHT; rect.bottom = rect.top + LINE_HEIGHT; if( !( iswspace( ch ) ) ) { xDot = DocLineParamGet( i, NULL, NULL ); xDot -= vcLtrItr->rdWidth; SqnAppendLetter( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, ch, xDot, i, bFirst ); bFirst = FALSE; DocIterateDelete( vcLtrItr, i ); rect.left = xDot; rect.right = xDot + 40; // 壱文字+改行・適当でよろし ViewRedrawSetRect( &rect ); // 末端だけ書き換えればいい? DocBadSpaceCheck( i ); // 良くないスペースを調べておく } } if( bSeled ) { DocRangeSelStateToggle( -1, -1, i , 1 ); // 該当行全体を選択状態にする DocReturnSelStateToggle( i, 1 ); // 改行も選択で } } // キャレット位置適当に調整 *pXdot = 0; DocLetterPosGetAdjust( pXdot, dLine, 0 ); // キャレット位置適当に調整 ViewDrawCaret( *pXdot, dLine, 1 ); DocPageInfoRenew( -1, 1 ); return S_OK; }
/*! 行頭全角空白及びユニコード空白を削除する @param[in] pXdot 今のドット位置を受けて戻す・削除に巻き込まれた対応 @param[in] dLine 今の行数 @return HRESULT 終了状態コード */ HRESULT DocTopSpaceErase( PINT pXdot, INT dLine ) { UINT_PTR iLines; INT iTop, iBottom, i; BOOLEAN bFirst = TRUE, bSeled = FALSE; TCHAR ch; LETR_ITR vcLtrItr; LINE_ITR itLine; // 範囲確認 iLines = DocNowFilePageLineCount( ); iTop = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineTop; iBottom = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineBottom; if( 0 <= iTop && 0 <= iBottom ) bSeled = TRUE; if( 0 > iTop ) iTop = 0; if( 0 > iBottom ) iBottom = iLines - 1; TRACE( TEXT("行頭空白を削除") ); // 選択範囲は、操作した行全体を選択状態にする itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, iTop ); // 位置合わせ for( i = iTop; iBottom >= i; i++, itLine++ ) // 範囲内の各行について { // 文字があるなら操作する if( 0 != itLine->vcLine.size( ) ) { vcLtrItr = itLine->vcLine.begin( ); ch = vcLtrItr->cchMozi; // 空白かつ半角ではない if( ( iswspace( ch ) && TEXT(' ') != ch ) ) { SqnAppendLetter( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, ch, 0, i, bFirst ); bFirst = FALSE; DocIterateDelete( vcLtrItr, i ); } } if( bSeled ) { DocRangeSelStateToggle( -1, -1, i, 1 ); // 該当行全体を選択状態にする DocReturnSelStateToggle( i, 1 ); // 改行も選択で } DocBadSpaceCheck( i ); // 状態をリセット ViewRedrawSetLine( i ); } // キャレット位置ずれてたら適当に調整 *pXdot = 0; DocLetterPosGetAdjust( pXdot, dLine, 0 ); // キャレット位置適当に調整 ViewDrawCaret( *pXdot, dLine, 1 ); DocPageInfoRenew( -1, 1 ); return S_OK; }
/*! 各行の末端から800くらいまでを、指定した文字で埋める。 @param[in] ptFill 埋め文字列 */ HRESULT DocScreenFill( LPTSTR ptFill ) { UINT_PTR dLines, dRiDot, cchSize; BOOLEAN bSel = TRUE, bFirst; INT iTop, iBottom, i, iUnt, j, remain; INT nDot, sDot, mDot; LPTSTR ptBuffer; wstring wsBuffer; // 現在行数と、右ドット数・ルーラ位置を使う dLines = DocNowFilePageLineCount( ); dRiDot = gdRightRuler; // 選択範囲あるならそっち優先。ないなら画面全体 iTop = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineTop; iBottom = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineBottom; if( 0 > iTop || 0 > iBottom ){ iTop = 0; iBottom = dLines - 1; bSel = FALSE; } ViewSelPageAll( -1 ); // 選択範囲無くなる // 埋め文字列の幅 mDot = ViewStringWidthGet( ptFill ); bFirst = TRUE; // 各行毎に追加する感じで for( i = iTop; iBottom >= i; i++ ) { nDot = DocLineParamGet( i , NULL, NULL ); // 呼び出せば中で面倒みてくれる sDot = dRiDot - nDot; // 残りドット if( 0 >= sDot ){ continue; } // 右端超えてるならなにもせんでいい iUnt = (sDot / mDot) + 1; // 埋める分・はみ出し・適当で良い // 入れる文字列作成 wsBuffer.clear( ); for( j = 0; iUnt > j; j++ ){ wsBuffer += wstring( ptFill ); } cchSize = wsBuffer.size( ) + 1; ptBuffer = (LPTSTR)malloc( cchSize * sizeof(TCHAR) ); StringCchCopy( ptBuffer, cchSize, wsBuffer.c_str( ) ); // 末端にブチこむ DocInsertString( &nDot, &i, NULL, ptBuffer, 0, bFirst ); bFirst = FALSE; FREE(ptBuffer); DocBadSpaceCheck( i ); // ここで空白チェキ・あまり意味はないが色換えは必要 } if( !(bSel) ) // 非選択状態で { remain = 40 - dLines; // とりあえず40行とする if( 0 < remain ) // 足りないなら { DocAdditionalLine( remain, &bFirst ); // とりあえず改行して dLines = DocNowFilePageLineCount( ); iUnt = (dRiDot / mDot) + 1; // 埋める分・はみ出し・適当で良い // 入れる文字列作成 wsBuffer.clear( ); for( j = 0; iUnt > j; j++ ){ wsBuffer += wstring( ptFill ); } cchSize = wsBuffer.size( ) + 1; ptBuffer = (LPTSTR)malloc( cchSize * sizeof(TCHAR) ); StringCchCopy( ptBuffer, cchSize, wsBuffer.c_str( ) ); iTop = iBottom + 1; iBottom = dLines - 1; for( i = iTop; iBottom >= i; i++ ) { // 末端にブチこむ nDot = DocLineParamGet( i , NULL, NULL ); // 多分0のハズ DocInsertString( &nDot, &i, NULL, ptBuffer, 0, bFirst ); bFirst = FALSE; DocBadSpaceCheck( i ); // ここで空白チェキ・あまり意味はないが色換えは必要 } FREE(ptBuffer); } } DocPageInfoRenew( -1, 1 ); return S_OK; }