Index: sakura_core/COpe.h =================================================================== --- sakura_core/COpe.h (リビジョン 50499) +++ sakura_core/COpe.h (リビジョン 62789) @@ -11,12 +11,12 @@ Please contact the copyright holder to use this code for other purpose. */ -class COpe; - #ifndef _COPE_H_ #define _COPE_H_ +class COpe; class CMemory;// 2002/2/10 aroka +#include "basis/SakuraBasis.h" // CLogicRange // アンドゥバッファ用 操作コード @@ -25,6 +25,8 @@ OPE_INSERT = 1, OPE_DELETE = 2, OPE_MOVECARET = 3, + OPE_SELECT, + OPE_SELECT_L }; @@ -86,9 +88,37 @@ } }; +template +class TSelectOpe +: public COpe +{ +public: + TSelectOpe(const RangeT& selectRange, bool boxSelecting, const CLogicPoint& caretPos) + : COpe(OPE), selectRange(selectRange), boxSelecting(boxSelecting) + { + this->m_ptCaretPos_PHY_After = this->m_ptCaretPos_PHY_Before = caretPos; + } + RangeT selectRange; // fromと toの関係。fromは選択始点。toは fromより前にも後ろにもなりうる。 + bool boxSelecting; +}; +/** 選択範囲/矩形選択範囲とキャレット位置 + SelectOpeが保存するのは選択範囲の*変化*ではない。主役は挿入や削除という操作で、 + その前後の付加的静的情報として存在する。 + 1.Insert/Deleteの直前のものを保存し、アンドゥのときに復元できるようにする。 + 2.矩形選択入力/インデントのように選択範囲がクリアされないInsertの場合は、操作直 + 後にも保存してリドゥにそなえる。 + 3.キャレットが選択範囲の終点にいないことが全選択で起こる。 +*/ +typedef TSelectOpe CSelectOpe; +/** CSelectOpeの CLayoutRange版。矩形選択にどうぞ。 + Logic単位で位置情報を保存すると、レイアウトの変化には強くなるが + 文字のない部分を選択することもある矩形選択では情報が失われる。 + 矩形選択のときはレイアウト単位で記録した方がうまくいくことが多いかも。 +*/ +typedef TSelectOpe CSelectLOpe; Index: sakura_core/CViewCommander_New.cpp =================================================================== --- sakura_core/CViewCommander_New.cpp (リビジョン 50499) +++ sakura_core/CViewCommander_New.cpp (リビジョン 62789) @@ -60,8 +60,33 @@ CLayoutPoint ptCaretPos_After; + const struct // OPE_SELECTと OPE_SELECT_Lのためのサブルーチン。 + { + CEditView* view; + void operator()(const CLayoutRange& selectRange, bool boxSelecting) const + { + this->view->GetSelectionInfo().DisableSelectArea(false); + this->view->GetCaret().MoveCursor(selectRange.GetFrom(), false); + this->view->GetSelectionInfo().BeginSelectArea(); + this->view->GetSelectionInfo().SetBoxSelect(boxSelecting); + this->view->GetCaret().MoveCursor(selectRange.GetTo(), false); + this->view->GetSelectionInfo().ChangeSelectAreaByCurrentCursor(this->view->GetCaret().GetCaretLayoutPos()); + } + } RestoreSelectArea = {this->m_pCommanderView}; + /* 各種モードの取り消し */ - Command_CANCEL_MODE(); + // Command_CANCEL_MODE(); + /* + Command_CANCEL_MODE()は主に範囲選択のクリアと選択ロックの解除を行う。 + 範囲選択のクリア(再描画あり)を行うと CSelect(L)Opeで範囲選択を復元したときにちらつく。 + かといって、CSelect(L)Opeが含まれていないときは従来通りクリアを行いたい。 + どうするか。再描画なしでクリアする。方法は Command_CANCEL_MODEに redrawフラグを渡すこともできるが + Command_CANCEL_MODEの中身をコピペしてフラグだけ書き換えることにする。 + */ + if( m_pCommanderView->GetSelectionInfo().IsTextSelected() ){ + m_pCommanderView->GetSelectionInfo().DisableSelectArea(false); + } + m_pCommanderView->GetSelectionInfo().m_bSelectingLock = false; m_pCommanderView->m_bDoing_UndoRedo = TRUE; /* アンドゥ・リドゥの実行中か */ @@ -135,7 +160,23 @@ /* カーソルを移動 */ GetCaret().MoveCursor( ptCaretPos_After, false ); break; + case OPE_SELECT: /* OPE_INSERTや OPE_DELETE前後の選択範囲とキャレット位置を復元する。 */ + { + CSelectOpe* pSelectOpe = dynamic_cast(pcOpe); + + CLayoutRange selectRange; + this->GetDocument()->m_cLayoutMgr.LogicToLayout(pSelectOpe->selectRange, &selectRange); + + RestoreSelectArea(selectRange, pSelectOpe->boxSelecting); + // キャレット位置の復元は COpe共通のタスクらしいのでここではやらない。 + break; } + case OPE_SELECT_L: /* OPE_INSERTや OPE_DELETE前後の選択範囲とキャレット位置を復元する。 */ + CSelectLOpe* pSelectOpe = dynamic_cast(pcOpe); + RestoreSelectArea(pSelectOpe->selectRange, pSelectOpe->boxSelecting); + // キャレット位置の復元は COpe共通のタスクらしいのでここではやらない。 + break; + } GetDocument()->m_cLayoutMgr.LogicToLayout( pcOpe->m_ptCaretPos_PHY_Before, @@ -217,9 +258,33 @@ CLayoutPoint ptCaretPos_To; CLayoutPoint ptCaretPos_After; + const struct // OPE_SELECTと OPE_SELECT_Lのためのサブルーチン。 + { + CEditView* view; + void operator()(const CLayoutRange& selectRange, bool boxSelecting) const + { + this->view->GetSelectionInfo().DisableSelectArea(false); + this->view->GetCaret().MoveCursor(selectRange.GetFrom(), false); + this->view->GetSelectionInfo().BeginSelectArea(); + this->view->GetSelectionInfo().SetBoxSelect(boxSelecting); + this->view->GetCaret().MoveCursor(selectRange.GetTo(), false); + this->view->GetSelectionInfo().ChangeSelectAreaByCurrentCursor(this->view->GetCaret().GetCaretLayoutPos()); + } + } RestoreSelectArea = {this->m_pCommanderView}; /* 各種モードの取り消し */ - Command_CANCEL_MODE(); + //Command_CANCEL_MODE(); + /* + Command_CANCEL_MODE()は主に範囲選択のクリアと選択ロックの解除を行う。 + 範囲選択のクリア(再描画あり)を行うと CSelect(L)Opeで範囲選択を復元したときにちらつく。 + かといって、CSelect(L)Opeが含まれていないときは従来通りクリアを行いたい。 + どうするか。再描画なしでクリアする。方法は Command_CANCEL_MODEに redrawフラグを渡すこともできるが + Command_CANCEL_MODEの中身をコピペしてフラグだけ書き換えることにする。 + */ + if( m_pCommanderView->GetSelectionInfo().IsTextSelected() ){ + m_pCommanderView->GetSelectionInfo().DisableSelectArea(false); + } + m_pCommanderView->GetSelectionInfo().m_bSelectingLock = false; m_pCommanderView->m_bDoing_UndoRedo = TRUE; /* アンドゥ・リドゥの実行中か */ @@ -292,7 +357,23 @@ break; case OPE_MOVECARET: break; + case OPE_SELECT: /* OPE_INSERTや OPE_DELETE前後の選択範囲とキャレット位置を復元する。 */ + { + CSelectOpe* pSelectOpe = dynamic_cast(pcOpe); + + CLayoutRange selectRange; + this->GetDocument()->m_cLayoutMgr.LogicToLayout(pSelectOpe->selectRange, &selectRange); + + RestoreSelectArea(selectRange, pSelectOpe->boxSelecting); + // キャレット位置の復元は COpe共通のタスクらしいのでここではやらない。 + break; } + case OPE_SELECT_L: /* OPE_INSERTや OPE_DELETE前後の選択範囲とキャレット位置を復元する。 */ + CSelectLOpe* pSelectOpe = dynamic_cast(pcOpe); + RestoreSelectArea(pSelectOpe->selectRange, pSelectOpe->boxSelecting); + // キャレット位置の復元は COpe共通のタスクらしいのでここではやらない。 + break; + } GetDocument()->m_cLayoutMgr.LogicToLayout( pcOpe->m_ptCaretPos_PHY_After, &ptCaretPos_After Index: sakura_core/CViewCommander.cpp =================================================================== --- sakura_core/CViewCommander.cpp (リビジョン 50499) +++ sakura_core/CViewCommander.cpp (リビジョン 62789) @@ -4923,15 +4923,23 @@ m_pCommanderView->SetDrawSwitch(false); // 2002.01.25 hor /* 矩形範囲選択中か */ if( m_pCommanderView->GetSelectionInfo().IsBoxSelecting() ){ - // From Here 2001.12.03 hor /* 上書モードのときは選択範囲削除 */ if( ! m_pCommanderView->IsInsMode() /* Oct. 2, 2005 genta */){ sSelectOld = GetSelect(); m_pCommanderView->DeleteData( FALSE ); GetSelect() = sSelectOld; m_pCommanderView->GetSelectionInfo().SetBoxSelect(true); + } else { + /* + UNDO/REDOのための記録(キャレット位置・選択状態) ※主にUNDOで役に立つ + 範囲選択をクリアされる前に記録する。 + */ + if(! m_pCommanderView->m_bDoing_UndoRedo){ + const CViewSelect& selInfo = this->m_pCommanderView->GetSelectionInfo(); + CLayoutRange selectLayoutRange = selInfo.m_sSelect.GetFrom() == selInfo.m_sSelectBgn.GetFrom() ? selInfo.m_sSelect : CLayoutRange(selInfo.m_sSelect.GetTo(), selInfo.m_sSelect.GetFrom()); + GetOpeBlk()->AppendOpe(new CSelectLOpe(selectLayoutRange, true, this->GetCaret().GetCaretLogicPos())); + } } - // To Here 2001.12.03 hor /* 2点を対角とする矩形を求める */ CLayoutRange rcSel; @@ -5074,18 +5082,16 @@ GetCaret().MoveCursor( rcSel.GetFrom(), TRUE ); GetCaret().m_nCaretPosX_Prev = GetCaret().GetCaretLayoutPos().GetX2(); - if( !m_pCommanderView->m_bDoing_UndoRedo ){ /* アンドゥ・リドゥの実行中か */ - /* 操作の追加 */ - GetOpeBlk()->AppendOpe( - new CMoveCaretOpe( - GetCaret().GetCaretLogicPos(), // 操作前のキャレット位置 - GetCaret().GetCaretLogicPos() // 操作後のキャレット位置 - ) - ); - } GetSelect().SetFrom(rcSel.GetFrom()); //範囲選択開始位置 GetSelect().SetTo(rcSel.GetTo()); //範囲選択終了位置 m_pCommanderView->GetSelectionInfo().SetBoxSelect(true); + + /* + UNDO/REDOのための記録(キャレット位置・選択状態) ※主にREDOで役に立つ + */ + if(! m_pCommanderView->m_bDoing_UndoRedo){ + GetOpeBlk()->AppendOpe(new CSelectLOpe(GetSelect(), true, GetCaret().GetCaretLogicPos())); + } } else if( GetSelect().IsLineOne() ){ // 通常選択(1行内) if( INDENT_NONE != eIndent && !bSoftTab ){ @@ -5113,6 +5119,18 @@ sSelectOld.GetToPointer()->y++; } + /* + UNDO/REDOのための記録(キャレット位置・選択状態) ※主にUNDOで役に立つ + 範囲選択をクリアされる前に記録する。 + */ + if(! m_pCommanderView->m_bDoing_UndoRedo){ + CLogicRange selectLogicRange; + const CViewSelect& selInfo = this->m_pCommanderView->GetSelectionInfo(); + CLayoutRange selectLayoutRange = selInfo.m_sSelect.GetFrom() == selInfo.m_sSelectBgn.GetFrom() ? selInfo.m_sSelect : CLayoutRange(selInfo.m_sSelect.GetTo(), selInfo.m_sSelect.GetFrom()); + this->GetDocument()->m_cLayoutMgr.LayoutToLogic(selectLayoutRange, &selectLogicRange); + GetOpeBlk()->AppendOpe(new CSelectOpe(selectLogicRange, false, this->GetCaret().GetCaretLogicPos())); + } + // 現在の選択範囲を非選択状態に戻す */ m_pCommanderView->GetSelectionInfo().DisableSelectArea( FALSE ); @@ -5149,18 +5167,19 @@ GetSelect() = sSelectOld; - // From Here 2001.12.03 hor GetCaret().MoveCursor( GetSelect().GetTo(), TRUE ); GetCaret().m_nCaretPosX_Prev = GetCaret().GetCaretLayoutPos().GetX2(); - if( !m_pCommanderView->m_bDoing_UndoRedo ){ /* アンドゥ・リドゥの実行中か */ - GetOpeBlk()->AppendOpe( - new CMoveCaretOpe( - GetCaret().GetCaretLogicPos(), // 操作前のキャレット位置 - GetCaret().GetCaretLogicPos() // 操作後のキャレット位置 - ) - ); + + /* + UNDO/REDOのための記録(キャレット位置・選択状態) ※主にREDOで役に立つ + */ + if(! m_pCommanderView->m_bDoing_UndoRedo){ + CLogicRange selectLogicRange; + const CViewSelect& selInfo = this->m_pCommanderView->GetSelectionInfo(); + CLayoutRange selectLayoutRange = selInfo.m_sSelect.GetFrom() == selInfo.m_sSelectBgn.GetFrom() ? selInfo.m_sSelect : CLayoutRange(selInfo.m_sSelect.GetTo(), selInfo.m_sSelect.GetFrom()); + this->GetDocument()->m_cLayoutMgr.LayoutToLogic(selectLayoutRange, &selectLogicRange); + GetOpeBlk()->AppendOpe(new CSelectOpe(selectLogicRange, false, this->GetCaret().GetCaretLogicPos())); } - // To Here 2001.12.03 hor } /* 再描画 */ m_pCommanderView->SetDrawSwitch(true); // 2002.01.25 hor Index: sakura_core/view/CEditView_Command_New.cpp =================================================================== --- sakura_core/view/CEditView_Command_New.cpp (リビジョン 50499) +++ sakura_core/view/CEditView_Command_New.cpp (リビジョン 62789) @@ -436,13 +436,18 @@ if( GetSelectionInfo().IsTextSelected() ){ CWaitCursor cWaitCursor( this->GetHwnd() ); // 2002.02.05 hor if( !m_bDoing_UndoRedo ){ /* アンドゥ・リドゥの実行中か */ - /* 操作の追加 */ - m_pcOpeBlk->AppendOpe( - new CMoveCaretOpe( - GetCaret().GetCaretLogicPos(), // 操作前のキャレット位置 - GetCaret().GetCaretLogicPos() // 操作後のキャレット位置 - ) - ); + /* 操作の追加(選択範囲とキャレット位置の保存) */ + CLayoutRange selectLayoutRange = this->GetSelectionInfo().m_sSelect.GetFrom() == this->GetSelectionInfo().m_sSelectBgn.GetFrom() ? this->GetSelectionInfo().m_sSelect : CLayoutRange(this->GetSelectionInfo().m_sSelect.GetTo(), this->GetSelectionInfo().m_sSelect.GetFrom()); + if(this->GetSelectionInfo().IsBoxSelecting()) { + // 矩形選択のときは選択終点が改行より後ろにある場合にそなえてレイアウト座標で + // 選択範囲を保存する。レイアウトの変更には弱くなるので、折り返し桁を変更する頻度と + // 改行の後ろにカーソルを持って行く頻度のどちらが多いかの問題。 + m_pcOpeBlk->AppendOpe(new CSelectLOpe(selectLayoutRange, true, this->GetCaret().GetCaretLogicPos())); + } else { + CLogicRange selectLogicRange; + this->GetDocument()->m_cLayoutMgr.LayoutToLogic(selectLayoutRange, &selectLogicRange); + m_pcOpeBlk->AppendOpe(new CSelectOpe(selectLogicRange, false, this->GetCaret().GetCaretLogicPos())); + } } /* 矩形範囲選択中か */