/*! 現在頁の末端に改行を追加する @param[in] addLine 追加する行数 @param[in] pFirst アンドゥの非0初めてのグループ 0続きの処理 @return 全体の行数 */ INT DocAdditionalLine( INT addLine, PBOOLEAN pFirst ) { UINT_PTR iLines; INT cbSize, cchMozi, i; INT dBaseDot, dBaseLine; LPTSTR ptBuffer = NULL; iLines = DocNowFilePageLineCount( ); // この頁の行数 // 追加するのは最終行の末端 dBaseLine = iLines - 1; cchMozi = CH_CRLF_CCH * addLine; // 改行の文字数+ぬるたーみねーた cbSize = (cchMozi + 1) * sizeof(TCHAR); ptBuffer = (LPTSTR)malloc( cbSize ); ZeroMemory( ptBuffer, cbSize ); for( i = 0; addLine > i; i++ ) { StringCchCat( ptBuffer, cchMozi + 1, CH_CRLFW ); ViewRedrawSetLine( dBaseLine + i ); // 再描画行を確定しておく } dBaseDot = DocLineParamGet( dBaseLine, NULL, NULL ); SqnAppendString( &(gitFileIt->vcCont.at( gixFocusPage ).stUndoLog), DO_INSERT, ptBuffer, dBaseDot, dBaseLine, *pFirst ); DocStringAdd( &dBaseDot, &dBaseLine, ptBuffer, cchMozi ); FREE( ptBuffer ); *pFirst = FALSE; return iLines; }
/*! 行末空白削除の面倒見る・選択行とか @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] xDot 追加開始するドット位置 @param[in] yLine 追加開始する行番号 @param[in] dNeedLine 使う行数 @param[in] bFirst アンドゥの非0初めてのグループ 0続きの処理 @return INT 非0しなかった 0処理した */ INT DocSquareAddPreMod( INT xDot, INT yLine, INT dNeedLine, BOOLEAN bFirst ) { // 行増やすのと、所定の位置までスペースで埋める INT_PTR iLines; INT iBaseDot, iBaseLine, iMinus, i; UINT cchBuf; LPTSTR ptBuffer = NULL; // この頁の行数 iLines = DocNowFilePageLineCount( ); // 全体行数より、追加行数が多かったら、改行増やす if( iLines < (dNeedLine + yLine) ) { iMinus = (dNeedLine + yLine) - iLines; // 追加する行数 DocAdditionalLine( iMinus, &bFirst );// bFirst = FALSE; // この頁の行数取り直し iLines = DocNowFilePageLineCount( ); } // 各行のドット数を確認して、足りないところをパディングする //多い分には問題無し・足りないのが3以下なら無視、あとは適当にパディングを作る //良い感じの数が無かったら増減して作れるまでさがす for( i = 0; dNeedLine > i; i++ ) { iBaseLine = yLine + i; iBaseDot = DocLineParamGet( iBaseLine, NULL, NULL ); // 基準から存在ドットを引くと、+なら足りない iMinus = xDot - iBaseDot; if( gbUniPad ){ if( 0 >= iMinus ) continue; } else{ if( 3 >= iMinus ) continue; } // 余るか3以下なら気にする必要は無い ptBuffer = DocPaddingSpaceWithPeriod( iMinus, NULL, NULL, NULL, FALSE ); if( !ptBuffer ) // まずは綺麗に納めるのを試みて、ダメならズレありで再計算 { ptBuffer = DocPaddingSpaceWithGap( iMinus, NULL, NULL ); } if( !ptBuffer ){ continue; } StringCchLength( ptBuffer, STRSAFE_MAX_CCH, &cchBuf ); SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_INSERT, ptBuffer, iBaseDot, iBaseLine, bFirst ); bFirst = FALSE; DocStringAdd( &iBaseDot, &iBaseLine, ptBuffer, cchBuf ); FREE( ptBuffer ); } return bFirst; }
/*! 指定行のドット位置(キャレット位置)でデリート押した @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] 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 対象行 @param[in] dBgnMozi 開始文字位置 @param[in] dEndMozi 終端文字位置 @param[in,out] pFirst アンドゥ記録用 @return UINT 街頭部分の文字数 */ UINT DocRangeDeleteByMozi( INT xDot, INT yLine, INT dBgnMozi, INT dEndMozi, PBOOLEAN pFirst ) { UINT_PTR cchSize; INT iBytes; LPTSTR ptBuffer; LETR_ITR vcLtrBgn, vcLtrEnd, vcItr; wstring wsDelBuf; LINE_ITR itLine; itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, yLine ); vcLtrBgn = itLine->vcLine.begin( ); vcLtrEnd = itLine->vcLine.begin( ); vcLtrBgn += dBgnMozi; // 該当位置まで移動して vcLtrEnd += dEndMozi; // そのエリアの終端も確認 wsDelBuf.clear(); iBytes = 0; for( vcItr = vcLtrBgn; vcLtrEnd != vcItr; vcItr++ ) { wsDelBuf += vcItr->cchMozi; iBytes += vcItr->mzByte; } // 該当部分を削除 itLine->vcLine.erase( vcLtrBgn, vcLtrEnd ); itLine->iByteSz -= iBytes; // アンドゥバッファ作成 cchSize = wsDelBuf.size( ) + 1; ptBuffer = (LPTSTR)malloc( cchSize * sizeof(TCHAR) ); StringCchCopy( ptBuffer, cchSize, wsDelBuf.c_str( ) ); SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, ptBuffer, xDot, yLine, *pFirst ); FREE( ptBuffer ); *pFirst = FALSE; return (UINT)(cchSize - 1); }
/*! ずれ調整を実行する @param[in] pxDot 調整位置 @param[in] yLine 対象行 @return INT 調整したドット量 */ INT DocDiffAdjExec( PINT pxDot, INT yLine ) { INT dMotoDot = 0; INT dBgnDot, dEndDot, dBgnCnt, dRngCnt, iSabun, dTgtDot, nDot; UINT_PTR cchSize, cchPlus; BOOLEAN bIsSpace; LPTSTR ptPlus, ptBuffer; wstring wsDelBuf, wsAddBuf; LETR_ITR vcLtrBgn, vcLtrEnd, vcItr; LINE_ITR itLine; itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, yLine ); // 調整値の状況を確認 dTgtDot = DocLineStateCheckWithDot( *pxDot, yLine, &dBgnDot, &dEndDot, &dBgnCnt, &dRngCnt, &bIsSpace ); if( !(bIsSpace) ) { NotifyBalloonExist( TEXT("連続するスペースの部分にカーソルを当てるですぅ"), TEXT("調整不可能"), NIIF_ERROR ); return 0; } //今現在の空白幅を確認 // 対象行の長さを確認 dMotoDot = DocLineParamGet( yLine, NULL, NULL ); iSabun = gdDiffLock - dMotoDot; // 差分確認・マイナスならはみ出してる //まず全角半角で埋めて、半角が多いようならピリオド付けて再計算 dTgtDot += iSabun; // 変更後のドット数 if( 41 > dTgtDot ) // ユニコード使うなら確認しなくても大丈夫? { NotifyBalloonExist( TEXT("もう少し幅がないと調整できないですぅ"), TEXT("狭すぎ"), NIIF_ERROR ); return 0; } //埋め文字列作成 ptPlus = DocPaddingSpaceWithPeriod( dTgtDot, NULL, NULL, NULL, FALSE ); if( !(ptPlus) ) { NotifyBalloonExist( TEXT("調整出来なかったですぅ"), TEXT("自動調整失敗"), NIIF_ERROR ); return 0; } StringCchLength( ptPlus, STRSAFE_MAX_CCH, &cchPlus ); vcLtrBgn = itLine->vcLine.begin( ); vcLtrBgn += dBgnCnt; // 該当位置まで移動して vcLtrEnd = vcLtrBgn; vcLtrEnd += dRngCnt; // そのエリアの終端も確認 wsDelBuf.clear(); for( vcItr = vcLtrBgn; vcLtrEnd != vcItr; vcItr++ ){ wsDelBuf += vcItr->cchMozi; } // 該当部分を削除 itLine->vcLine.erase( vcLtrBgn, vcLtrEnd ); nDot = dBgnDot; cchSize = wsDelBuf.size( ) + 1; ptBuffer = (LPTSTR)malloc( cchSize * sizeof(TCHAR) ); StringCchCopy( ptBuffer, cchSize, wsDelBuf.c_str( ) ); SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, ptBuffer, dBgnDot, yLine, TRUE ); FREE( ptBuffer ); //ここで文字列追加 DocStringAdd( &nDot, &yLine, ptPlus, cchPlus ); SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_INSERT, ptPlus, dBgnDot, yLine, FALSE ); FREE(ptPlus); //もろもろの位置合わせしておk *pxDot = nDot; DocLetterPosGetAdjust( pxDot, yLine, 0 ); ViewRedrawSetLine( yLine ); ViewDrawCaret( *pxDot, yLine, 1 ); return iSabun; }
/*! 指定範囲に右揃え線を付ける @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; }
/*! 現在のドット位置を含んでいる空白エリアを1ドットずつずらす @param[in] vk 方向・右か左か @param[in] pXdot 今のドット位置を受けて戻す @param[in] dLine 今の行数 @param[in] dFirst アンドゥグループ・非0なら最初の一発 0続き @return UINT 非0ズレ値 0失敗 */ UINT DocSpaceDifference( UINT vk, PINT pXdot, INT dLine, UINT dFirst ) { INT dTgtDot, dNowDot; INT dBgnDot, dEndDot; INT dBgnCnt, dRngCnt; UINT_PTR cchSize; BOOLEAN bIsSpace; LPTSTR ptSpace;//, ptOldSp; INT dZenSp, dHanSp, dUniSp; INT iDots, iBytes; wstring wsBuffer; LETR_ITR vcLtrBgn, vcLtrEnd, vcItr; LINE_ITR itLine; itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, dLine ); dNowDot = *pXdot; if( 0 == dNowDot ) // 0の場合は強引に移動 { dNowDot = itLine->vcLine.at( 0 ).rdWidth; } dTgtDot = DocLineStateCheckWithDot( dNowDot, dLine, &dBgnDot, &dEndDot, &dBgnCnt, &dRngCnt, &bIsSpace ); if( !(bIsSpace) ) return 0; // 非スペースエリアは意味が無い if( VK_RIGHT == vk ) dTgtDot++; // 右なら増やすってこと else if( VK_LEFT == vk ) dTgtDot--; else return 0; // 関係ないのはアウツ // 当てはめるアレを計算する ptSpace = DocPaddingSpace( dTgtDot, &dZenSp, &dHanSp ); if( gbUniPad ) { // 作成不可だったり半角多すぎたら、ユニコード使って作り直し if( !(ptSpace) || (dZenSp < dHanSp) ) // (dZenSp + 1) { FREE(ptSpace); ptSpace = DocPaddingSpaceUni( dTgtDot, &dZenSp, &dHanSp, &dUniSp ); } } if( !(ptSpace) ) return 0; // 作成不可だった場合 StringCchLength( ptSpace, STRSAFE_MAX_CCH, &cchSize ); vcLtrBgn = itLine->vcLine.begin( ); vcLtrBgn += dBgnCnt; // 該当位置まで移動して vcLtrEnd = vcLtrBgn; vcLtrEnd += dRngCnt; // そのエリアの終端も確認 iDots = 0; iBytes = 0; wsBuffer.clear(); for( vcItr = vcLtrBgn; vcLtrEnd != vcItr; vcItr++ ) { wsBuffer += vcItr->cchMozi; iDots += vcItr->rdWidth; iBytes += vcItr->mzByte; } // 該当部分を一旦削除・アンドゥリドゥするなら内容を記録する必要がある itLine->vcLine.erase( vcLtrBgn, vcLtrEnd ); itLine->iByteSz -= iBytes; if( 0 > itLine->iByteSz ){ itLine->iByteSz = 0; } itLine->iDotCnt -= iDots; if( 0 > itLine->iDotCnt ){ itLine->iDotCnt = 0; } // DocLineParamGet( yLine, NULL, NULL ); // 行内容の再計算 //あとの函数内で呼ばれまくってる // Space文字列を追加 dNowDot = dBgnDot; DocStringAdd( &dNowDot, &dLine, ptSpace, cchSize ); *pXdot = dNowDot; // cchSize = wsBuffer.size( ) + 1; // ptOldSp = (LPTSTR)malloc( cchSize * sizeof(TCHAR) ); // StringCchCopy( ptOldSp, cchSize, wsBuffer.c_str( ) ); SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, wsBuffer.c_str( ), dBgnDot, dLine, dFirst ); SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_INSERT, ptSpace, dBgnDot, dLine, FALSE ); // 弐回目なので確定でよろし // FREE( ptOldSp ); FREE( ptSpace ); return dTgtDot; }
/*! キャレット位置から、左右に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; }
/*! 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,out] pNowDot 今のキャレットのドット位置 @param[in,out] pdLine 対象の行番号・絶対0インデックスか @param[in,out] pdMozi 今のキャレットの文字数・NULLでもおk @param[in] ptText 挿入する文字列 @param[in] dStyle 矩形かどうか、不可視特別か @param[in] bFirst アンドゥ用・これが最初のアクションか @return 0壱行ですんだ 非0複数行に渡った */ INT DocInsertString( PINT pNowDot, PINT pdLine, PINT pdMozi, LPCTSTR ptText, UINT dStyle, BOOLEAN bFirst ) { INT dBaseDot, dBaseLine, dNeedLine; INT dCrLf, i, dLastLine; UINT_PTR cchSize; LPPOINT pstPoint; dBaseDot = *pNowDot; dBaseLine = *pdLine; dLastLine = *pdLine; if( !(ptText) ) return 0; // 挿入文字列がないなら直ぐ終わってよい StringCchLength( ptText, STRSAFE_MAX_CCH, &cchSize ); if( dStyle & D_SQUARE ) // 矩形用 { // 使う行数 dNeedLine = DocStringInfoCount( ptText, cchSize, NULL, NULL ); bFirst = DocSquareAddPreMod( *pNowDot, *pdLine, dNeedLine, bFirst ); // 中でアンドゥ追加までやる。 pstPoint = NULL; // NULL化必須 dCrLf = DocSquareAdd( pNowDot, pdLine, ptText, cchSize, &pstPoint ); // 貼付前の整形を含めて1Groupとして扱う必要がある SqnAppendSquare( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_INSERT, ptText, pstPoint, dCrLf, bFirst ); bFirst = FALSE; FREE( pstPoint ); dLastLine = *pdLine; } else { // この中で改行とか面倒見る dCrLf = DocStringAdd( pNowDot, pdLine, ptText, cchSize ); SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_INSERT, ptText, dBaseDot, dBaseLine, bFirst ); bFirst = FALSE; dLastLine = DocPageParamGet( NULL, NULL );//再計算必要か? } if( dCrLf ) { for( i = dBaseLine; dLastLine >= i; i++ ){ ViewRedrawSetLine( i ); } } else { ViewRedrawSetLine( *pdLine ); } if( pdMozi ){ *pdMozi = DocLetterPosGetAdjust( pNowDot, *pdLine , 0 ); } // 今の文字位置を確認 // ヤバイ状態のときは操作しないようにする if( !(D_INVISI & dStyle) ) ViewDrawCaret( *pNowDot, *pdLine, TRUE ); return dCrLf; }
/*! 文字列の改行処理をする @param[in] xDot キャレットのドット位置 @param[in] yLine 対象の行番号・絶対0インデックスか @param[in] bFirst アンドゥ処理の先頭かどうか @return HRESULT 終了状態コード */ HRESULT DocCrLfAdd( INT xDot, INT yLine, BOOLEAN bFirst ) { SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_INSERT, CH_CRLFW, xDot, yLine, bFirst ); return DocInputReturn( xDot , yLine ); }
/*! 選択範囲を指定文字列で塗りつぶす @param[in] ptBrush ブラシ文字列・NULLなら空白 @param[in] pdDot キャレットドット位置・書き換える必要がある @param[in] pdLine 行番号・書き換える必要がある @return 非0塗った 0してない */ INT DocSelectedBrushFilling( LPTSTR ptBrush, PINT pdDot, PINT pdLine ) { UINT_PTR iMozis; UINT_PTR cchSize; INT i, j, dBeginX = 0, dBeginY = 0; INT iLct, dTgtDot, dBgnDot, dNowDot; BOOLEAN bFirst; LPTSTR ptReplc = NULL, ptDeled; // INT dZenSp, dHanSp, dUniSp; wstring wsBuffer; LETR_ITR itLtr, itEnd, itHead, itTail; LINE_ITR itLine; bFirst = TRUE; 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; } // 選択範囲が無かった dBeginY = i; // 選択肢のある行 dBeginX = 0; // 壱行ずつ処理していく itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, i ); for( iLct = i; j >= iLct; iLct++, itLine++ ) { // 文字数確認して iMozis = itLine->vcLine.size( ); if( 0 < iMozis ) { itLtr = itLine->vcLine.begin( ); itEnd = itLine->vcLine.end( ); itHead = itEnd; itTail = itEnd; dBgnDot = 0; dTgtDot = 0; // 最初の選択部分を検索 for( ; itLtr != itEnd; itLtr++ ) { if( CT_SELECT & itLtr->mzStyle ) { itHead = itLtr; dTgtDot = itLtr->rdWidth; itLtr++; // 次の文字を参照 break; } dBgnDot += itLtr->rdWidth; } if( iLct == i ){ dBeginX = dBgnDot; } // 意味があるのは最後のところ // 選択されてない所まで検索 for( ; itLtr != itEnd; itLtr++ ) { if( !(CT_SELECT & itLtr->mzStyle) ) { itTail = itLtr; break; } dTgtDot += itLtr->rdWidth; // ドット数を確認 } // 当てはめるアレを計算する if( ptBrush ) { ptReplc = BrushStringMake( dTgtDot, ptBrush ); } else // 空白指定ということ { ptReplc = DocPaddingSpaceMake( dTgtDot ); } // ここで、埋め文字列が作成不可なら、この行の処理は飛ばす if( !(ptReplc) ) continue; // 該当部分の内容を記録<アンドゥ用 wsBuffer.clear(); for( itLtr = itHead; itLtr != itTail; itLtr++ ) { wsBuffer += itLtr->cchMozi; } cchSize = wsBuffer.size( ) + 1; ptDeled = (LPTSTR)malloc( cchSize * sizeof(TCHAR) ); StringCchCopy( ptDeled, cchSize, wsBuffer.c_str( ) ); // 該当部分を削除 itLine->vcLine.erase( itHead, itTail ); // ブラシ文字列で埋める StringCchLength( ptReplc, STRSAFE_MAX_CCH, &cchSize ); dNowDot = dBgnDot; DocStringAdd( &dNowDot, &iLct, ptReplc, cchSize ); SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_DELETE, ptDeled, dBgnDot, iLct, bFirst ); bFirst = FALSE; SqnAppendString( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog), DO_INSERT, ptReplc, dBgnDot, iLct, bFirst ); FREE( ptDeled ); FREE( ptReplc ); ViewRedrawSetLine( iLct ); } } ViewSelPageAll( -1 ); // 選択範囲無くなる // カーソル位置移動せないかん *pdDot = dBeginX; *pdLine = dBeginY; return 1; }
/*! 選択されているところを全削除しちゃう @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; }