/*! 矩形貼付をする前に、 場の状況を確認して、必要なら整形する @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; }
/*! 指定された行の始点終点ドット位置の区間の文字の選択状態をON/OFFする @param[in] dBgnDot 開始ドット位置・マイナスなら0 @param[in] dEndDot 終了ドット位置・マイナスなら行末端 @param[in] rdLine 対象の行番号・ドキュメントの0インデックス @param[in] dForce 0斗愚留 +選択状態 ー選択解除 @return 該当文字のドット数 */ INT DocRangeSelStateToggle( INT dBgnDot, INT dEndDot, INT rdLine, INT dForce ) { UINT_PTR iLines; INT dLtrDot = 0, dMaxDots, dDot; RECT rect; iLines = DocNowFilePageLineCount( ); if( (INT)iLines <= rdLine ) return 0; dMaxDots = DocLineParamGet( rdLine, NULL, NULL ); // 範囲調整 if( 0 > dBgnDot ) dBgnDot = 0; if( 0 > dEndDot ) dEndDot = dMaxDots; for( dDot = dBgnDot; dEndDot > dDot; ) { dDot += DocLetterSelStateToggle( dDot, rdLine, dForce ); } //操作済のアレの計算がヘン・フラグの兼ね合いとか dLtrDot = dDot - dBgnDot; rect.left = dBgnDot; rect.top = rdLine * LINE_HEIGHT; rect.right = dEndDot; rect.bottom = rect.top + LINE_HEIGHT; // ViewRedrawSetLine( rdLine ); ViewRedrawSetRect( &rect ); DocSelectedByteStatus( ); return dLtrDot; // ドット数戻してOK }
/*! 示されたドット位置の直後の文字の選択状態の確認 @param[in] nowDot 対象のドット位置 @param[in] rdLine 対象の行番号・ドキュメントの0インデックス @return 非0選択状態 0選択してない */ UINT DocLetterSelStateGet( INT nowDot, INT rdLine ) { UINT dStyle; INT iLetter; INT_PTR iLines, iLength; LINE_ITR itLine; iLines = DocNowFilePageLineCount( ); if( iLines <= rdLine ) return 0; iLetter = DocLetterPosGetAdjust( &nowDot, rdLine, 0 ); // 今の文字位置を確認 // 直後の文字を確認 itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, rdLine ); if( (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.end() == itLine ){ return 0; } iLength = itLine->vcLine.size(); if( iLength <= iLetter ) return 0; // フラグ操作 dStyle = itLine->vcLine.at( iLetter ).mzStyle; if( dStyle & CT_SELECT ) return 1; return 0; }
/*! 現在頁の末端に改行を追加する @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] hWnd ウインドウハンドル @param[in] hInst 実存ハンドル @param[in] iNow 今の行 @return HRESULT 終了状態コード */ HRESULT DocPageDivide( HWND hWnd, HINSTANCE hInst, INT iNow ) { INT iDivLine = iNow + 1; INT iLines, mRslt, iNewPage; // INT_PTR iTotal, iNext; ONELINE stLine; LINE_ITR itLine, itEnd; ZeroONELINE( &stLine ); //mRslt = MessageBox( hWnd, TEXT("分割しちゃったら復帰できないよ・・・\r\n本当にバラしていい?"), TEXT("確認です"), MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2 ); mRslt = MessageBoxCheckBox( hWnd, hInst, 1 ); if( IDNO == mRslt ){ return E_ABORT; } //分割は、アンドゥをリセットすべし<要は削除なので、リセットしなくてもいいかもだ //今の頁の該当部分を削除しちゃう iLines = DocNowFilePageLineCount( );//DocPageParamGet( NULL, NULL ); // 行数確保 if( iLines <= iDivLine ) return E_OUTOFMEMORY; // 今の頁の次に作成 //iTotal = DocNowFilePageCount( ); //iNext = gixFocusPage + 1; // 次の頁 //if( iTotal <= iNext ){ iNext = -1; } // 全頁より多いなら末端指定 iNewPage = DocPageCreate( gixFocusPage ); // 新頁 PageListInsert( iNewPage ); // ページリストビューに追加 // 空の壱行が作られてるので、削除しておく (*gitFileIt).vcCont.at( iNewPage ).ltPage.clear( ); itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin( ); std::advance( itLine, iDivLine ); // 該当行まで進める itEnd = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.end( ); // 末端位置確保 std::copy( itLine, itEnd, back_inserter( (*gitFileIt).vcCont.at( iNewPage ).ltPage ) ); (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.erase( itLine, itEnd ); SqnFreeAll( &((*gitFileIt).vcCont.at( gixFocusPage ).stUndoLog) ); // アンドゥログ削除 // バイト情報とかの取り直し DocPageByteCount( gitFileIt, gixFocusPage, NULL, NULL ); DocPageInfoRenew( gixFocusPage, TRUE ); DocPageByteCount( gitFileIt, iNewPage, NULL, NULL ); DocPageInfoRenew( iNewPage, FALSE ); ViewRedrawSetLine( -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; }
/*! 指定された行の改行の選択状態をON/OFFする @param[in] rdLine 対象の行番号・ドキュメントの0インデックス @param[in] dForce 0斗愚留 +選択状態 ー選択解除 @return HRESULT 終了状態コード */ HRESULT DocReturnSelStateToggle( INT rdLine, INT dForce ) { UINT_PTR iLines; UINT dStyle, maeSty; INT iLnDot, dByte; RECT rect; LINE_ITR itLine; iLines = DocNowFilePageLineCount( ); if( (INT)iLines <= rdLine ) return E_OUTOFMEMORY; iLnDot = DocLineParamGet( rdLine, NULL, NULL ); // フラグ操作 itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, rdLine ); dStyle = itLine->dStyle; maeSty = dStyle; if( 0 == dForce ){ dStyle ^= CT_SELRTN; } else if( 0 < dForce ){ dStyle |= CT_SELRTN; } else if( 0 > dForce ){ dStyle &= ~CT_SELRTN; } itLine->dStyle = dStyle; if( maeSty != dStyle ) // フラグ操作されてたら { if( gbCrLfCode ) dByte = YY2_CRLF; else dByte = STRB_CRLF; if( CT_SELRTN & dStyle ) gdSelByte += dByte; else gdSelByte -= dByte; if( 0 > gdSelByte ) gdSelByte = 0; // 0未満になったら本当はおかしい DocSelectedByteStatus( ); } rect.left = iLnDot; rect.top = rdLine * LINE_HEIGHT; rect.right = iLnDot + 20; // たぶんこれくらい rect.bottom = rect.top + LINE_HEIGHT; // ViewRedrawSetLine( rdLine ); ViewRedrawSetRect( &rect ); return S_OK; }
/*! 指定行のドット位置(キャレット位置)でデリート押した @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; }
/*! 示されたドット位置の直後の文字の選択状態をON/OFFして、該当文字の幅を返す・単独では呼ばれない? @param[in] nowDot 対象のドット位置 @param[in] rdLine 対象の行番号・ドキュメントの0インデックス @param[in] dForce 0斗愚留 +選択状態 ー選択解除 @return 該当文字のドット数 */ INT DocLetterSelStateToggle( INT nowDot, INT rdLine, INT dForce ) { UINT dStyle, maeSty; INT dLtrDot = 0, iLetter, dByte; INT_PTR iLines, iLength; LINE_ITR itLine; iLines = DocNowFilePageLineCount( ); if( iLines <= rdLine ) return 0; iLetter = DocLetterPosGetAdjust( &nowDot, rdLine, 0 ); // 今の文字位置を確認 // 直後の文字の幅を確認 itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, rdLine ); if( (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.end() == itLine ){ return 0; } iLength = itLine->vcLine.size(); if( iLength <= iLetter ) return 0; dLtrDot = itLine->vcLine.at( iLetter ).rdWidth; dByte = itLine->vcLine.at( iLetter ).mzByte; // フラグ操作 dStyle = itLine->vcLine.at( iLetter ).mzStyle; maeSty = dStyle; if( 0 == dForce ){ dStyle ^= CT_SELECT; } else if( 0 < dForce ){ dStyle |= CT_SELECT; } else if( 0 > dForce ){ dStyle &= ~CT_SELECT; } itLine->vcLine.at( iLetter ).mzStyle = dStyle; TRACE( TEXT("L[%d] D[%d] B[%d] f[0x%X]"), rdLine, dLtrDot, dByte, dStyle ); if( maeSty != dStyle ) // フラグ操作されてたら { if( CT_SELECT & dStyle ) gdSelByte += dByte; else gdSelByte -= dByte; if( 0 > gdSelByte ) gdSelByte = 0; // 0未満になったら本当はおかしい } return dLtrDot; // ドット数戻して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] rdLine 対象の行番号・絶対0インデックスか @param[in] iStart 開始文字位置0インデックス・この文字から開始・常時0でよい? @param[out] *pstTexts 文字とスタイルを格納するバッファを作るためのポインターへのポインター・NULLなら必要文字数だけ返す @param[out] pchLen 確保した文字数・NULLターミネータはノーカン・バイトじゃないぞ @param[out] pdFlag 文字列について・普通のとか連続空白とか・NULL不可 @return 文字列の使用ドット数 */ INT DocLineDataGetAlloc( INT rdLine, INT iStart, LPLETTER *pstTexts, PINT pchLen, PUINT pdFlag ) { INT iSize, i = 0, j, dotCnt; INT_PTR iCount, iLines; // 始点と終点を使えるようにする // −1なら末端 LINE_ITR itLine; iLines = DocNowFilePageLineCount( ); if( iLines <= rdLine ) return -1; itLine = gitFileIt->vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, rdLine ); iCount = itLine->vcLine.size( ); *pdFlag = 0; if( 0 == iCount ) // 文字列の中身がない { *pchLen = 0; dotCnt = 0; } else { if( iStart >= iCount ) return 0; // 通り過ぎた iSize = iCount - iStart; // 文字数を入れる // 色換えの必要があるところまでとか、一塊ずつで面倒見るように *pchLen = iSize; iSize++; // NULLターミネータの為に増やす if( !pstTexts ) return 0; // 入れるところないならここで終わる *pstTexts = (LPLETTER)malloc( iSize * sizeof(LETTER) ); if( !( *pstTexts ) ){ TRACE( TEXT("malloc error") ); return 0; } ZeroMemory( *pstTexts, iSize * sizeof(LETTER) ); dotCnt = 0; for( i = iStart, j = 0; iCount > i; i++, j++ ) { (*pstTexts)[j].cchMozi = itLine->vcLine.at( i ).cchMozi; (*pstTexts)[j].rdWidth = itLine->vcLine.at( i ).rdWidth; (*pstTexts)[j].mzStyle = itLine->vcLine.at( i ).mzStyle; dotCnt += itLine->vcLine.at( i ).rdWidth; } // 末端がspaceかどうか確認 if( iswspace( itLine->vcLine.at( iCount-1 ).cchMozi ) ) { *pdFlag |= CT_LASTSP; } } if( iLines - 1 > rdLine ) *pdFlag |= CT_RETURN; // 次の行があるなら改行 else *pdFlag |= CT_EOF; // ないならこの行末端がEOF // 改行の状態を確保 *pdFlag |= itLine->dStyle; return dotCnt; }
/*! 指定範囲に右揃え線を付ける @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; }
/*! ページ全体から、選択されている文字列を確保する・freeは呼んだ方でやる @param[in] bStyle 1ユニコードかシフトJISで、矩形かどうか @param[out] *pText 確保した領域を返す・ワイド文字かマルチ文字になる・NULLだと必要バイト数を返すのみ @param[out] *pstPt 選択範囲の行番号と開始ドット位置をメモリして返す・開放は呼んだほうでやる・NULLなら何もしない @return 確保したバイト数・NULLターミネータも含む */ INT DocSelectTextGetAlloc( UINT bStyle, LPVOID *pText, LPPOINT *pstPt ) { // 指定行の指定範囲をコピーするようにすればいい // SJISの場合は、ユニコード文字は&#ddddd;で確保される // もしかしたら&#xhhhh;かもしれない UINT_PTR iLines, i, j, iLetters; INT_PTR iSize, cchSz; INT d, k, m, iLn; BOOLEAN bNoSel; LPPOINT pstPoint = NULL; string srString; // ユニコード・シフトJISで確保 wstring wsString; LINE_ITR itLine; srString.clear( ); wsString.clear( ); // ページ全体の行数 iLines = DocNowFilePageLineCount( ); // 開始地点から開始 d = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineTop; k = (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineBottom; TRACE( TEXT("選択内容確保[%d - %d]"), d, k ); if( 0 > d ){ d = 0; } if( 0 > k ){ k = iLines - 1; } if( pstPt ) { iLn = k - d + 1; // 行の数 if( 0 < iLn ){ pstPoint = (LPPOINT)malloc( iLn * sizeof(POINT) ); } *pstPt = pstPoint; } itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, d ); for( m = 0, i = d; iLines > i; i++, m++, itLine++ ) { if( pstPoint ){ pstPoint[m].x = 0; pstPoint[m].y = i; } // 各行の文字数 iLetters = itLine->vcLine.size( ); bNoSel = TRUE; for( j = 0; iLetters > j; j++ ) { // 選択されている部分を文字列に確保 if( CT_SELECT & itLine->vcLine.at( j ).mzStyle ) { bNoSel = FALSE; if( bStyle & D_UNI ) wsString += itLine->vcLine.at( j ).cchMozi; else srString += string( itLine->vcLine.at( j ).acSjis ); } if( bNoSel && pstPt ) pstPoint[m].x += itLine->vcLine.at( j ).rdWidth; } if( bStyle & D_SQUARE ) // 矩形のときは容赦なく改行 { if( bStyle & D_UNI ) wsString += wstring( CH_CRLFW ); else srString += string( CH_CRLFA ); } else { // 改行が含まれていたらその分確保 if( CT_SELRTN & itLine->dStyle ) { if( bStyle & D_UNI ) wsString += wstring( CH_CRLFW ); else srString += string( CH_CRLFA ); } } // 選択範囲末端までイッたらおしまい if( (INT)i == (*gitFileIt).vcCont.at( gixFocusPage ).dSelLineBottom ) break; } if( bStyle & D_UNI ) // ユニコードである { cchSz = wsString.size( ) + 1; // NULLターミネータ分足す iSize = cchSz * sizeof(TCHAR); // ユニコードなのでバイト数は2倍である if( pText ) { *pText = (LPTSTR)malloc( iSize ); ZeroMemory( *pText, iSize ); StringCchCopy( (LPTSTR)(*pText), cchSz, wsString.c_str( ) ); } } else { iSize = srString.size( ) + 1; // NULLターミネータ分足す if( pText ) { *pText = (LPSTR)malloc( iSize ); ZeroMemory( *pText, iSize ); StringCchCopyA( (LPSTR)(*pText), iSize, srString.c_str( ) ); } } return iSize; }
/*! 行末文字を削除する。ただし空白だったら削除しない @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; }
/*! ページ全体の選択状態をON/OFFする @param[in] dForce 0无 +選択状態 ー選択解除 @return 全体文字数 */ INT DocPageSelStateToggle( INT dForce ) { UINT_PTR iLines, ln, iLetters, mz; UINT dStyle; INT iTotal, iDot, iWid; RECT inRect; LINE_ITR itLine; if( 0 == dForce ) return 0; // 0なら処理しない if( 0 > gixFocusPage ) return 0; // 特殊な状況下では処理しない iTotal = 0; iLines = DocNowFilePageLineCount( ); itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); for( ln = 0; iLines > ln; ln++, itLine++ ) { iDot = 0; // そこまでのドット数をため込む inRect.top = ln * LINE_HEIGHT; inRect.bottom = inRect.top + LINE_HEIGHT; iLetters = itLine->vcLine.size( ); // この行の文字数確認して // 壱文字ずつ、全部をチェキっていく for( mz = 0; iLetters > mz; mz++ ) { // 直前の状態 dStyle = itLine->vcLine.at( mz ).mzStyle; iWid = itLine->vcLine.at( mz ).rdWidth; inRect.left = iDot; inRect.right = iDot + iWid; if( 0 < dForce ) { itLine->vcLine.at( mz ).mzStyle |= CT_SELECT; if( !(dStyle & CT_SELECT) ){ ViewRedrawSetRect( &inRect ); } } else { itLine->vcLine.at( mz ).mzStyle &= ~CT_SELECT; if( dStyle & CT_SELECT ){ ViewRedrawSetRect( &inRect ); } } iDot += iWid; iTotal++; } // 壱行終わったら末尾状況確認。改行・本文末端に改行はない・選択のときのみ dStyle = itLine->dStyle; inRect.left = iDot; inRect.right = iDot + 20; // 改行描画エリア・大体これくらい if( 0 < dForce ) { if( iLines > ln+1 ) { itLine->dStyle |= CT_SELRTN; if( !(dStyle & CT_SELRTN) ){ ViewRedrawSetRect( &inRect ); } } } else { itLine->dStyle &= ~CT_SELRTN; if( dStyle & CT_SELRTN ){ ViewRedrawSetRect( &inRect ); } } } if( 0 < dForce ) // 頁全体のバイト数そのものか、非選択なので0 { DocSelRangeSet( 0, iLines - 1 ); DocPageParamGet( NULL, &gdSelByte ); } else { DocSelRangeSet( -1, -1 ); gdSelByte = 0; } DocSelectedByteStatus( ); // ViewRedrawSetLine( -1 ); // 画面表示更新 return iTotal; }
/*! 各行の末端から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; }
/*! 指定行のドット位置(キャレット位置)に壱文字追加する・この函数内ではアンドゥの面倒は見ない @param[in] nowDot 挿入するドット位置 @param[in] rdLine 対象の行番号・絶対0インデックスか @param[in] ch 追加したい文字 @return INT 追加した文字のドット数 */ INT DocInputLetter( INT nowDot, INT rdLine, TCHAR ch ) { INT_PTR iLetter, iCount, iLines; LETTER stLetter; LETR_ITR vcItr; LINE_ITR itLine; // アンドゥリドゥは呼んだところで #ifdef DO_TRY_CATCH try{ #endif if( 0 == ch ) { TRACE( TEXT("NULL文字が入った") ); return 0; } iLines = DocNowFilePageLineCount( ); if( iLines <= rdLine ) { TRACE( TEXT("OutOfRange 指定[%d] 行数[%d]"), rdLine, iLines ); return 0; } iLetter = DocLetterPosGetAdjust( &nowDot, rdLine, 0 ); // 今の文字位置を確認 itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, rdLine ); // 対象行までイテレートする // 文字数確認 iCount = itLine->vcLine.size( ); // データ作成 DocLetterDataCheck( &stLetter, ch ); // 指定行のドット位置(キャレット位置)に壱文字追加するとき if( iLetter >= iCount ) // 文字数同じなら末端に追加ということ { itLine->vcLine.push_back( stLetter ); } else // そうでないなら途中に追加 { vcItr = itLine->vcLine.begin( ); vcItr += iLetter; itLine->vcLine.insert( vcItr, stLetter ); } itLine->iDotCnt += stLetter.rdWidth; itLine->iByteSz += stLetter.mzByte; (*gitFileIt).vcCont.at( gixFocusPage ).dByteSz += stLetter.mzByte; // DocBadSpaceCheck( rdLine ); 呼んだところでまとめてやる #ifdef DO_TRY_CATCH } catch( exception &err ){ return ETC_MSG( err.what(), 0 ); } catch( ... ){ return ETC_MSG( ("etc error"), 0 ); } #endif return stLetter.rdWidth; }
/*! ページ全体を確保する・freeは呼んだ方でやる @param[in] bStyle 1ユニコードかシフトJIS @param[out] *pText 確保した領域を返す・ワイド文字かマルチ文字になる・NULLだと必要バイト数を返すのみ @return 確保したバイト数・NULLターミネータも含む */ INT DocPageTextAllGetAlloc( UINT bStyle, LPVOID *pText ) { // SJISの場合は、ユニコード文字は&#dddd;で確保される UINT_PTR iLines, i, iLetters, j; UINT_PTR cchSize; INT_PTR iSize; LPTSTR ptData; LPSTR pcStr; string srString; // ユニコード・シフトJISで確保 wstring wsString; LINE_ITR itLine; srString.clear( ); wsString.clear( ); if( gitFileIt->vcCont.at( gixFocusPage ).ptRawData ) // 生データ状態なら { ptData = (*gitFileIt).vcCont.at( gixFocusPage ).ptRawData; StringCchLength( ptData, STRSAFE_MAX_CCH, &cchSize ); if( bStyle & D_UNI ) // ユニコードである { iSize = (cchSize+1) * sizeof(TCHAR); // NULLターミネータ分足す if( pText ) { *pText = (LPTSTR)malloc( iSize ); ZeroMemory( *pText, iSize ); StringCchCopy( (LPTSTR)(*pText), cchSize, ptData ); } } else { pcStr = SjisEncodeAlloc( ptData ); if( pcStr ) { StringCchLengthA( pcStr, STRSAFE_MAX_CCH, &cchSize ); iSize = cchSize + 1; // NULLターミネータ分足す if( pText ){ *pText = pcStr; } else{ FREE( pcStr ); } } } } else { // ページ全体の行数 iLines = DocNowFilePageLineCount( ); itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); for( i = 0; iLines > i; i++, itLine++ ) { // 各行の文字数 iLetters = itLine->vcLine.size( ); if( bStyle & D_UNI ) { for( j = 0; iLetters > j; j++ ) { wsString += itLine->vcLine.at( j ).cchMozi; } if( iLines > (i+1) ) wsString += wstring( CH_CRLFW ); } else { for( j = 0; iLetters > j; j++ ) { srString += string( itLine->vcLine.at( j ).acSjis ); } if( iLines > (i+1) ) srString += string( CH_CRLFA ); } } if( bStyle & D_UNI ) // ユニコードである { cchSize = wsString.size( ) + 1; // NULLターミネータ分足す iSize = cchSize * sizeof(TCHAR); // ユニコードなのでバイト数は2倍である if( pText ) { *pText = (LPTSTR)malloc( iSize ); ZeroMemory( *pText, iSize ); StringCchCopy( (LPTSTR)(*pText), cchSize, wsString.c_str( ) ); } } else { iSize = srString.size( ) + 1; // NULLターミネータ分足す if( pText ) { *pText = (LPSTR)malloc( iSize ); ZeroMemory( *pText, iSize ); StringCchCopyA( (LPSTR)(*pText), iSize, srString.c_str( ) ); } } } return iSize; }
/*! 全体又は選択範囲を右に寄せる @param[in] pXdot 今のドット位置を受けて戻す @param[in] dLine 今の行数 @return HRESULT 終了状態コード */ HRESULT DocRightSlide( PINT pXdot, INT dLine ) { UINT_PTR iLines; INT iTop, iBottom, i; INT dSliDot, dRitDot, dPaDot, dInBgn; INT dMozi, dLefDot, dAdDot; BOOLEAN bFirst = TRUE; LPTSTR ptBuffer = NULL; LINE_ITR itLine; TRACE( TEXT("右寄せ") ); // 右寄せ限界確認 dSliDot = InitParamValue( INIT_LOAD, VL_RIGHT_SLIDE, 790 ); // 範囲確認 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 ); // 選択範囲無くなる dRitDot = DocPageMaxDotGet( iTop, iBottom ); // 一番右のドット確認 dPaDot = dSliDot - dRitDot; if( 0 > dPaDot ) { NotifyBalloonExist( TEXT("はみ出してるみたい"), TEXT("失敗"), NIIF_ERROR ); return E_FAIL; } itLine = (*gitFileIt).vcCont.at( gixFocusPage ).ltPage.begin(); std::advance( itLine, iTop ); // 位置合わせ for( i = iTop; iBottom >= i; i++, itLine++ ) { dAdDot = dPaDot; // 行頭の開き状態を確認 dLefDot = LayerHeadSpaceCheck( &(itLine->vcLine), &dMozi ); if( 0 < dLefDot ) { dAdDot += dLefDot; // 手前に空白があるなら、その分含めてずらし用スペースを計算 DocRangeDeleteByMozi( 0, i, 0, dMozi, &bFirst ); bFirst = FALSE; } // 先頭からうめちゃう dInBgn = 0; ptBuffer = DocPaddingSpaceWithPeriod( dAdDot, NULL, NULL, NULL, TRUE ); DocInsertString( &dInBgn, &i, NULL, ptBuffer, 0, bFirst ); bFirst = FALSE; FREE(ptBuffer); ViewRedrawSetLine( i ); } // キャレット位置適当に調整 *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; }
/*! 指定行のドット位置(キャレット位置)で改行する @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; }