Undo.cpp

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( &copy[i].color );  if ( hr != 0 )  error();
1553|    hr = attr->get_Width( &copy[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|