C:\home\SVGCats_src\src\Undo.cpp
1|/*********************************************************************** 2| 1. <<< SVGCsts 用アンドゥバッファ (Undo) >>> 3|************************************************************************/ 4| 5|#include "mixer_precomp.h" /* Auto precompiled header, Look at mixer-... folder */ 6|// #pragma hdrstop 7| 8|#if defined(USES_MXP_AUTOINC) 9| #include "Undo.ah" /* Auto include header, Look at mixer-... folder */ 10|#endif 11| 12| 13| 14|/*-------------------------------------------------------------------------*/ 15|/* 2. <<<< ◆ (Undo_Buf) アンドゥバッファ >>>> */ 16|/*-------------------------------------------------------------------------*/ 17| 18| 19| 20|Undo_Buf::Undo_Buf() 21|{ 22| ListX_init( &m_Steps ); 23| m_Now = NULL; 24| m_Save = NULL; 25| m_MultiNum = 0; 26| m_MultiNest = 0; 27| 28| m_holdStrokes = NULL; 29| Undo_StrokeTable_init(); 30| 31| m_PageDelNum = 0; 32| ListX_init( &m_deletedPages ); 33| 34| ListX_init( &m_holds ); 35|} 36| 37| 38| 39|Undo_Buf::~Undo_Buf() 40|{ 41| Undo_Step_Com* step; 42| SVGCat_Page* page; 43| ListX_ElemX* pPrim; 44| 45| if ( m_holdStrokes != NULL ) m_holdStrokes->Release(); 46| 47| for ( ListX_forEach( &m_Steps, &step, Undo_Step_Com ) ) { 48| if ( step->typeID == Undo_PrimType ) { 49| Undo_Step* step2 = (Undo_Step*)step; 50| 51| if ( step2->before != NULL ) delete step2->before; 52| if ( step2->after != NULL ) delete step2->after; 53| if ( step2->before_z != NULL ) delete step2->before_z; 54| if ( step2->after_z != NULL ) delete step2->after_z; 55| } 56| else if ( step->typeID == Undo_InkType ) { 57| Undo_Step_Ink* step2 = (Undo_Step_Ink*)step; 58| 59| free( step2->stroke_id2s ); 60| if ( step2->op == Undo_Ink_Add || step2->op == Undo_Ink_Del ) 61| step2->boundingBox->Release(); 62| else if ( step2->op == Undo_Ink_ChgAttr ) { 63| free( step2->beforeAttr ); 64| free( step2->afterAttr ); 65| } 66| } 67| else if ( step->typeID == Undo_PageType ) { 68| Undo_Step_Page* step2 = (Undo_Step_Page*)step; 69| 70| if ( step2->beforeNum_start == step2->afterNum ) { 71| free( step2->beforeTitle ); 72| free( step2->afterTitle ); 73| } 74| } 75| } 76| 77| for ( ListX_forEach( &m_deletedPages, &page, SVGCat_Page ) ) { 78| for ( ListX_forEach( &page->prims, &pPrim, ListX_ElemX ) ) { 79| delete (CadPrim*)pPrim->p; 80| } 81| ListX_toEmptyDelete( &page->prims, ListX_ElemX, NULL ); 82| Variant_finish( &page->ink ); 83| } 84| ListX_finish2( &m_deletedPages, SVGCat_Page, NULL ); 85| 86| Undo_StrokeTable_finish(); 87| 88| ListX_finish2( &m_Steps, Undo_Step, NULL ); 89| ListX_finish2( &m_holds, ListX_ElemX, NULL ); 90|} 91| 92| 93| 94|void Undo_Buf::print( const char* title ) 95|{ 96| #ifndef ERRORS_CUT_DEBUG_TOOL 97|// ListX_ElemX* p; 98| Undo_Step_Com* sp; 99| int i; 100| 101|// for ( ListX_forEach( m_prims, &p, ListX_ElemX ) ) { 102|// ((CadPrim*)p->p)->print( title ); 103|// } 104| i = 0; 105| for ( ListX_forEach( &m_Steps, &sp, Undo_Step_Com ) ) { 106| if ( sp->typeID == Undo_PrimType ) { 107| Undo_Step* sp2 = (Undo_Step*)sp; 108| 109| Errors_printf( "%s[%d] Prim:", title, i ); 110| if ( sp2->before != NULL ) sp2->before->print( " before" ); 111| if ( sp2->after != NULL ) sp2->after->print( " after" ); 112| } 113| else if ( sp->typeID == Undo_InkType ) { 114| Undo_Step_Ink* sp2 = (Undo_Step_Ink*)sp; 115| 116| Errors_printf( "%s[%d] Ink:", title, i ); 117| } 118| else { 119| Undo_Step_Page* sp2 = (Undo_Step_Page*)sp; 120| 121| Errors_printf( "%s[%d] Page: beforeNum_start=%d, beforeNum_over=%d, afterNum=%d", 122| title, i, sp2->beforeNum_start, sp2->beforeNum_over, sp2->afterNum ); 123| } 124| i++; 125| } 126| #endif 127|} 128| 129| 130| 131|/*********************************************************************** 132| 2-1. <<< [Undo_Buf::StartMulti] 複数図形の開始を通知する >>> 133|************************************************************************/ 134|void Undo_Buf::StartMulti() 135|{ 136| m_MultiNest ++; 137| if ( m_MultiNest == 1 ) 138| m_MultiNum = 1; 139|} 140| 141| 142| 143|/*********************************************************************** 144| 2-2. <<< [Undo_Buf::AllocNewStep] 図形に対する操作の前後を記録する >>> 145|【引数】 146| ・CadPrim* before; 操作前の図形のコピー(new したもの) 147| ・CadPrim* after; 操作後の図形のコピー(new したもの) 148| ・CadPrim* before_f; before の1つ手前(next)の図形のコピー(new したもの,NULL可) 149| ・CadPrim* after_f; after の1つ手前(next)の図形のコピー(new したもの,NULL可) 150| ・int iPage; 操作対象が所属するページの番号(背景がないときは0〜) 151|【補足】 152|・各図形の操作関数の中で本関数を呼び出します。 153|・before, after には、new したオブジェクト指定してください。 154|・before, adter に指定したオブジェクトは、Undo_Buf が delete します。 155|・before_f, after_f は、Z オーダーに変化が無ければ、両方に NULL を 156| 指定できます。 157|・複数同時の操作を記録するときは、手前の図形から順番に本関数を呼び出してください。 158|************************************************************************/ 159|void Undo_Buf::AllocNewStep( CadPrim* before, CadPrim* after, 160| CadPrim* before_f, CadPrim* after_f, int iPage ) 161|{ 162| CSVGCatApp* app = (CSVGCatApp*)AfxGetApp(); 163| Undo_Step* step; 164| 165| #ifndef NDEBUG 166| { 167| ListX_ElemX* p; 168| 169| for ( ListX_forEach( &app->m_file.m_pages, &p, ListX_ElemX ) ) { 170| ASSERT( before == NULL || before != (CadPrim*)p->p ); 171| ASSERT( after == NULL || after != (CadPrim*)p->p ); 172| ASSERT( before_f == NULL || before_f != (CadPrim*)p->p ); 173| ASSERT( after_f == NULL || after_f != (CadPrim*)p->p ); 174| } 175| } 176| #endif 177| 178| if ( before != NULL ) before->SetBInUndoBuf( true ); 179| if ( after != NULL ) after->SetBInUndoBuf( true ); 180| if ( before_f != NULL ) before_f->SetBInUndoBuf( true ); 181| if ( after_f != NULL ) after_f->SetBInUndoBuf( true ); 182| 183| /* 値に変化が無いときは記録しない */ 184| if ( before != NULL && after != NULL && before->isEqual( after ) ) { 185| if ( ( before_f == NULL && after_f != NULL ) || 186| ( before_f != NULL && after_f == NULL ) || 187| ( before_f != NULL && after_f != NULL && ! before_f->isEqual( after_f ) ) ); 188| else { 189| delete before; 190| delete after; 191| if ( before_f != NULL ) delete before_f; 192| if ( after_f != NULL ) delete after_f; 193| return; 194| } 195| } 196| 197| /* 記録の開始位置より後のステップを削除する */ 198| ClearAfterSteps(); 199| 200| /* ステップを記録する */ 201| step = ListX_addFirstMalloc( &m_Steps, Undo_Step ); 202| step->typeID = Undo_PrimType; 203| step->bFirstOfMulti = ( m_MultiNum <= 1 ); 204| step->iPage = iPage; 205| 206| step->before = before; 207| step->after = after; 208| step->before_z = before_f; 209| step->after_z = after_f; 210| step->page = ListX_get( &app->m_file.m_pages, iPage, SVGCat_Page ); 211| 212| m_Now = (Undo_Step_Com*)step; 213| if ( m_MultiNum >= 1 ) m_MultiNum++; 214| 215| 216| #if ERRORS_DEBUG_FALSE 217| Errors_startPool(); 218| Errors_printf( "AllocNewStep" ); 219| if ( before != NULL ) before->print("before"); 220| if ( after != NULL ) after->print("after"); 221| if ( before_f != NULL ) before_f->print("before_z"); 222| if ( after_f != NULL ) after_f->print("after_z"); 223| Errors_endPool(); 224| #endif 225|} 226| 227| 228| 229|/*********************************************************************** 230| 2-3. <<< [Undo_Buf::AllocNewStep_Ink] インクに対する操作の内容を記録する(移動、拡大) >>> 231|【引数】 232| ・int op; 操作内容(Undo_Ink_Move, Undo_Ink_Resize) 233| ・IInkDisp* ink; IInkOverlay 等に所属するインク(所有しない) 234| ・IInkStrokes* strokes; ink に所属している操作対象となるストローク(所有しない) 235| ・int dx, dy; 移動量か、拡大縮小矩形サイズの変化量 236| ・int iPage; 操作対象が所属するページID(常に0〜) 237|************************************************************************/ 238|void Undo_Buf::AllocNewStep_Ink( int op, IInkDisp* ink, IInkStrokes* strokes, 239| int dx, int dy, int iPage ) 240|{ 241| Undo_Step_Ink* step; 242| 243| ASSERT( op == Undo_Ink_Move || op == Undo_Ink_Resize ); 244| 245| /* 値に変化が無いときは記録しない */ 246| if ( dx == 0 && dy == 0 ) return; 247| 248| /* 記録の開始位置より後のステップを削除する */ 249| ClearAfterSteps(); 250| 251| /* ステップを記録する */ 252| step = ListX_addFirstMalloc( &m_Steps, Undo_Step_Ink ); 253| step->typeID = Undo_InkType; 254| step->bFirstOfMulti = ( m_MultiNum <= 1 ); 255| step->iPage = iPage; 256| step->op = op; 257| step->stroke_id2s = Undo_StrokeTable_lookupId2( strokes, NULL ); 258| step->dx = dx; 259| step->dy = dy; 260| 261| m_Now = (Undo_Step_Com*)step; 262| if ( m_MultiNum >= 1 ) m_MultiNum++; 263|} 264| 265| 266| 267|/*********************************************************************** 268| 2-4. <<< [Undo_Buf::AllocNewStep_Ink2] インクに対する操作の内容を記録する(生成、削除) >>> 269|【引数】 270| ・int op; 操作内容(Undo_Ink_Add, Undo_Ink_Del) 271| ・IInkDisp* ink; IInkOverlay 等に所属するインク(所有しない) 272| ・IInkStrokes* strokes; ink に所属している操作対象となるストローク(所有しない) 273| ・bool bPlus; 前回と同じ操作なら、ストロークを追加するかどうか。 274| ・int iPage; 操作対象が所属するページID(常に0〜) 275|【補足】 276|・bPlus==true のとき、前回の操作ステップと同じ操作(生成/削除)なら、そのステップに 277| 更にストロークを追加します。同じ操作ではないときは、新しいステップを追加します。 278|************************************************************************/ 279|void Undo_Buf::AllocNewStep_Ink2( int op, IInkDisp* ink, IInkStrokes* strokes, 280| bool bPlus, int iPage ) 281|{ 282| Undo_Step_Ink* step; 283| Undo_Step_Ink* _m_now2 = NULL; 284| IInkRectangle* rect; 285| HRESULT hr; 286| 287| ASSERT( op == Undo_Ink_Add || op == Undo_Ink_Del ); 288| 289| if ( m_Now != NULL && m_Now->typeID == Undo_InkType ) 290| _m_now2 = (Undo_Step_Ink*)m_Now; 291| 292| 293| /* 前回のステップにストロークを追加する */ 294| if ( bPlus && _m_now2 != NULL && _m_now2->op == op && iPage == _m_now2->iPage ) { 295| step = _m_now2; 296| 297| if ( op == Undo_Ink_Add ) 298| step->stroke_id2s = Undo_StrokeTable_addId2( strokes, step->stroke_id2s ); 299| else /* Undo_Ink_Del */ 300| step->stroke_id2s = Undo_StrokeTable_lookupId2( strokes, step->stroke_id2s ); 301| 302| hr = strokes->GetBoundingBox( IBBM_Default, &rect ); 303| if ( hr != 0 ) error(); 304| 305| hr = step->strokesInk->AddStrokesAtRectangle( strokes, rect ); 306| if ( hr != 0 ) error(); 307| 308| hr = step->boundingBox->Release(); step->boundingBox = NULL; 309| 310| hr = step->strokesInk->GetBoundingBox( IBBM_Default, &step->boundingBox ); 311| if ( hr != 0 ) error(); 312| 313| hr = rect->Release(); rect = NULL; 314| } 315| 316| /* 新しいステップを記録する */ 317| else { 318| 319| /* 記録の開始位置より後のステップを削除する */ 320| ClearAfterSteps(); 321| 322| /* ステップを記録する */ 323| step = ListX_addFirstMalloc( &m_Steps, Undo_Step_Ink ); 324| step->typeID = Undo_InkType; 325| step->bFirstOfMulti = ( m_MultiNum <= 1 ); 326| step->iPage = iPage; 327| step->op = op; 328| if ( op == Undo_Ink_Add ) 329| step->stroke_id2s = Undo_StrokeTable_addId2( strokes, NULL ); 330| else /* Undo_Ink_Del */ 331| step->stroke_id2s = Undo_StrokeTable_lookupId2( strokes, NULL ); 332| 333| hr = ink->ExtractStrokes( strokes, IEF_CopyFromOriginal, &step->strokesInk ); 334| if ( hr != 0 ) error(); 335| 336| hr = strokes->GetBoundingBox( IBBM_Default, &step->boundingBox ); 337| if ( hr != 0 ) error(); 338| } 339| 340| m_Now = (Undo_Step_Com*)step; 341| if ( m_MultiNum >= 1 ) m_MultiNum++; 342|} 343| 344| 345| 346|/*********************************************************************** 347| 2-5. <<< [Undo_Buf::AllocNewStep_Ink3] インクに対する操作の内容を記録する(属性の変更) >>> 348|【引数】 349| ・int op; 操作内容(Undo_Ink_ChgAttr) 350| ・IInkStrokes* strokes; 変更を行った後のストロークの集合 351| ・Undo_InkAttr* before; 変更前のインクの属性(所有する、→補足) 352| ・Undo_InkAttr* after; 変更後のインクの属性(所有する、→補足) 353| ・int iPage; 操作対象が所属するページID(常に0〜) 354|【補足】 355|・before, after は、Undo_InkAttr_new で取得できます。 356|************************************************************************/ 357|void Undo_Buf::AllocNewStep_Ink3( int op, IInkStrokes* strokes, 358| Undo_InkAttr* before, Undo_InkAttr* after, int iPage ) 359|{ 360| Undo_Step_Ink* step; 361| 362| ASSERT( op == Undo_Ink_ChgAttr ); 363| 364| /* 記録の開始位置より後のステップを削除する */ 365| ClearAfterSteps(); 366| 367| /* ステップを記録する */ 368| step = ListX_addFirstMalloc( &m_Steps, Undo_Step_Ink ); 369| step->typeID = Undo_InkType; 370| step->bFirstOfMulti = ( m_MultiNum <= 1 ); 371| step->iPage = iPage; 372| step->op = op; 373| step->stroke_id2s = Undo_StrokeTable_lookupId2( strokes, NULL ); 374| 375| step->beforeAttr = before; 376| step->afterAttr = after; 377| 378| m_Now = (Undo_Step_Com*)step; 379| if ( m_MultiNum >= 1 ) m_MultiNum++; 380|} 381| 382| 383| 384|/*********************************************************************** 385| 2-6. <<< [Undo_Buf::AllocNewStep_Page] ページに対する操作の前後を記録する >>> 386|【引数】 387| ・int beforeNum_start; 操作対象の最初のページ番号(新規作成 = -1) 388| ・int beforeNum_over; 操作対象の最後の次のページ番号(→補足) 389| ・int beforeType; 移動前の位置、1=次の兄弟はいない、2=孤独な子、0=その他(非移動=-1) 390| ・int afterNum; 移動後や生成するページ番号(削除 = -1) 391| ・int redoBaseNum; 移動先: 0=afterNumの前、正=Redoでこのページの後に入れる、負=Redo でこのページの子に入れる 392| ・SVGCat_Page* delPage_list; 削除したページのリスト、被所有、(非削除=NULL) 393| ・int 返り値; ページ削除ID(非削除=-1) 394|【補足】 395|・各図形の操作関数の中で本関数を呼び出します。 396|・新規作成のとき、beforeNum_over は、CSVGCatApp::NewPage の pos になります。 397|・beforeType == 1 のとき、beforeNum_over は、前の兄弟のページ番号になります。 398|・delPage_first のリストの最後までが削除対象になります。 399|************************************************************************/ 400|int Undo_Buf::AllocNewStep_Page( int beforeNum_start, int beforeNum_over, 401| int beforeType, int afterNum, int redoBaseNum, SVGCat_Page* delPage_list ) 402|{ 403| CSVGCatApp* app = (CSVGCatApp*)AfxGetApp(); 404| Undo_Step_Page* step; 405| 406| /* 記録の開始位置より後のステップを削除する */ 407| ClearAfterSteps(); 408| 409| /* ステップを記録する */ 410| step = ListX_addFirstMalloc( &m_Steps, Undo_Step_Page ); 411| step->typeID = Undo_PageType; 412| step->bFirstOfMulti = ( m_MultiNum <= 1 ); 413| step->iPage = -1; 414| 415| step->beforeNum_start = beforeNum_start; 416| step->beforeNum_over = beforeNum_over; 417| step->afterNum = afterNum; 418| step->firstPage = delPage_list; 419| if ( afterNum == -1 ) step->iFirstPage = m_PageDelNum; 420| else if ( beforeNum_start != -1 ) { 421| step->beforeType = beforeType; 422| step->redoBaseNum = redoBaseNum; 423| } 424| if ( afterNum == -1 ) m_PageDelNum += beforeNum_over - beforeNum_start; 425| 426| if ( delPage_list != NULL ) 427| ListX_insertSet( &m_deletedPages, NULL, delPage_list ); 428| 429| m_Now = (Undo_Step_Com*)step; 430| if ( m_MultiNum >= 1 ) m_MultiNum++; 431| 432| 433| #if ERRORS_DEBUG_FALSE 434| Errors_startPool(); 435| Errors_printf( "AllocNewStep Page" ); 436| Errors_printf( " before_start=%d, before_over=%d, after=%d", 437| beforeNum_start, beforeNum_over, afterNum ); 438| Errors_endPool(); 439| #endif 440| 441| return step->iFirstPage; 442|} 443| 444| 445| 446|/*********************************************************************** 447| 2-7. <<< [Undo_Buf::AllocNewStep_PageTitle] ページタイトルの編集前後を記録する >>> 448|【引数】 449| ・int pageNum; ページ番号 450| ・char* before; 編集前のページタイトル 451| ・char* after; 編集後のページタイトル 452|************************************************************************/ 453|int Undo_Buf::AllocNewStep_PageTitle( int pageNum, const char* before, const char* after ) 454|{ 455| CSVGCatApp* app = (CSVGCatApp*)AfxGetApp(); 456| Undo_Step_Page* step; 457| 458| /* 記録の開始位置より後のステップを削除する */ 459| ClearAfterSteps(); 460| 461| /* ステップを記録する */ 462| step = ListX_addFirstMalloc( &m_Steps, Undo_Step_Page ); 463| step->typeID = Undo_PageType; 464| step->bFirstOfMulti = ( m_MultiNum <= 1 ); 465| step->iPage = -1; 466| 467| step->beforeNum_start = pageNum; 468| step->beforeNum_over = pageNum+1; 469| step->afterNum = pageNum; 470| step->beforeTitle = (char*)malloc( (strlen( before ) + 1) * sizeof(char) ); 471| strcpy( step->beforeTitle, before ); 472| step->afterTitle = (char*)malloc( (strlen( after ) + 1) * sizeof(char) ); 473| strcpy( step->afterTitle, after ); 474| 475| m_Now = (Undo_Step_Com*)step; 476| if ( m_MultiNum >= 1 ) m_MultiNum++; 477| 478| return step->iFirstPage; 479|} 480| 481| 482| 483| 484|/*********************************************************************** 485| 2-8. <<< [Undo_Buf::EndMulti] 複数図形の終了を通知する >>> 486|************************************************************************/ 487|void Undo_Buf::EndMulti() 488|{ 489| m_MultiNest --; 490| if ( m_MultiNest == 0 ) 491| m_MultiNum = 0; 492|} 493| 494| 495| 496|/*********************************************************************** 497| 2-9. <<< [Undo_Buf::ClearAfterSteps] アンドゥバッファの現在位置より後を削除する >>> 498|************************************************************************/ 499|void Undo_Buf::ClearAfterSteps() 500|{ 501| CSVGCatApp* app = (CSVGCatApp*)AfxGetApp(); 502| Undo_Step_Com* step; 503| Undo_Step_Com* nextStep; 504| 505| for ( step = ListX_getFirst( &m_Steps, Undo_Step_Com ) ; ; ) { 506| if ( m_Now == step ) break; 507| if ( m_Save == step ) m_Save = NULL; 508| 509| if ( step->typeID == Undo_PrimType ) { 510| Undo_Step* step2 = (Undo_Step*)step; 511| 512| if ( step2->before != NULL ) { 513| step2->before->AdjustLinks( &step2->page->prims ); /* ポインタを有効にしてから */ 514| delete step2->before; 515| } 516| if ( step2->after != NULL ) { 517| step2->after->AdjustLinks( &step2->page->prims ); 518| delete step2->after; 519| } 520| if ( step2->before_z != NULL ) { 521| step2->before_z->AdjustLinks( &step2->page->prims ); 522| delete step2->before_z; 523| } 524| if ( step2->after_z != NULL ) { 525| step2->after_z->AdjustLinks( &step2->page->prims ); 526| delete step2->after_z; 527| } 528| } 529| else if ( step->typeID == Undo_InkType ) { 530| Undo_Step_Ink* step2 = (Undo_Step_Ink*)step; 531| 532| free( step2->stroke_id2s ); 533| if ( step2->op == Undo_Ink_Add || step2->op == Undo_Ink_Del ) 534| step2->boundingBox->Release(); 535| else if ( step2->op == Undo_Ink_ChgAttr ) { 536| free( step2->beforeAttr ); 537| free( step2->afterAttr ); 538| } 539| } 540| else if ( step->typeID == Undo_PageType ) { 541| Undo_Step_Page* step2 = (Undo_Step_Page*)step; 542| 543| if ( step2->beforeNum_start == step2->afterNum ) { 544| free( step2->beforeTitle ); 545| free( step2->afterTitle ); 546| } 547| } 548| 549| nextStep = ListX_Elem_getNextT( step, Undo_Step_Com ); 550| ListX_removeFree( &m_Steps, step ); 551| step = nextStep; 552| } 553| 554|} 555| 556| 557| 558|/*********************************************************************** 559| 2-10. <<< [Undo_Buf::ClearAll] アンドゥバッファのすべて削除する >>> 560|************************************************************************/ 561|void Undo_Buf::ClearAll() 562|{ 563| SVGCat_Page* page; 564| ListX_ElemX* pPrim; 565| 566| m_Now = NULL; 567| ClearAfterSteps(); 568| Undo_StrokeTable_clear(); 569| m_PageDelNum = 0; 570| 571| for ( ListX_forEach( &m_deletedPages, &page, SVGCat_Page ) ) { 572| for ( ListX_forEach( &page->prims, &pPrim, ListX_ElemX ) ) { 573| delete (CadPrim*)pPrim->p; 574| } 575| ListX_toEmptyDelete( &page->prims, ListX_ElemX, NULL ); 576| Variant_finish( &page->ink ); 577| } 578| ListX_toEmptyDelete( &m_deletedPages, SVGCat_Page, NULL ); 579|} 580| 581| 582| 583|/*********************************************************************** 584| 2-11. <<< [Undo_Buf::Undo] アンドゥをする >>> 585|【補足】 586|・集合操作のとき、アンドゥもリドゥも奥から順番に処理されます 587|************************************************************************/ 588|#if ERRORS_DEBUG_FALSE 589| #define UNDO_TRACE 590|#endif 591| 592|ListX* Undo_Buf::Undo( CMainFrame* frame, IInkDisp* ink ) 593|{ 594| CSVGCatApp* app = (CSVGCatApp*)AfxGetApp(); 595| Undo_Step_Com* now; /* Undo する前の m_Now を退避した値 */ 596| bool bContinue; 597| ListX_ElemX* p; 598| ListX* prims = NULL; 599| 600| if ( m_Now == NULL ) /*重いとき、まれにツールボタンの更新が遅れるため。*/ 601| return NULL; 602| 603| #ifdef UNDO_TRACE 604| print(""); 605| #endif 606| 607| now = m_Now; 608| 609| do { 610| if ( m_Now == NULL ) break; 611| 612| if ( now == m_Now ) { 613| ListX_toEmptyDelete( &m_holds, ListX_ElemX, NULL ); 614| } 615| 616| if ( m_Now->typeID == Undo_PageType ) prims = NULL; 617| else prims = &ListX_get( &app->m_file.m_pages, now->iPage, SVGCat_Page )->prims; 618| 619| #ifdef UNDO_TRACE 620| if ( prims != NULL ) app->printPrims( prims, "a" ); 621| Errors_printf( "Undo[%d]", ListX_getI( &m_Steps, m_Now ) ); 622| #endif 623| 624| 625| /* 図形に対する操作のアンドゥをする */ 626| if ( m_Now->typeID == Undo_PrimType ) { 627| Undo_Step* _m_now2 = (Undo_Step*)m_Now; 628| Undo_Step* now2 = (Undo_Step*)now; 629| 630| 631| #ifdef UNDO_TRACE 632| Errors_startPool(); 633| Errors_printf( "Undo" ); 634| if ( _m_now2->before != NULL ) _m_now2->before->print("before"); 635| if ( _m_now2->after != NULL ) _m_now2->after->print("after"); 636| if ( _m_now2->before_z != NULL ) _m_now2->before_z->print("before_z"); 637| if ( _m_now2->after_z != NULL ) _m_now2->after_z->print("after_z"); 638| Errors_endPool(); 639| #endif 640| 641| 642| /* 削除のアンドゥをする */ 643| if ( _m_now2->after == NULL ) { 644| p = ListX_addFirstMalloc( &m_holds, ListX_ElemX ); 645| p->p = Undo_Uty_createPrim( _m_now2->before, _m_now2->before_z, prims ); 646| } 647| 648| else { 649| 650| /* 生成のアンドゥをする */ 651| if ( _m_now2->before == NULL ) { 652| Undo_Uty_deletePrim( _m_now2->after, prims ); 653| } 654| 655| /* 編集のアンドゥをする */ 656| else { 657| CadPrim* prim; 658| 659| prim = Undo_Uty_editPrim( _m_now2->after, _m_now2->before, 660| _m_now2->after_z, _m_now2->before_z, prims, 661| &ListX_get( &app->m_file.m_pages, now->iPage, SVGCat_Page )->canvas ); 662| if ( prim != NULL ) { 663| p = ListX_addFirstMalloc( &m_holds, ListX_ElemX ); 664| p->p = prim; 665| } 666| } 667| } 668| } 669| 670| 671| /* インクに対する操作のアンドゥをする */ 672| else if ( m_Now->typeID == Undo_InkType ) { 673| Undo_Step_Ink* _m_now2 = (Undo_Step_Ink*)m_Now; 674| IInkStrokes* strokes; 675| HRESULT hr; 676| 677| switch ( _m_now2->op ) { 678| case Undo_Ink_Move: 679| strokes = Undo_StrokeTable_lookupStrokes( _m_now2->stroke_id2s, ink ); 680| hr = strokes->Move( (float)-_m_now2->dx, (float)-_m_now2->dy ); 681| if ( hr != 0 ) error(); 682| Undo_StrokeTable_updateStrokes( _m_now2->stroke_id2s, strokes ); 683| if ( m_holdStrokes != NULL ) m_holdStrokes->Release(); 684| m_holdStrokes = strokes; 685| break; 686| 687| case Undo_Ink_Resize: { 688| IInkRectangle* rect; 689| RECT rectX; 690| 691| strokes = Undo_StrokeTable_lookupStrokes( _m_now2->stroke_id2s, ink ); 692| hr = strokes->GetBoundingBox( IBBM_Default, &rect ); if ( hr != 0 ) error(); 693| hr = rect->get_Data( &rectX ); if ( hr != 0 ) error(); 694| 695| rectX.right -= _m_now2->dx; rectX.bottom -= _m_now2->dy; 696| hr = rect->put_Data( rectX ); if ( hr != 0 ) error(); 697| 698| hr = strokes->ScaleToRectangle( rect ); if ( hr != 0 ) error(); 699| 700| hr = rect->Release(); 701| Undo_StrokeTable_updateStrokes( _m_now2->stroke_id2s, strokes ); 702| if ( m_holdStrokes != NULL ) m_holdStrokes->Release(); 703| m_holdStrokes = strokes; 704| break; 705| } 706| 707| case Undo_Ink_Add: 708| strokes = Undo_StrokeTable_lookupStrokes( _m_now2->stroke_id2s, ink ); 709| Undo_StrokeTable_updateStrokes( _m_now2->stroke_id2s, strokes ); 710| hr = ink->DeleteStrokes( strokes ); 711| if ( hr != 0 ) error(); 712| if ( m_holdStrokes != NULL ) m_holdStrokes->Release(); 713| m_holdStrokes = NULL; 714| strokes->Release(); 715| break; 716| 717| case Undo_Ink_Del: 718| if ( m_holdStrokes != NULL ) m_holdStrokes->Release(); 719| m_holdStrokes = Undo_Uty_addStrokes( ink, _m_now2->strokesInk, _m_now2->boundingBox ); 720| Undo_StrokeTable_updateStrokes( _m_now2->stroke_id2s, m_holdStrokes ); 721| break; 722| 723| case Undo_Ink_ChgAttr: 724| strokes = Undo_StrokeTable_lookupStrokes( _m_now2->stroke_id2s, ink ); 725| Undo_InkAttr_resume( _m_now2->beforeAttr, strokes ); 726| Undo_StrokeTable_updateStrokes( _m_now2->stroke_id2s, strokes ); 727| if ( m_holdStrokes != NULL ) m_holdStrokes->Release(); 728| m_holdStrokes = strokes; 729| break; 730| } 731| } 732| 733| 734| /* ページに対する操作のアンドゥをする */ 735| else if ( m_Now->typeID == Undo_PageType ) { 736| CTreeCtrl* tree = &frame->m_Left->GetTreeCtrl(); 737| Undo_Step_Page* _m_now2 = (Undo_Step_Page*)m_Now; 738| int nPage = _m_now2->beforeNum_over - _m_now2->beforeNum_start; 739| int pageNum = app->m_file.m_CurrentPageNum; 740| int i, m; 741| SVGCat_Page* page; 742| SVGCat_Page* prevPage; 743| SVGCat_Page* nextPage; 744| SVGCat_Page* parentPage; 745| char path[_MAX_PATH]; 746| 747| app->ChgPage( &app->m_file, -1 ); 748| 749| 750| /* ページタイトルの編集をアンドゥする */ 751| if ( _m_now2->beforeNum_start == _m_now2->afterNum ) { 752| HTREEITEM item; 753| 754| page = ListX_get( &app->m_file.m_pages, _m_now2->afterNum - 755| app->m_file.m_StartPageNum, SVGCat_Page ); 756| 757| StrX_cpy( page->title, _m_now2->beforeTitle, sizeof(page->title) ); 758| 759| frame->ChgPage( _m_now2->afterNum ); 760| item = tree->GetSelectedItem(); 761| tree->SetItemText( item, page->title ); 762| } 763| 764| 765| /* ページ新規作成のアンドゥをする */ 766| else if ( _m_now2->beforeNum_start == -1 ) { 767| HTREEITEM item, prev; 768| int addPos = _m_now2->beforeNum_over; 769| 770| page = ListX_get( &app->m_file.m_pages, _m_now2->afterNum - 771| app->m_file.m_StartPageNum, SVGCat_Page ); 772| 773| 774| /* ツリーの項目を削除するための準備をする(開いていないツリー項目を開く) */ 775| frame->ChgPage( _m_now2->afterNum ); 776| item = tree->GetSelectedItem(); 777| if ( addPos == 0 ) { 778| prev = tree->GetPrevSiblingItem( item ); /* 新規ボタンを押したときに表示されていたページ */ 779| pageNum = SVGCat_File_getPageNum( &app->m_file, page->prev ); 780| } 781| else if ( addPos == 1 ) { 782| prev = tree->GetParentItem( item ); 783| pageNum = _m_now2->afterNum - 1; 784| } 785| else { 786| prev = tree->GetNextSiblingItem( item ); 787| pageNum = _m_now2->afterNum; 788| } 789| 790| 791| /* 削除するページより後のページのインク一時ファイルを移動する */ 792| remove( app->GetInkWorkFilePath( app->m_file.m_id, _m_now2->afterNum, IRO_MaskPen ) ); 793| remove( app->GetInkWorkFilePath( app->m_file.m_id, _m_now2->afterNum, IRO_CopyPen ) ); 794| m = SVGCat_File_getMaxPageNum( &app->m_file ); 795| for ( i = _m_now2->afterNum; i < m ; i++ ) { 796| strcpy( path, app->GetInkWorkFilePath( app->m_file.m_id, i, IRO_MaskPen ) ); 797| MoveFile( app->GetInkWorkFilePath( app->m_file.m_id, i+1, IRO_MaskPen ), path ); 798| strcpy( path, app->GetInkWorkFilePath( app->m_file.m_id, i, IRO_CopyPen ) ); 799| MoveFile( app->GetInkWorkFilePath( app->m_file.m_id, i+1, IRO_CopyPen ), path ); 800| } 801| 802| /* ページ間リンクを調節する */ 803| prevPage = page->prev; 804| nextPage = page->next; 805| parentPage = page->parent; 806| if ( addPos == 0 ) { /* 下 */ 807| prevPage->next = nextPage; 808| if ( nextPage != NULL ) nextPage->prev = prevPage; 809| } 810| else if ( addPos == 1 ) { /* 子 */ 811| parentPage->firstChild = nextPage; 812| if ( nextPage != NULL ) nextPage->prev = prevPage; 813| } 814| else { /* 上 */ 815| if ( prevPage != NULL ) prevPage->next = nextPage; 816| else if ( parentPage != NULL ) parentPage->firstChild = nextPage; 817| nextPage->prev = prevPage; 818| } 819| 820| 821| /* ページを削除する */ 822| ListX_remove( &app->m_file.m_pages, page ); 823| ListX_addLast( &m_deletedPages, page ); 824| 825| 826| /* ツリーの項目を削除する */ 827| tree->Select( prev, TVGN_CARET ); 828| tree->DeleteItem( item ); 829| } 830| 831| 832| /* ページ削除のアンドゥをする */ 833| else if ( _m_now2->afterNum == -1 ) { 834| SVGCat_Page* pageBk; 835| SVGCat_Page* pos = ListX_get( &app->m_file.m_pages, _m_now2->beforeNum_start - 836| app->m_file.m_StartPageNum, SVGCat_Page ); 837| HTREEITEM item, parent; 838| bool bInsertAfter; /* 選択状態にしたページ項目より後に追加するかどうか */ 839| int maxPageNum = SVGCat_File_getMaxPageNum( &app->m_file ); 840| 841| /* ツリーに項目を追加するための準備をする(開いていないツリー項目を開く) */ 842| bInsertAfter = ( _m_now2->beforeNum_start > maxPageNum ); 843| if ( bInsertAfter ) { 844| frame->ChgPage( maxPageNum ); 845| pageNum = maxPageNum + 1; 846| } 847| else { 848| frame->ChgPage( _m_now2->beforeNum_start ); 849| pageNum = _m_now2->beforeNum_start; 850| } 851| 852| 853| /* 図形を元に戻す */ 854| page = ListX_removeSet( &m_deletedPages, _m_now2->firstPage, NULL, SVGCat_Page ); 855| ListX_insertSet( &app->m_file.m_pages, pos, page ); 856| m_PageDelNum -= nPage; 857| 858| 859| /* 戻すページより後のページのインク一時ファイルを移動する */ 860| m = SVGCat_File_getMaxPageNum( &app->m_file ); 861| for ( i = m; i >= _m_now2->beforeNum_start; i-- ) { 862| strcpy( path, app->GetInkWorkFilePath( app->m_file.m_id, nPage+i, IRO_MaskPen ) ); 863| MoveFile( app->GetInkWorkFilePath( app->m_file.m_id, i, IRO_MaskPen ), path ); 864| strcpy( path, app->GetInkWorkFilePath( app->m_file.m_id, nPage+i, IRO_CopyPen ) ); 865| MoveFile( app->GetInkWorkFilePath( app->m_file.m_id, i, IRO_CopyPen ), path ); 866| } 867| 868| /* インク一時ファイルを元に戻す */ 869| for ( i = 0; i < nPage; i++ ) { 870| strcpy( path, app->GetInkWorkFilePath( app->m_file.m_id, _m_now2->beforeNum_start+i, IRO_MaskPen ) ); 871| MoveFile( app->GetInkWorkFilePath( app->m_file.m_id, 10000+_m_now2->iFirstPage+i, IRO_MaskPen ), path ); 872| strcpy( path, app->GetInkWorkFilePath( app->m_file.m_id, _m_now2->beforeNum_start+i, IRO_CopyPen ) ); 873| MoveFile( app->GetInkWorkFilePath( app->m_file.m_id, 10000+_m_now2->iFirstPage+i, IRO_CopyPen ), path ); 874| } 875| 876| 877| /* ページ間リンクを調節する */ 878| prevPage = _m_now2->firstPage->prev; 879| nextPage = _m_now2->firstPage->next; 880| parentPage = _m_now2->firstPage->parent; 881| if ( prevPage != NULL ) prevPage->next = _m_now2->firstPage; 882| else if ( parentPage != NULL ) parentPage->firstChild = _m_now2->firstPage; 883| if ( nextPage != NULL ) nextPage->prev = _m_now2->firstPage; 884| 885| 886| /* ツリーに項目を追加する */ 887| pageBk = page->next; page->next = NULL; 888| item = tree->GetSelectedItem(); 889| if ( page->next == NULL && page->prev == NULL ) { 890| parent = ( bInsertAfter ? item : tree->GetPrevSiblingItem( item ) ); 891| item = TVI_FIRST; 892| } 893| else { 894| if ( bInsertAfter ) { 895| for ( parent = tree->GetParentItem( item ); ; parent = tree->GetParentItem( parent ) ) { 896| if ( parent == NULL ) { ASSERT( parentPage == NULL ); break; } 897| if ( (SVGCat_Page*)tree->GetItemData( parent ) == parentPage ) break; 898| } 899| for ( item = tree->GetChildItem( parent ); 900| tree->GetNextSiblingItem( item ) != NULL; 901| item = tree->GetNextSiblingItem( item ) ); 902| } 903| else { 904| parent = tree->GetParentItem( item ); 905| item = tree->GetPrevSiblingItem( item ); 906| } 907| } 908| item = frame->LoadTree( tree, page, parent, item ); 909| page->next = pageBk; 910| 911| tree->Select( item, TVGN_CARET ); 912| } 913| 914| 915| /* ページ移動のアンドゥをする */ 916| else { 917| HTREEITEM srcItem, dstItem; 918| int nPage = _m_now2->beforeNum_over - _m_now2->beforeNum_start; 919| 920| if ( _m_now2->beforeType == 1 ) { 921| frame->ChgPage( _m_now2->afterNum ); srcItem = tree->GetSelectedItem(); 922| frame->ChgPage( _m_now2->beforeNum_over ); dstItem = tree->GetSelectedItem(); 923| } 924| else if ( _m_now2->beforeNum_start < _m_now2->afterNum ) { 925| frame->ChgPage( _m_now2->afterNum - nPage ); srcItem = tree->GetSelectedItem(); 926| frame->ChgPage( _m_now2->beforeNum_start - (_m_now2->beforeType != 0) ); 927| dstItem = tree->GetSelectedItem(); 928| } 929| else { 930| frame->ChgPage( _m_now2->afterNum ); srcItem = tree->GetSelectedItem(); 931| frame->ChgPage( _m_now2->beforeNum_over - (_m_now2->beforeType != 0) ); 932| dstItem = tree->GetSelectedItem(); 933| } 934| 935| frame->MovePage( srcItem, dstItem, _m_now2->beforeType == 1, _m_now2->beforeType == 2, false ); 936| 937| pageNum = _m_now2->beforeNum_start; 938| } 939| 940| 941| app->ChgPage( &app->m_file, pageNum ); 942| 943| #ifdef UNDO_TRACE 944| app->printPages( "Undo" ); 945| #endif 946| } 947| 948| bContinue = ! m_Now->bFirstOfMulti; 949| 950| /* アンドゥバッファを更新する */ 951| m_Now = ListX_Elem_getNextT( m_Now, Undo_Step_Com ); 952| 953| #ifdef UNDO_TRACE 954| if ( prims != NULL ) app->printPrims( prims, "b" ); 955| #endif 956| 957| } while ( m_Now != NULL && bContinue ); 958| 959| 960| /* リンクのつなぎなおしと、リンクしているハンドルの移動をする */ 961| if ( prims != NULL ) Relink( prims ); 962| 963| #ifdef UNDO_TRACE 964| if ( prims != NULL ) app->printPrims( prims, "c" ); 965| #endif 966| 967| /* ページ管理と同期を取る */ 968| if ( app->m_file.m_CurrentPageNum == now->iPage + app->m_file.m_StartPageNum && 969| now->typeID != Undo_PageType ) { 970| SVGCat_Page* page = ListX_get( &app->m_file.m_pages, now->iPage, SVGCat_Page ); 971| 972| SVGCat_File_loadPage( &app->m_file, page ); 973| } 974| 975| return prims; 976|} 977| 978| 979| 980|/*********************************************************************** 981| 2-12. <<< [Undo_Buf::IsAbleUndo] アンドゥできるかどうかを返す >>> 982|************************************************************************/ 983|bool Undo_Buf::IsAbleUndo() 984|{ 985| return ( m_Now != NULL ); 986|} 987| 988| 989| 990|/*********************************************************************** 991| 2-13. <<< [Undo_Buf::GetNextUndoPageNum] 次にアンドゥするものがあるページ番号を返す >>> 992|************************************************************************/ 993|int Undo_Buf::GetNextUndoPageNum() 994|{ 995| CSVGCatApp* app = (CSVGCatApp*)AfxGetApp(); 996| 997| /* ページに対する操作の対象となるページ番号を返す */ 998| if ( m_Now->typeID == Undo_PageType ) { 999| Undo_Step_Page* _m_now2 = (Undo_Step_Page*)m_Now; 1000| 1001| if ( _m_now2->beforeNum_start == -1 ) 1002| return _m_now2->afterNum; 1003| else if ( _m_now2->afterNum == -1 ) 1004| return -1; 1005| else { 1006| if ( _m_now2->afterNum <= _m_now2->beforeNum_start ) 1007| return _m_now2->afterNum; 1008| else 1009| return _m_now2->afterNum - ( _m_now2->beforeNum_over - _m_now2->beforeNum_start ); 1010| } 1011| } 1012| 1013| /* その他の操作の対象となるページ番号を返す */ 1014| else { 1015| if ( m_Now == NULL || m_Now->iPage == -1 ) return -1; 1016| else return m_Now->iPage + app->m_file.m_StartPageNum; 1017| } 1018|} 1019| 1020| 1021| 1022|/*********************************************************************** 1023| 2-14. <<< [Undo_Buf::Redo] リドゥをする >>> 1024|【補足】 1025|・集合操作のとき、アンドゥもリドゥも奥から順番に処理されます 1026|************************************************************************/ 1027|#if ERRORS_DEBUG_FALSE 1028| #define REDO_TRACE 1029|#endif 1030| 1031|ListX* Undo_Buf::Redo( CMainFrame* frame, IInkDisp* ink ) 1032|{ 1033| CSVGCatApp* app = (CSVGCatApp*)AfxGetApp(); 1034| Undo_Step_Com* prev; 1035| Undo_Step_Com* prev2; 1036| Undo_Step_Com* step; 1037| bool bContinue; 1038| ListX_ElemX* p; 1039| ListX* prims = NULL; 1040| 1041| if ( m_Now == ListX_getFirst( &m_Steps, Undo_Step_Com ) ) return NULL; 1042| 1043| #ifdef REDO_TRACE 1044| print(""); 1045| #endif 1046| 1047| /* アンドゥする情報のある位置 prev を取得する */ 1048| prev = NULL; prev2 = NULL; 1049| for ( ListX_forEach( &m_Steps, &step, Undo_Step_Com ) ) { 1050| if ( step == m_Now ) break; 1051| if ( step->bFirstOfMulti ) { prev2 = prev; prev = step; } 1052| } 1053| if ( prev2 == NULL ) prev = ListX_getFirst( &m_Steps, Undo_Step_Com ); 1054| else prev = ListX_Elem_getNextT( prev2, Undo_Step_Com ); 1055| 1056| 1057| /* アンドゥバッファを更新する */ 1058| ListX_toEmptyDelete( &m_holds, ListX_ElemX, NULL ); 1059| m_Now = prev; 1060| 1061| 1062| do { 1063| 1064| if ( prims == NULL ) { 1065| if ( m_Now->typeID == Undo_PageType ) prims = NULL; 1066| else prims = &ListX_get( &app->m_file.m_pages, m_Now->iPage, SVGCat_Page )->prims; 1067| } 1068| 1069| #ifdef REDO_TRACE 1070| if ( prims != NULL ) app->printPrims(prims,"a"); 1071| Errors_printf( "Redo[%d]", ListX_getI( &m_Steps, prev ) ); 1072| #endif 1073| 1074| /* 図形に対する操作のアンドゥをする */ 1075| if ( prev->typeID == Undo_PrimType ) { 1076| Undo_Step* now2 = (Undo_Step*)m_Now; 1077| Undo_Step* prev2 = (Undo_Step*)prev; 1078| 1079| /* 生成のリドゥをする */ 1080| if ( prev2->before == NULL ) { 1081| p = ListX_addFirstMalloc( &m_holds, ListX_ElemX ); 1082| p->p = Undo_Uty_createPrim( prev2->after, prev2->after_z, prims ); 1083| } 1084| 1085| else { 1086| 1087| /* 削除のリドゥをする */ 1088| if ( prev2->after == NULL ) { 1089| Undo_Uty_deletePrim( prev2->before, prims ); 1090| } 1091| 1092| /* 編集のリドゥをする */ 1093| else { 1094| CadPrim* prim; 1095| 1096| prim = Undo_Uty_editPrim( prev2->before, prev2->after, 1097| prev2->before_z, prev2->after_z, prims, 1098| &ListX_get( &app->m_file.m_pages, now2->iPage, SVGCat_Page )->canvas ); 1099| if ( prim != NULL ) { 1100| p = ListX_addFirstMalloc( &m_holds, ListX_ElemX ); 1101| p->p = prim; 1102| } 1103| } 1104| } 1105| } 1106| 1107| 1108| /* インクに対する操作のリドゥをする */ 1109| else if ( prev->typeID == Undo_InkType ) { 1110| Undo_Step_Ink* prev2 = (Undo_Step_Ink*)prev; 1111| IInkStrokes* strokes; 1112| HRESULT hr; 1113| 1114| switch ( prev2->op ) { 1115| case Undo_Ink_Move: 1116| strokes = Undo_StrokeTable_lookupStrokes( prev2->stroke_id2s, ink ); 1117| hr = strokes->Move( (float)prev2->dx, (float)prev2->dy ); 1118| if ( hr != 0 ) error(); 1119| Undo_StrokeTable_updateStrokes( prev2->stroke_id2s, strokes ); 1120| if ( m_holdStrokes != NULL ) m_holdStrokes->Release(); 1121| m_holdStrokes = strokes; 1122| break; 1123| 1124| case Undo_Ink_Resize: { 1125| IInkRectangle* rect; 1126| RECT rectX; 1127| 1128| strokes = Undo_StrokeTable_lookupStrokes( prev2->stroke_id2s, ink ); 1129| hr = strokes->GetBoundingBox( IBBM_Default, &rect ); if ( hr != 0 ) error(); 1130| hr = rect->get_Data( &rectX ); if ( hr != 0 ) error(); 1131| 1132| rectX.right += prev2->dx; rectX.bottom += prev2->dy; 1133| hr = rect->put_Data( rectX ); if ( hr != 0 ) error(); 1134| 1135| hr = strokes->ScaleToRectangle( rect ); if ( hr != 0 ) error(); 1136| 1137| hr = rect->Release(); 1138| Undo_StrokeTable_updateStrokes( prev2->stroke_id2s, strokes ); 1139| if ( m_holdStrokes != NULL ) m_holdStrokes->Release(); 1140| m_holdStrokes = strokes; 1141| break; 1142| } 1143| 1144| case Undo_Ink_Add: 1145| if ( m_holdStrokes != NULL ) m_holdStrokes->Release(); 1146| m_holdStrokes = Undo_Uty_addStrokes( ink, prev2->strokesInk, prev2->boundingBox ); 1147| Undo_StrokeTable_updateStrokes( prev2->stroke_id2s, m_holdStrokes ); 1148| break; 1149| 1150| case Undo_Ink_Del: 1151| strokes = Undo_StrokeTable_lookupStrokes( prev2->stroke_id2s, ink ); 1152| Undo_StrokeTable_updateStrokes( prev2->stroke_id2s, strokes ); 1153| hr = ink->DeleteStrokes( strokes ); 1154| if ( hr != 0 ) error(); 1155| if ( m_holdStrokes != NULL ) m_holdStrokes->Release(); 1156| strokes->Release(); 1157| m_holdStrokes = NULL; 1158| break; 1159| 1160| case Undo_Ink_ChgAttr: 1161| strokes = Undo_StrokeTable_lookupStrokes( prev2->stroke_id2s, ink ); 1162| Undo_InkAttr_resume( prev2->afterAttr, strokes ); 1163| Undo_StrokeTable_updateStrokes( prev2->stroke_id2s, strokes ); 1164| if ( m_holdStrokes != NULL ) m_holdStrokes->Release(); 1165| m_holdStrokes = strokes; 1166| break; 1167| } 1168| } 1169| 1170| 1171| /* ページに対する操作のリドゥをする */ 1172| else if ( prev->typeID == Undo_PageType ) { 1173| Undo_Step_Page* prev2 = (Undo_Step_Page*)prev; 1174| int nPage = prev2->beforeNum_over - prev2->beforeNum_start; 1175| int pageNum = app->m_file.m_CurrentPageNum; 1176| int i, m; 1177| CTreeCtrl* tree = &frame->m_Left->GetTreeCtrl(); 1178| SVGCat_Page* page; 1179| SVGCat_Page* prevPage; 1180| SVGCat_Page* nextPage; 1181| SVGCat_Page* parentPage; 1182| char path[_MAX_PATH]; 1183| 1184| app->ChgPage( &app->m_file, -1 ); 1185| 1186| 1187| /* ページタイトルの編集をアンドゥする */ 1188| if ( prev2->beforeNum_start == prev2->afterNum ) { 1189| HTREEITEM item; 1190| 1191| page = ListX_get( &app->m_file.m_pages, prev2->afterNum - 1192| app->m_file.m_StartPageNum, SVGCat_Page ); 1193| 1194| StrX_cpy( page->title, prev2->afterTitle, sizeof(page->title) ); 1195| 1196| frame->ChgPage( prev2->afterNum ); 1197| item = tree->GetSelectedItem(); 1198| tree->SetItemText( item, page->title ); 1199| } 1200| 1201| 1202| /* ページ新規作成のリドゥをする */ 1203| else if ( prev2->beforeNum_start == -1 ) { 1204| HTREEITEM item, parent; 1205| int maxPageNum = SVGCat_File_getMaxPageNum( &app->m_file ); 1206| int addPos = prev2->beforeNum_over; 1207| SVGCat_Page* pos = ListX_get( &app->m_file.m_pages, prev2->afterNum - 1208| app->m_file.m_StartPageNum, SVGCat_Page ); 1209| SVGCat_Page* pageBk; 1210| 1211| 1212| page = ListX_getLast( &m_deletedPages, SVGCat_Page ); 1213| 1214| 1215| /* ツリーに項目を追加するための準備をする(開いていないツリー項目を開く) */ 1216| if ( addPos == 0 ) { 1217| frame->ChgPage( SVGCat_File_getPageNum( &app->m_file, page->prev ) ); 1218| } 1219| else if ( addPos == 1 ) { 1220| frame->ChgPage( prev2->afterNum - 1 ); 1221| } 1222| else { 1223| frame->ChgPage( prev2->afterNum ); 1224| } 1225| pageNum = prev2->afterNum; 1226| 1227| 1228| /* ページを追加する */ 1229| ListX_remove( &m_deletedPages, page ); 1230| ListX_insert( &app->m_file.m_pages, pos, page ); 1231| 1232| 1233| /* 戻すページより後のページのインク一時ファイルを移動する */ 1234| m = SVGCat_File_getMaxPageNum( &app->m_file ); 1235| for ( i = m - 1; i >= pageNum; i-- ) { 1236| strcpy( path, app->GetInkWorkFilePath( app->m_file.m_id, i+1, IRO_MaskPen ) ); 1237| MoveFile( app->GetInkWorkFilePath( app->m_file.m_id, i, IRO_MaskPen ), path ); 1238| strcpy( path, app->GetInkWorkFilePath( app->m_file.m_id, i+1, IRO_CopyPen ) ); 1239| MoveFile( app->GetInkWorkFilePath( app->m_file.m_id, i, IRO_CopyPen ), path ); 1240| } 1241| 1242| /* 空のインク一時ファイルを新規作成する */ 1243| { 1244| FILE* f; 1245| 1246| f = FileX_open( app->GetInkWorkFilePath( app->m_file.m_id, prev2->afterNum, IRO_MaskPen ), "w" ); 1247| fclose( f ); 1248| f = FileX_open( app->GetInkWorkFilePath( app->m_file.m_id, prev2->afterNum, IRO_CopyPen ), "w" ); 1249| fclose( f ); 1250| } 1251| 1252| 1253| /* ページ間リンクを調節する */ 1254| prevPage = page->prev; 1255| nextPage = page->next; 1256| parentPage = page->parent; 1257| if ( addPos == 0 ) { /* 下 */ 1258| prevPage->next = page; 1259| if ( nextPage != NULL ) nextPage->prev = page; 1260| } 1261| else if ( addPos == 1 ) { /* 子 */ 1262| parentPage->firstChild = page; 1263| if ( nextPage != NULL ) nextPage->prev = page; 1264| } 1265| else { /* 上 */ 1266| if ( prevPage != NULL ) prevPage->next = page; 1267| else if ( parentPage != NULL ) parentPage->firstChild = page; 1268| nextPage->prev = page; 1269| } 1270| 1271| 1272| /* ツリーに項目を追加する */ 1273| pageBk = page->next; page->next = NULL; 1274| item = tree->GetSelectedItem(); 1275| if ( addPos == 0 ) { /* 下 */ 1276| parent = tree->GetParentItem( item ); 1277| item = frame->LoadTree( tree, page, parent, item ); 1278| } 1279| else if ( addPos == 1 ) { /* 子 */ 1280| item = frame->LoadTree( tree, page, item, TVI_FIRST ); 1281| } 1282| else { /* 上 */ 1283| parent = tree->GetParentItem( item ); 1284| item = tree->GetPrevSiblingItem( item ); 1285| if ( item == NULL ) item = TVI_FIRST; 1286| item = frame->LoadTree( tree, page, parent, item ); 1287| } 1288| page->next = pageBk; 1289| 1290| tree->Select( item, TVGN_CARET ); 1291| } 1292| 1293| 1294| /* ページ削除のリドゥをする */ 1295| else if ( prev2->afterNum == -1 ) { 1296| SVGCat_Page* last = ListX_get( &app->m_file.m_pages, prev2->beforeNum_over - 1 - 1297| app->m_file.m_StartPageNum, SVGCat_Page ); 1298| HTREEITEM item, next; 1299| 1300| 1301| /* ツリーから項目を削除するための準備をする(開いていないツリー項目を開く) */ 1302| frame->ChgPage( prev2->beforeNum_start ); 1303| 1304| 1305| /* 図形を再び削除する */ 1306| page = ListX_removeSet( &app->m_file.m_pages, prev2->firstPage, last, SVGCat_Page ); 1307| ListX_insertSet( &m_deletedPages, NULL, page ); 1308| m_PageDelNum += nPage; 1309| 1310| 1311| /* 削除するインク・ファイルの名前を変える */ 1312| for ( i = 0; i < nPage; i++ ) { 1313| strcpy( path, app->GetInkWorkFilePath( app->m_file.m_id, 10000+prev2->iFirstPage+i, IRO_MaskPen ) ); 1314| MoveFile( app->GetInkWorkFilePath( app->m_file.m_id, prev2->beforeNum_start+i, IRO_MaskPen ), path ); 1315| strcpy( path, app->GetInkWorkFilePath( app->m_file.m_id, 10000+prev2->iFirstPage+i, IRO_CopyPen ) ); 1316| MoveFile( app->GetInkWorkFilePath( app->m_file.m_id, prev2->beforeNum_start+i, IRO_CopyPen ), path ); 1317| } 1318| 1319| 1320| /* 削除したページより後のページのインク一時ファイルを移動する */ 1321| m = ListX_getN( &app->m_file.m_pages, SVGCat_Page ) + app->m_file.m_StartPageNum - 1; 1322| for ( i = prev2->beforeNum_start; i <= m; i++ ) { 1323| strcpy( path, app->GetInkWorkFilePath( app->m_file.m_id, i, IRO_MaskPen ) ); 1324| MoveFile( app->GetInkWorkFilePath( app->m_file.m_id, nPage+i, IRO_MaskPen ), path ); 1325| strcpy( path, app->GetInkWorkFilePath( app->m_file.m_id, i, IRO_CopyPen ) ); 1326| MoveFile( app->GetInkWorkFilePath( app->m_file.m_id, nPage+i, IRO_CopyPen ), path ); 1327| } 1328| 1329| 1330| /* ページ間リンクを調節する */ 1331| prevPage = prev2->firstPage->prev; 1332| nextPage = prev2->firstPage->next; 1333| parentPage = prev2->firstPage->parent; 1334| if ( prevPage != NULL ) prevPage->next = nextPage; 1335| else if ( parentPage != NULL ) parentPage->firstChild = nextPage; 1336| if ( nextPage != NULL ) nextPage->prev = prevPage; 1337| if ( prevPage == NULL && nextPage == NULL ) 1338| parentPage->firstChild = NULL; 1339| 1340| 1341| /* ツリーから項目を削除する */ 1342| item = tree->GetSelectedItem(); 1343| next = tree->GetNextSiblingItem( item ); 1344| if ( next == NULL ) next = tree->GetPrevSiblingItem( item ); 1345| if ( next == NULL ) next = tree->GetParentItem( item ); 1346| tree->DeleteItem( item ); 1347| tree->Select( next, TVGN_CARET ); 1348| 1349| pageNum = SVGCat_File_getPageNum( &app->m_file, (SVGCat_Page*)tree->GetItemData( next ) ); 1350| } 1351| 1352| /* ページ移動のリドゥをする */ 1353| else { 1354| HTREEITEM srcItem, dstItem; 1355| 1356| if ( prev2->redoBaseNum == 0 ) pageNum = prev2->afterNum; 1357| else if ( prev2->redoBaseNum > 0 ) pageNum = prev2->redoBaseNum; 1358| else pageNum = -prev2->redoBaseNum; 1359| 1360| frame->ChgPage( prev2->beforeNum_start ); srcItem = tree->GetSelectedItem(); 1361| frame->ChgPage( pageNum ); dstItem = tree->GetSelectedItem(); 1362| 1363| frame->MovePage( srcItem, dstItem, prev2->redoBaseNum > 0, prev2->redoBaseNum < 0, false ); 1364| 1365| if ( prev2->afterNum <= prev2->beforeNum_start ) pageNum = prev2->afterNum; 1366| else pageNum = prev2->afterNum - ( prev2->beforeNum_over - prev2->beforeNum_start ); 1367| } 1368| 1369| 1370| app->ChgPage( &app->m_file, pageNum ); 1371| 1372| #ifdef UNDO_TRACE 1373| app->printPages( "Redo" ); 1374| #endif 1375| } 1376| 1377| bContinue = ! prev->bFirstOfMulti; 1378| prev = ListX_Elem_getNextT( prev, Undo_Step_Com ); 1379| } while ( bContinue ); 1380| 1381| 1382| #ifdef REDO_TRACE 1383| if ( prims != NULL ) app->printPrims( prims, "b" ); 1384| #endif 1385| 1386| if ( prims != NULL ) Relink( prims ); 1387| 1388| #ifdef REDO_TRACE 1389| if ( prims != NULL ) app->printPrims( prims, "c" ); 1390| #endif 1391| 1392| 1393| /* ページ管理と同期を取る */ 1394| if ( app->m_file.m_CurrentPageNum == m_Now->iPage + app->m_file.m_StartPageNum && 1395| prims != NULL ) { 1396| SVGCat_Page* page = ListX_get( &app->m_file.m_pages, m_Now->iPage, SVGCat_Page ); 1397| 1398| SVGCat_File_loadPage( &app->m_file, page ); 1399| } 1400| 1401| return prims; 1402|} 1403| 1404| 1405| 1406|/*********************************************************************** 1407| 2-15. <<< [Undo_Buf::IsAbleRedo] リドゥできるかどうかを返す >>> 1408|************************************************************************/ 1409|bool Undo_Buf::IsAbleRedo() 1410|{ 1411| Undo_Step_Com* first = ListX_getFirst( &m_Steps, Undo_Step_Com ); 1412| 1413| return ( first != NULL && m_Now != first ); 1414|} 1415| 1416| 1417| 1418|/*********************************************************************** 1419| 2-16. <<< [Undo_Buf::GetNextRedoPageNum] 次にリドゥするものがあるページ番号を返す >>> 1420|************************************************************************/ 1421|int Undo_Buf::GetNextRedoPageNum() 1422|{ 1423| CSVGCatApp* app = (CSVGCatApp*)AfxGetApp(); 1424| Undo_Step_Com* prev; 1425| Undo_Step_Com* prev2; 1426| Undo_Step_Com* step; 1427| 1428| if ( m_Now == ListX_getFirst( &m_Steps, Undo_Step_Com ) ) return -1; 1429| 1430| /* アンドゥする情報のある位置 prev を取得する */ 1431| prev = NULL; prev2 = NULL; 1432| for ( ListX_forEach( &m_Steps, &step, Undo_Step_Com ) ) { 1433| if ( step == m_Now ) break; 1434| if ( step->bFirstOfMulti ) { prev2 = prev; prev = step; } 1435| } 1436| if ( prev2 == NULL ) prev = ListX_getFirst( &m_Steps, Undo_Step_Com ); 1437| else prev = ListX_Elem_getNextT( prev2, Undo_Step_Com ); 1438| 1439| 1440| /* ページに対する操作の対象となるページ番号を返す */ 1441| if ( prev->typeID == Undo_PageType ) { 1442| Undo_Step_Page* prev2 = (Undo_Step_Page*)prev; 1443| 1444| if ( prev2->beforeNum_start == -1 ) 1445| return -1; 1446| else 1447| return prev2->beforeNum_start; 1448| } 1449| 1450| /* その他の操作の対象となるページ番号を返す */ 1451| else { 1452| if ( prev->iPage == -1 ) return -1; 1453| else return prev->iPage + app->m_file.m_StartPageNum; 1454| } 1455|} 1456| 1457| 1458| 1459|/*********************************************************************** 1460| 2-17. <<< [Undo_Buf::Relink] リンク先を復活し、リンクしているハンドルの移動をする >>> 1461|【補足】 1462|・アンドゥバッファに含まれるすべての図形のアンドゥ/リドゥをした後で、呼ばれます。 1463|************************************************************************/ 1464|void Undo_Buf::Relink( ListX* prims ) 1465|{ 1466| CSVGCatApp* app = (CSVGCatApp*)AfxGetApp(); 1467| ListX_ElemX* p; 1468| ListX_ElemX* p2; 1469| CadPrim* prim; 1470| CadPrim_Link* link; 1471| int iLink; 1472| CadPrim* linkPrim; 1473| int i, n; 1474| 1475| /* リンク先が含まれなかったら、リンクを復活する */ 1476| for ( ListX_forEach( prims, &p, ListX_ElemX ) ) { 1477| ((CadPrim*)p->p)->AdjustLinks( prims ); 1478| } 1479| for ( ListX_forEach( &m_holds, &p, ListX_ElemX ) ) { 1480| prim = (CadPrim*)p->p; 1481| 1482| /* LinkToHandle について、m_hold に含まれないリンク図形を移動する */ 1483| n = prim->GetNumOfLinkToHandle(); 1484| for ( i = 1; i <= n; i++ ) { 1485| link = prim->GetLinkToHandle( i ); 1486| if ( link == NULL ) continue; 1487| for ( ListX_forEach( &m_holds, &p2, ListX_ElemX ) ) { 1488| if ( link->prim->GetID() == ((CadPrim*)p2->p)->GetID() ) break; 1489| } 1490| if ( p2 == NULL ) { 1491| link->prim->LinkToControler( link->iHandle, prim ); 1492| link->prim->MoveByHandle( link->iHandle, link->x, link->y, true, false ); 1493| } 1494| } 1495| 1496| /* LinkToControler について */ 1497| n = prim->GetNumOfLinkToControler(); 1498| for ( i = 1; i <= n; i++ ) { 1499| iLink = prim->GetLinkIDToControler( i ); 1500| if ( iLink == 0 ) continue; 1501| for ( ListX_forEach( &m_holds, &p2, ListX_ElemX ) ) { 1502| if ( iLink == ((CadPrim*)p2->p)->GetID() ) break; 1503| } 1504| if ( p2 == NULL ) { 1505| linkPrim = prim->GetLinkToControler( i ); 1506| linkPrim->LinkToHandle( 0, prim, i ); 1507| } 1508| } 1509| } 1510|} 1511| 1512| 1513| 1514|void Undo_Buf::OnSaveed() 1515|{ 1516| m_Save = m_Now; 1517|} 1518| 1519|bool Undo_Buf::IsModify() 1520|{ 1521| return m_Save != m_Now; 1522|} 1523| 1524| 1525| 1526|/*-------------------------------------------------------------------------*/ 1527|/* 2-18. <<< ◆ (Undo_InkAttr) インクの属性のコピール >>> */ 1528|/*-------------------------------------------------------------------------*/ 1529| 1530| 1531|/*********************************************************************** 1532| 2-19. <<< [Undo_InkAttr_new] インクの属性のコピーを取る >>> 1533|【補足】 1534|・返り値は、AllocNewStep_Ink3 に渡します。 要free ですが、Undo_Buf が 1535| 管理します。 1536|************************************************************************/ 1537|Undo_InkAttr* Undo_InkAttr_new( IInkStrokes* strokes ) 1538|{ 1539| Undo_InkAttr* copy; 1540| IInkStrokeDisp* stroke; 1541| IInkDrawingAttributes* attr; 1542| long i, n; 1543| HRESULT hr; 1544| 1545| hr = strokes->get_Count( &n ); if ( hr != 0 ) error(); 1546| copy = (Undo_InkAttr*)malloc( sizeof(Undo_InkAttr) * n ); 1547| 1548| for ( i = 0; i < n; i++ ) { 1549| hr = strokes->Item( i, &stroke ); if ( hr != 0 ) error(); 1550| hr = stroke->get_DrawingAttributes( &attr ); if ( hr != 0 ) error(); 1551| 1552| hr = attr->get_Color( ©[i].color ); if ( hr != 0 ) error(); 1553| hr = attr->get_Width( ©[i].width ); if ( hr != 0 ) error(); 1554| 1555| hr = attr->Release(); 1556| hr = stroke->Release(); 1557| } 1558| 1559| return copy; 1560|} 1561| 1562| 1563| 1564| 1565|/*********************************************************************** 1566| 2-20. <<< [Undo_InkAttr_resume] コピーを元に、インクの属性を戻す >>> 1567|************************************************************************/ 1568|void Undo_InkAttr_resume( Undo_InkAttr* m, IInkStrokes* strokes ) 1569|{ 1570| IInkStrokeDisp* stroke; 1571| IInkDrawingAttributes* attr; 1572| long i, n; 1573| HRESULT hr; 1574| 1575| hr = strokes->get_Count( &n ); if ( hr != 0 ) error(); 1576| 1577| for ( i = 0; i < n; i++ ) { 1578| hr = strokes->Item( i, &stroke ); if ( hr != 0 ) error(); 1579| hr = stroke->get_DrawingAttributes( &attr ); if ( hr != 0 ) error(); 1580| 1581| hr = attr->put_Color( m[i].color ); if ( hr != 0 ) error(); 1582| hr = attr->put_Width( m[i].width ); if ( hr != 0 ) error(); 1583| 1584| hr = attr->Release(); 1585| hr = stroke->Release(); 1586| } 1587|} 1588| 1589| 1590|/*-------------------------------------------------------------------------*/ 1591|/* 2-21. <<< ◆ (Undo_StrokesTable) ストロークの識別番号と IInkDisp の対応テーブル >>> */ 1592|/*-------------------------------------------------------------------------*/ 1593| 1594|long* Undo_StrokeTable_Ids; 1595|int Undo_StrokeTable_n; 1596|int Undo_StrokeTable_m; 1597| 1598| 1599|/*********************************************************************** 1600| 2-22. <<< [Undo_StrokeTable_clear] テーブルをクリアする >>> 1601|************************************************************************/ 1602|void Undo_StrokeTable_clear() 1603|{ 1604| Undo_StrokeTable_n = 0; 1605|} 1606| 1607| 1608| 1609|/*********************************************************************** 1610| 2-23. <<< [Undo_StrokeTable_addId2] ストローク集合のIDを登録し、ID2 の配列を取得する >>> 1611|【引数】 1612| ・IInkStrokes* strokes; IInkOverlay 等に所属する操作対象となったストローク(所有しない) 1613| ・long* id2s; NULL:新規ID2配列を取得、!NULL:ID2配列に追加 1614| ・long* 返り値; strokes に対応した ID2 の配列(要 free, [0]は要素数) 1615|【補足】 1616|・ユーザの操作によって、ストロークが追加されたときに呼び出してください。 1617| それは、必ずテーブルに ID を登録することで高速に行うためです。 1618|・テーブルに登録したストロークの識別番号(ID2)を取得します。 1619|************************************************************************/ 1620|long* Undo_StrokeTable_addId2( IInkStrokes* strokes, long* id2s ) 1621|{ 1622| HRESULT hr; 1623| IInkStrokeDisp* stroke; 1624| int i; 1625| long n; 1626| int offset; 1627| 1628| hr = strokes->get_Count( &n ); if ( hr != 0 ) error(); 1629| if ( id2s == NULL ) { 1630| offset = 0; 1631| id2s = (long*)malloc( sizeof(long) * (n+1) ); 1632| id2s[0] = n; 1633| } 1634| else { 1635| offset = id2s[0]; 1636| id2s = (long*)realloc( id2s, sizeof(long) * (offset+n+1) ); 1637| id2s[0] = offset + n; 1638| } 1639| 1640| /* IDのテーブルサイズが不足したら拡張する */ 1641| if ( Undo_StrokeTable_n + n >= Undo_StrokeTable_m ) { 1642| if ( n >= 256 ) error(); 1643| Undo_StrokeTable_m += 256; 1644| Undo_StrokeTable_Ids = (long*)realloc( Undo_StrokeTable_Ids, 1645| sizeof(long) * Undo_StrokeTable_m ); 1646| } 1647| 1648| /* ID を登録する */ 1649| for ( i = 0; i < n; i++ ) { 1650| hr = strokes->Item( i, &stroke ); if ( hr != 0 ) error(); 1651| hr = stroke->get_ID( &Undo_StrokeTable_Ids[ Undo_StrokeTable_n ] ); 1652| if ( hr != 0 ) error(); 1653| stroke->Release(); 1654| 1655| id2s[offset+i+1] = Undo_StrokeTable_n; 1656| Undo_StrokeTable_n ++; 1657| } 1658| 1659| return id2s; 1660|} 1661| 1662| 1663|/*********************************************************************** 1664| 2-24. <<< [Undo_StrokeTable_lookupId2] ストローク集合から ID2 の配列を取得する >>> 1665|【引数】 1666| ・IInkStrokes* strokes; IInkOverlay 等に所属する操作対象となったストローク(所有しない) 1667| ・long* id2s; NULL:新規ID2配列を取得、!NULL:ID2配列に追加 1668| ・long* 返り値; strokes に対応した ID2 の配列(要 free, [0]は要素数) 1669|【補足】 1670|・ユーザの操作によって、ストロークが変更されたときに呼び出してください。 1671|・テーブルに登録されていないストロークが指定されたときは、テーブルに 1672| 登録します。 1673|・テーブルに登録されている最新のストロークの記録から、IInkOverlay 等が管理する 1674| ID を照合し、ストロークの識別番号(ID2)を取得します。 1675|************************************************************************/ 1676|long* Undo_StrokeTable_lookupId2( IInkStrokes* strokes, long* id2s ) 1677|{ 1678| HRESULT hr; 1679| IInkStrokeDisp* stroke; 1680| int id2, i; 1681| long n, id; 1682| long* ids; 1683| int offset; 1684| 1685| hr = strokes->get_Count( &n ); if ( hr != 0 ) error(); 1686| ids = (long*)malloc( sizeof(long) * n ); 1687| if ( id2s == NULL ) { 1688| offset = 0; 1689| id2s = (long*)malloc( sizeof(long) * (n+1) ); 1690| id2s[0] = n; 1691| } 1692| else { 1693| offset = id2s[0]; 1694| id2s = (long*)realloc( id2s, sizeof(long) * (offset+n+1) ); 1695| id2s[0] = offset + n; 1696| } 1697| 1698| /* IInkOverlay 等が管理する、ストロークの ID の配列 ids を作成する */ 1699| for ( i = 0; i < n; i++ ) { 1700| hr = strokes->Item( i, &stroke ); if ( hr != 0 ) error(); 1701| hr = stroke->get_ID( &ids[i] ); if ( hr != 0 ) error(); 1702| stroke->Release(); 1703| id2s[offset+i+1] = -1L; /* 無効値 */ 1704| } 1705| 1706| /* テーブルを参照して ID2 の配列 id2s を作成する */ 1707| for ( id2 = Undo_StrokeTable_n - 1; id2 >= 0; id2-- ) { 1708| id = Undo_StrokeTable_Ids[id2]; 1709| 1710| for ( i = 0; i < n; i++ ) { 1711| if ( ids[i] == id ) 1712| break; 1713| } 1714| if ( i != n ) { /* テーブルに見つかったとき */ 1715| id2s[offset+i+1] = id2; 1716| } 1717| } 1718| 1719| /* テーブルに見つからなかった ID を登録する */ 1720| for ( i = 0; i < n; i++ ) { 1721| if ( id2s[offset+i+1] == -1 ) { 1722| if ( Undo_StrokeTable_n == Undo_StrokeTable_m ) { 1723| Undo_StrokeTable_m += 256; 1724| Undo_StrokeTable_Ids = (long*)realloc( Undo_StrokeTable_Ids, 1725| sizeof(long) * Undo_StrokeTable_m ); 1726| } 1727| Undo_StrokeTable_Ids[ Undo_StrokeTable_n ] = ids[i]; 1728| id2s[offset+i+1] = Undo_StrokeTable_n; 1729| Undo_StrokeTable_n ++; 1730| } 1731| } 1732| 1733| free( ids ); 1734| 1735| return id2s; 1736|} 1737| 1738| 1739|/*********************************************************************** 1740| 2-25. <<< [Undo_StrokeTable_lookupStrokes] 操作対象のストロークの集合を取得する >>> 1741|【引数】 1742| ・long* id2s; strokes に対応した ID2 の配列([0]は要素数) 1743| ・IInkDisp* ink; IInkOverlay 等に所属するインク(所有しない) 1744| ・IInkStrokes* 返り値; ink に所属している操作対象となるストローク(要 IUnknown::Release) 1745|************************************************************************/ 1746|#if ERRORS_DEBUG_FALSE 1747|#define UNDO_WATCH_RECONNECT 1748|#endif 1749| 1750|IInkStrokes* Undo_StrokeTable_lookupStrokes( long* id2s, IInkDisp* ink ) 1751|{ 1752| HRESULT hr; 1753| IInkStrokes* allStrokes; 1754| IInkStrokes* strokes; 1755| IInkStrokeDisp* stroke; 1756| int i, i2, n2, nHit = 0; 1757| long n, id; 1758| 1759| #ifdef UNDO_WATCH_RECONNECT 1760| Errors_startPool(); 1761| #endif 1762| 1763| hr = ink->get_Strokes( &allStrokes ); if ( hr != 0 ) error(); 1764| hr = allStrokes->get_Count( &n ); if ( hr != 0 ) error(); 1765| n2 = id2s[0]; 1766| 1767| hr = ink->HitTestCircle( INT_MIN, INT_MIN, 0.0f, &strokes ); if ( hr != S_OK ) error(); 1768| /* 空の Strokes を取得する(CoCreateInstance ではできないため) */ 1769| 1770| 1771| for ( i = n - 1; i >= 0; i -- ) { /* ink のストロークのループ */ 1772| #ifdef UNDO_WATCH_RECONNECT 1773| Errors_printf( "i = %d", i ); 1774| #endif 1775| 1776| if ( nHit == n ) { /* 全てヒットした */ 1777| #ifdef UNDO_WATCH_RECONNECT 1778| Errors_printf( "All Hit!" ); 1779| #endif 1780| break; 1781| } 1782| 1783| hr = allStrokes->Item( i, &stroke ); if ( hr != 0 ) error(); 1784| 1785| if ( n2 - nHit == i + 1 1786| #ifdef UNDO_WATCH_RECONNECT /* デバッグ時は無条件ヒットはしない */ 1787| && 0 1788| #endif 1789| ) { /* 残りは全てヒットする */ 1790| #ifdef UNDO_WATCH_RECONNECT 1791| Errors_printf( "No reason Hit!" ); 1792| #endif 1793| strokes->Add( stroke ); 1794| nHit ++; 1795| } 1796| else { 1797| 1798| hr = stroke->get_ID( &id ); if ( hr != 0 ) error(); 1799| #ifdef UNDO_WATCH_RECONNECT 1800| Errors_printf( "ID master = %d", id ); 1801| #endif 1802| 1803| for ( i2 = 0; i2 < n2; i2++ ) { 1804| #ifdef UNDO_WATCH_RECONNECT 1805| Errors_printf( "ID table = %d", Undo_StrokeTable_Ids[id2s[i2+1]] ); 1806| #endif 1807| if ( Undo_StrokeTable_Ids[id2s[i2+1]] == id ) 1808| break; 1809| } 1810| if ( i2 != n2 ) { /* hit */ 1811| #ifdef UNDO_WATCH_RECONNECT 1812| Errors_printf( "ID Hit!" ); 1813| #endif 1814| strokes->Add( stroke ); 1815| nHit ++; 1816| } 1817| } 1818| stroke->Release(); 1819| } 1820| 1821| ASSERT( nHit == n2 ); 1822| 1823| allStrokes->Release(); 1824| 1825| #ifdef UNDO_WATCH_RECONNECT 1826| Errors_endPool(); 1827| #endif 1828| 1829| return strokes; 1830|} 1831| 1832| 1833| 1834|/*********************************************************************** 1835| 2-26. <<< [Undo_StrokeTable_updateStrokes] テーブルに ID を通知する >>> 1836|【引数】 1837| ・long* id2s; strokes に対応した ID2 の配列([0]は要素数) 1838| ・IInkStrokes* strokes; IInkOverlay 等に所属する操作対象となったストローク(所有しない) 1839|【補足】 1840|・アンドゥ・リドゥ操作によって、ストロークが変更された後で呼び出してください。 1841|・ストロークが削除されるときは、削除するストロークを指定してください。 1842|************************************************************************/ 1843|void Undo_StrokeTable_updateStrokes( long* id2s, IInkStrokes* strokes ) 1844|{ 1845| HRESULT hr; 1846| IInkStrokeDisp* stroke; 1847| int i; 1848| 1849| #ifndef NDEBUG 1850| long n; 1851| hr = strokes->get_Count( &n ); if ( hr != 0 ) error(); 1852| ASSERT( n == id2s[0] ); 1853| #endif 1854| 1855| for ( i = 0; i < id2s[0]; i++ ) { 1856| hr = strokes->Item( i, &stroke ); if ( hr != 0 ) error(); 1857| hr = stroke->get_ID( & Undo_StrokeTable_Ids[ id2s[i+1] ] ); 1858| if ( hr != 0 ) error(); 1859| hr = stroke->Release(); 1860| } 1861|} 1862| 1863| 1864| 1865|/*-------------------------------------------------------------------------*/ 1866|/* 2-27. <<< ◆ (Undo_Uty) その他 >>> */ 1867|/*-------------------------------------------------------------------------*/ 1868| 1869|#if ERRORS_DEBUG_FALSE 1870|#define UNDO_UTY_TRACE 1871|#endif 1872| 1873| 1874| 1875|CadPrim* Undo_Uty_getPrimPtr( ListX* prims, int id ) 1876|{ 1877| ListX_ElemX* p; 1878| 1879| for ( ListX_forEach( prims, &p, ListX_ElemX ) ) { 1880| if ( ((CadPrim*)p->p)->GetID() == id ) 1881| return (CadPrim*)p->p; 1882| } 1883| return NULL; 1884|} 1885| 1886| 1887| 1888|CadPrim* Undo_Uty_createPrim( CadPrim* prim, CadPrim* prim_f, ListX* prims ) 1889|{ 1890| CadPrim* prim_f2; 1891| ListX_ElemX* p; 1892| 1893| #ifdef UNDO_UTY_TRACE 1894| Errors_printf( "CreatePrim id=%d", prim->GetID() ); 1895| Errors_printf( " forword id=%d", prim_f == NULL ? -1 : prim_f->GetID() ); 1896| #endif 1897| 1898| /* 生成する手前の図形 prim_f2 を得る */ 1899| if ( prim_f == NULL ) { 1900| p = NULL; 1901| } 1902| else { 1903| for ( ListX_forEach( prims, &p, ListX_ElemX ) ) { 1904| prim_f2 = (CadPrim*)p->p; 1905| if ( prim_f2->GetID() == prim_f->GetID() ) 1906| break; 1907| } 1908| // ASSERT( p != NULL ); まだ生成していない図形のときに NULL になる 1909| } 1910| 1911| /* 各図形を生成する */ 1912| p = ListX_insertMalloc( prims, p, ListX_ElemX ); 1913| 1914| switch ( prim->GetTypeID() ) { 1915| case Rect_Ex_TypeID: { 1916| Rect_Ex* rect = new Rect_Ex; 1917| p->p = rect; rect->copy( prim, prims ); 1918| break; 1919| } 1920| case Line_Ex_TypeID: { 1921| Line_Ex* line = new Line_Ex; 1922| p->p = line; line->copy( prim, prims ); 1923| break; 1924| } 1925| case Line_Corner_TypeID: { 1926| Line_Corner* line = new Line_Corner; 1927| p->p = line; line->copy( prim, prims ); 1928| break; 1929| } 1930| case Text_Box_TypeID: { 1931| Text_Box* text = new Text_Box; 1932| p->p = text; text->copy( prim, prims ); 1933| break; 1934| } 1935| case Matome_TypeID: { 1936| Matome* mato = new Matome; 1937| p->p = mato; mato->copy( prim, prims ); 1938| break; 1939| } 1940| default: ASSERT(0); 1941| } 1942| 1943| return (CadPrim*)p->p; 1944|} 1945| 1946| 1947| 1948|void Undo_Uty_deletePrim( CadPrim* target, ListX* prims ) 1949|{ 1950| CadPrim* target2; 1951| ListX_ElemX* p; 1952| 1953| #ifdef UNDO_UTY_TRACE 1954| Errors_printf( "DeletePrim id=%d", target->GetID() ); 1955| #endif 1956| 1957| /* アンドゥする対象 target2 を得る */ 1958| for ( ListX_forEach( prims, &p, ListX_ElemX ) ) { 1959| target2 = (CadPrim*)p->p; 1960| if ( target2->GetID() == target->GetID() ) 1961| break; 1962| } 1963| ASSERT( p != NULL ); 1964| 1965| delete target2; 1966| ListX_removeFree( prims, p ); 1967|} 1968| 1969| 1970| 1971|CadPrim* Undo_Uty_editPrim( CadPrim* target, CadPrim* newPrim, CadPrim* target_z, 1972| CadPrim* newPrim_z, ListX* prims, Canvas* canvas ) 1973|{ 1974| CadPrim* target2; 1975| CadPrim* target2_z; 1976| ListX_ElemX* p; 1977| Canvas canvas2; /* vfptr のある Canvas */ 1978| 1979| #ifdef UNDO_UTY_TRACE 1980| Errors_printf( "EditPrim id=%d", target->GetID() ); 1981| Errors_printf( " forword id=%d", target_z == NULL ? -1 : target_z->GetID() ); 1982| #endif 1983| 1984| /* アンドゥする対象 target2 を得る */ 1985| if ( target->GetTypeID() == Canvas_TypeID ) { 1986| target2 = &canvas2; 1987| } 1988| else { 1989| for ( ListX_forEach( prims, &p, ListX_ElemX ) ) { 1990| target2 = (CadPrim*)p->p; 1991| if ( target2->GetID() == target->GetID() ) 1992| break; 1993| } 1994| ASSERT( p != NULL ); 1995| } 1996| 1997| 1998| /* 元の属性に戻す */ 1999| target2->copy( newPrim, prims ); 2000| 2001| /* Z オーダーを戻す */ 2002| if ( newPrim_z != target_z ) { 2003| ListX_ElemX* front; 2004| 2005| if ( newPrim_z == NULL ) { 2006| front = NULL; 2007| } 2008| else { 2009| for ( ListX_forEach( prims, &front, ListX_ElemX ) ) { 2010| target2_z = (CadPrim*)front->p; 2011| if ( target2_z->GetID() == newPrim_z->GetID() ) 2012| break; 2013| } 2014| ASSERT( front != NULL ); 2015| } 2016| 2017| ListX_remove( prims, p ); 2018| if ( front == NULL ) 2019| ListX_addLast( prims, p ); 2020| else 2021| ListX_insert( prims, front, p ); 2022| } 2023| 2024| 2025| if ( target->GetTypeID() == Canvas_TypeID ) { 2026| *canvas = canvas2; 2027| target2 = NULL; 2028| } 2029| 2030| 2031| return target2; 2032|} 2033| 2034| 2035| 2036|/*********************************************************************** 2037| 2-28. <<< [Undo_Uty_addStrokes] インクのストロークを追加する >>> 2038|【引数】 2039| ・IInkDisp* masterInk; IInkOverlay 等に所属するインク 2040| ・IInkDisp* strokesInk; 追加するストロークだけが入ったインク 2041| ・IInkRectangle* boundingBox; 追加するストロークの座標 2042| ・IInkStrokes* 返り値; 追加したストローク(要 IUnknown::Release) 2043|************************************************************************/ 2044|IInkStrokes* Undo_Uty_addStrokes( IInkDisp* masterInk, IInkDisp* strokesInk, IInkRectangle* boundingBox ) 2045|{ 2046| IInkStrokes* strokes; 2047| IInkStrokes* strokes2; 2048| IInkStrokeDisp* stroke; 2049| long i,n; 2050| HRESULT hr; 2051| 2052| hr = masterInk->get_Strokes( &strokes ); if ( hr != 0 ) error(); 2053| hr = strokesInk->get_Strokes( &strokes2 ); if ( hr != 0 ) error(); 2054| hr = strokes->get_Count( &n ); if ( hr != 0 ) error(); 2055| hr = strokes->Release(); 2056| 2057| /* ストロークを追加する */ 2058| hr = masterInk->AddStrokesAtRectangle( strokes2, boundingBox ); 2059| if ( hr != 0 ) error(); 2060| 2061| hr = strokes2->Release(); 2062| 2063| /* strokes を選択するストロークのみ残す(strokes2 では Ink が違うので後でエラーになる) */ 2064| hr = masterInk->get_Strokes( &strokes ); if ( hr != 0 ) error(); 2065| for ( i = 0; i < n; i++ ) { 2066| hr = strokes->Item( 0, &stroke ); if ( hr != 0 ) error(); 2067| hr = strokes->Remove( stroke ); if ( hr != 0 ) error(); 2068| hr = stroke->Release(); 2069| } 2070| 2071| return strokes; 2072|} 2073| 2074|