1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_svx.hxx" 26 #include <svx/framelinkarray.hxx> 27 28 #include <math.h> 29 #include <vector> 30 #include <algorithm> 31 #include <vcl/outdev.hxx> 32 33 namespace svx { 34 namespace frame { 35 36 // ============================================================================ 37 38 39 Cell::Cell() : 40 mnAddLeft( 0 ), 41 mnAddRight( 0 ), 42 mnAddTop( 0 ), 43 mnAddBottom( 0 ), 44 mbMergeOrig( false ), 45 mbOverlapX( false ), 46 mbOverlapY( false ) 47 { 48 } 49 50 void Cell::MirrorSelfX( bool bMirrorStyles, bool bSwapDiag ) 51 { 52 std::swap( maLeft, maRight ); 53 std::swap( mnAddLeft, mnAddRight ); 54 if( bMirrorStyles ) 55 { 56 maLeft.MirrorSelf(); 57 maRight.MirrorSelf(); 58 } 59 if( bSwapDiag ) 60 { 61 std::swap( maTLBR, maBLTR ); 62 if( bMirrorStyles ) 63 { 64 maTLBR.MirrorSelf(); 65 maBLTR.MirrorSelf(); 66 } 67 } 68 } 69 70 void Cell::MirrorSelfY( bool bMirrorStyles, bool bSwapDiag ) 71 { 72 std::swap( maTop, maBottom ); 73 std::swap( mnAddTop, mnAddBottom ); 74 if( bMirrorStyles ) 75 { 76 maTop.MirrorSelf(); 77 maBottom.MirrorSelf(); 78 } 79 if( bSwapDiag ) 80 std::swap( maTLBR, maBLTR ); 81 /* Do not mirror diagonal styles, because they are oriented vertical. 82 Therefore swapping the styles is sufficient for correct behaviour. */ 83 } 84 85 // ---------------------------------------------------------------------------- 86 87 88 void lclRecalcCoordVec( LongVec& rCoords, const LongVec& rSizes ) 89 { 90 DBG_ASSERT( rCoords.size() == rSizes.size() + 1, "lclRecalcCoordVec - inconsistent vectors" ); 91 LongVec::iterator aCIt = rCoords.begin(); 92 LongVec::const_iterator aSIt = rSizes.begin(), aSEnd = rSizes.end(); 93 for( ; aSIt != aSEnd; ++aCIt, ++aSIt ) 94 *(aCIt + 1) = *aCIt + *aSIt; 95 } 96 97 void lclSetMergedRange( CellVec& rCells, size_t nWidth, size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow ) 98 { 99 for( size_t nCol = nFirstCol; nCol <= nLastCol; ++nCol ) 100 { 101 for( size_t nRow = nFirstRow; nRow <= nLastRow; ++nRow ) 102 { 103 Cell& rCell = rCells[ nRow * nWidth + nCol ]; 104 rCell.mbMergeOrig = false; 105 rCell.mbOverlapX = nCol > nFirstCol; 106 rCell.mbOverlapY = nRow > nFirstRow; 107 } 108 } 109 rCells[ nFirstRow * nWidth + nFirstCol ].mbMergeOrig = true; 110 } 111 112 // ---------------------------------------------------------------------------- 113 114 static const Style OBJ_STYLE_NONE; 115 static const Cell OBJ_CELL_NONE; 116 117 const bool DIAG_DBL_CLIP_DEFAULT = false; 118 119 // ============================================================================ 120 121 ArrayImpl::ArrayImpl( size_t nWidth, size_t nHeight, bool bDiagDblClip ) : 122 mnWidth( nWidth ), 123 mnHeight( nHeight ), 124 mnFirstClipCol( 0 ), 125 mnFirstClipRow( 0 ), 126 mnLastClipCol( nWidth - 1 ), 127 mnLastClipRow( nHeight - 1 ), 128 mbXCoordsDirty( false ), 129 mbYCoordsDirty( false ), 130 mbDiagDblClip( bDiagDblClip ) 131 { 132 // default-construct all vectors 133 maCells.resize( mnWidth * mnHeight ); 134 maWidths.resize( mnWidth, 0L ); 135 maHeights.resize( mnHeight, 0L ); 136 maXCoords.resize( mnWidth + 1, 0L ); 137 maYCoords.resize( mnHeight + 1, 0L ); 138 } 139 140 const Cell& ArrayImpl::GetCell( size_t nCol, size_t nRow ) const 141 { 142 return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : OBJ_CELL_NONE; 143 } 144 145 Cell& ArrayImpl::GetCellAcc( size_t nCol, size_t nRow ) 146 { 147 static Cell aDummy; 148 return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : aDummy; 149 } 150 151 size_t ArrayImpl::GetMergedFirstCol( size_t nCol, size_t nRow ) const 152 { 153 size_t nFirstCol = nCol; 154 while( (nFirstCol > 0) && GetCell( nFirstCol, nRow ).mbOverlapX ) --nFirstCol; 155 return nFirstCol; 156 } 157 158 size_t ArrayImpl::GetMergedFirstRow( size_t nCol, size_t nRow ) const 159 { 160 size_t nFirstRow = nRow; 161 while( (nFirstRow > 0) && GetCell( nCol, nFirstRow ).mbOverlapY ) --nFirstRow; 162 return nFirstRow; 163 } 164 165 size_t ArrayImpl::GetMergedLastCol( size_t nCol, size_t nRow ) const 166 { 167 size_t nLastCol = nCol + 1; 168 while( (nLastCol < mnWidth) && GetCell( nLastCol, nRow ).mbOverlapX ) ++nLastCol; 169 return nLastCol - 1; 170 } 171 172 size_t ArrayImpl::GetMergedLastRow( size_t nCol, size_t nRow ) const 173 { 174 size_t nLastRow = nRow + 1; 175 while( (nLastRow < mnHeight) && GetCell( nCol, nLastRow ).mbOverlapY ) ++nLastRow; 176 return nLastRow - 1; 177 } 178 179 const Cell& ArrayImpl::GetMergedOriginCell( size_t nCol, size_t nRow ) const 180 { 181 return GetCell( GetMergedFirstCol( nCol, nRow ), GetMergedFirstRow( nCol, nRow ) ); 182 } 183 184 Cell& ArrayImpl::GetMergedOriginCellAcc( size_t nCol, size_t nRow ) 185 { 186 return GetCellAcc( GetMergedFirstCol( nCol, nRow ), GetMergedFirstRow( nCol, nRow ) ); 187 } 188 189 bool ArrayImpl::IsMergedOverlappedLeft( size_t nCol, size_t nRow ) const 190 { 191 const Cell& rCell = GetCell( nCol, nRow ); 192 return rCell.mbOverlapX || (rCell.mnAddLeft > 0); 193 } 194 195 bool ArrayImpl::IsMergedOverlappedRight( size_t nCol, size_t nRow ) const 196 { 197 return GetCell( nCol + 1, nRow ).mbOverlapX || (GetCell( nCol, nRow ).mnAddRight > 0); 198 } 199 200 bool ArrayImpl::IsMergedOverlappedTop( size_t nCol, size_t nRow ) const 201 { 202 const Cell& rCell = GetCell( nCol, nRow ); 203 return rCell.mbOverlapY || (rCell.mnAddTop > 0); 204 } 205 206 bool ArrayImpl::IsMergedOverlappedBottom( size_t nCol, size_t nRow ) const 207 { 208 return GetCell( nCol, nRow + 1 ).mbOverlapY || (GetCell( nCol, nRow ).mnAddBottom > 0); 209 } 210 211 bool ArrayImpl::IsColInClipRange( size_t nCol ) const 212 { 213 return (mnFirstClipCol <= nCol) && (nCol <= mnLastClipCol); 214 } 215 216 bool ArrayImpl::IsRowInClipRange( size_t nRow ) const 217 { 218 return (mnFirstClipRow <= nRow) && (nRow <= mnLastClipRow); 219 } 220 221 bool ArrayImpl::IsInClipRange( size_t nCol, size_t nRow ) const 222 { 223 return IsColInClipRange( nCol ) && IsRowInClipRange( nRow ); 224 } 225 226 long ArrayImpl::GetColPosition( size_t nCol ) const 227 { 228 if( mbXCoordsDirty ) 229 { 230 lclRecalcCoordVec( maXCoords, maWidths ); 231 mbXCoordsDirty = false; 232 } 233 return maXCoords[ nCol ]; 234 } 235 236 long ArrayImpl::GetRowPosition( size_t nRow ) const 237 { 238 if( mbYCoordsDirty ) 239 { 240 lclRecalcCoordVec( maYCoords, maHeights ); 241 mbYCoordsDirty = false; 242 } 243 return maYCoords[ nRow ]; 244 } 245 246 long ArrayImpl::GetColWidth( size_t nFirstCol, size_t nLastCol ) const 247 { 248 return GetColPosition( nLastCol + 1 ) - GetColPosition( nFirstCol ); 249 } 250 251 long ArrayImpl::GetRowHeight( size_t nFirstRow, size_t nLastRow ) const 252 { 253 return GetRowPosition( nLastRow + 1 ) - GetRowPosition( nFirstRow ); 254 } 255 256 double ArrayImpl::GetHorDiagAngle( size_t nCol, size_t nRow, bool bSimple ) const 257 { 258 double fAngle = 0.0; 259 if( IsValidPos( nCol, nRow ) ) 260 { 261 if( bSimple || !GetCell( nCol, nRow ).IsMerged() ) 262 { 263 fAngle = frame::GetHorDiagAngle( maWidths[ nCol ] + 1, maHeights[ nRow ] + 1 ); 264 } 265 else 266 { 267 // return correct angle for each cell in the merged range 268 size_t nFirstCol = GetMergedFirstCol( nCol, nRow ); 269 size_t nFirstRow = GetMergedFirstRow( nCol, nRow ); 270 const Cell& rCell = GetCell( nFirstCol, nFirstRow ); 271 long nWidth = GetColWidth( nFirstCol, GetMergedLastCol( nCol, nRow ) ) + rCell.mnAddLeft + rCell.mnAddRight; 272 long nHeight = GetRowHeight( nFirstRow, GetMergedLastRow( nCol, nRow ) ) + rCell.mnAddTop + rCell.mnAddBottom; 273 fAngle = frame::GetHorDiagAngle( nWidth + 1, nHeight + 1 ); 274 } 275 } 276 return fAngle; 277 } 278 279 double ArrayImpl::GetVerDiagAngle( size_t nCol, size_t nRow, bool bSimple ) const 280 { 281 double fAngle = GetHorDiagAngle( nCol, nRow, bSimple ); 282 return (fAngle > 0.0) ? (F_PI2 - fAngle) : 0.0; 283 } 284 285 // ============================================================================ 286 287 class MergedCellIterator 288 { 289 public: 290 explicit MergedCellIterator( const Array& rArray, size_t nCol, size_t nRow ); 291 292 inline bool Is() const { return (mnCol <= mnLastCol) && (mnRow <= mnLastRow); } 293 inline size_t Col() const { return mnCol; } 294 inline size_t Row() const { return mnRow; } 295 296 MergedCellIterator& operator++(); 297 298 private: 299 size_t mnFirstCol; 300 size_t mnFirstRow; 301 size_t mnLastCol; 302 size_t mnLastRow; 303 size_t mnCol; 304 size_t mnRow; 305 }; 306 307 // ---------------------------------------------------------------------------- 308 309 MergedCellIterator::MergedCellIterator( const Array& rArray, size_t nCol, size_t nRow ) 310 { 311 DBG_ASSERT( rArray.IsMerged( nCol, nRow ), "svx::frame::MergedCellIterator::MergedCellIterator - not in merged range" ); 312 rArray.GetMergedRange( mnFirstCol, mnFirstRow, mnLastCol, mnLastRow, nCol, nRow ); 313 mnCol = mnFirstCol; 314 mnRow = mnFirstRow; 315 } 316 317 MergedCellIterator& MergedCellIterator::operator++() 318 { 319 DBG_ASSERT( Is(), "svx::frame::MergedCellIterator::operator++() - already invalid" ); 320 if( ++mnCol > mnLastCol ) 321 { 322 mnCol = mnFirstCol; 323 ++mnRow; 324 } 325 return *this; 326 } 327 328 // ============================================================================ 329 330 #define DBG_FRAME_ERROR( funcname, error ) DBG_ERRORFILE( "svx::frame::Array::" funcname " - " error ) 331 #define DBG_FRAME_CHECK( cond, funcname, error ) DBG_ASSERT( cond, "svx::frame::Array::" funcname " - " error ) 332 #define DBG_FRAME_CHECK_COL( col, funcname ) DBG_FRAME_CHECK( (col) < GetColCount(), funcname, "invalid column index" ) 333 #define DBG_FRAME_CHECK_ROW( row, funcname ) DBG_FRAME_CHECK( (row) < GetRowCount(), funcname, "invalid row index" ) 334 #define DBG_FRAME_CHECK_COLROW( col, row, funcname ) DBG_FRAME_CHECK( ((col) < GetColCount()) && ((row) < GetRowCount()), funcname, "invalid cell index" ) 335 #define DBG_FRAME_CHECK_INDEX( index, funcname ) DBG_FRAME_CHECK( (index) < GetCellCount(), funcname, "invalid cell index" ) 336 #define DBG_FRAME_CHECK_COL_1( col, funcname ) DBG_FRAME_CHECK( (col) <= GetColCount(), funcname, "invalid column index" ) 337 #define DBG_FRAME_CHECK_ROW_1( row, funcname ) DBG_FRAME_CHECK( (row) <= GetRowCount(), funcname, "invalid row index" ) 338 339 // ---------------------------------------------------------------------------- 340 341 #define CELL( col, row ) mxImpl->GetCell( col, row ) 342 #define CELLACC( col, row ) mxImpl->GetCellAcc( col, row ) 343 #define ORIGCELL( col, row ) mxImpl->GetMergedOriginCell( col, row ) 344 #define ORIGCELLACC( col, row ) mxImpl->GetMergedOriginCellAcc( col, row ) 345 346 // ---------------------------------------------------------------------------- 347 348 Array::Array() 349 { 350 Initialize( 0, 0 ); 351 } 352 353 Array::Array( size_t nWidth, size_t nHeight ) 354 { 355 Initialize( nWidth, nHeight ); 356 } 357 358 Array::~Array() 359 { 360 } 361 362 // array size and column/row indexes ------------------------------------------ 363 364 void Array::Initialize( size_t nWidth, size_t nHeight ) 365 { 366 bool bDiagDblClip = mxImpl.get() ? mxImpl->mbDiagDblClip : DIAG_DBL_CLIP_DEFAULT; 367 mxImpl.reset( new ArrayImpl( nWidth, nHeight, bDiagDblClip ) ); 368 } 369 370 void Array::Clear() 371 { 372 Initialize( mxImpl->mnWidth, mxImpl->mnHeight ); 373 } 374 375 size_t Array::GetColCount() const 376 { 377 return mxImpl->mnWidth; 378 } 379 380 size_t Array::GetRowCount() const 381 { 382 return mxImpl->mnHeight; 383 } 384 385 size_t Array::GetCellCount() const 386 { 387 return mxImpl->maCells.size(); 388 } 389 390 size_t Array::GetColFromIndex( size_t nCellIndex ) const 391 { 392 DBG_FRAME_CHECK_INDEX( nCellIndex, "GetColFromIndex" ); 393 return mxImpl->mnWidth ? (nCellIndex % mxImpl->mnWidth) : 0; 394 } 395 396 size_t Array::GetRowFromIndex( size_t nCellIndex ) const 397 { 398 DBG_FRAME_CHECK_INDEX( nCellIndex, "GetRowFromIndex" ); 399 return mxImpl->mnWidth ? (nCellIndex / mxImpl->mnWidth) : 0; 400 } 401 402 size_t Array::GetCellIndex( size_t nCol, size_t nRow, bool bRTL ) const 403 { 404 DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetCellIndex" ); 405 if (bRTL) 406 nCol = mxImpl->GetMirrorCol(nCol); 407 return mxImpl->GetIndex( nCol, nRow ); 408 } 409 410 // cell border styles --------------------------------------------------------- 411 412 void Array::SetCellStyleLeft( size_t nCol, size_t nRow, const Style& rStyle ) 413 { 414 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleLeft" ); 415 CELLACC( nCol, nRow ).maLeft = rStyle; 416 } 417 418 void Array::SetCellStyleRight( size_t nCol, size_t nRow, const Style& rStyle ) 419 { 420 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleRight" ); 421 CELLACC( nCol, nRow ).maRight = rStyle; 422 } 423 424 void Array::SetCellStyleTop( size_t nCol, size_t nRow, const Style& rStyle ) 425 { 426 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTop" ); 427 CELLACC( nCol, nRow ).maTop = rStyle; 428 } 429 430 void Array::SetCellStyleBottom( size_t nCol, size_t nRow, const Style& rStyle ) 431 { 432 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBottom" ); 433 CELLACC( nCol, nRow ).maBottom = rStyle; 434 } 435 436 void Array::SetCellStyleTLBR( size_t nCol, size_t nRow, const Style& rStyle ) 437 { 438 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTLBR" ); 439 CELLACC( nCol, nRow ).maTLBR = rStyle; 440 } 441 442 void Array::SetCellStyleBLTR( size_t nCol, size_t nRow, const Style& rStyle ) 443 { 444 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBLTR" ); 445 CELLACC( nCol, nRow ).maBLTR = rStyle; 446 } 447 448 void Array::SetCellStyleDiag( size_t nCol, size_t nRow, const Style& rTLBR, const Style& rBLTR ) 449 { 450 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleDiag" ); 451 Cell& rCell = CELLACC( nCol, nRow ); 452 rCell.maTLBR = rTLBR; 453 rCell.maBLTR = rBLTR; 454 } 455 456 void Array::SetColumnStyleLeft( size_t nCol, const Style& rStyle ) 457 { 458 DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleLeft" ); 459 for( size_t nRow = 0; nRow < mxImpl->mnHeight; ++nRow ) 460 SetCellStyleLeft( nCol, nRow, rStyle ); 461 } 462 463 void Array::SetColumnStyleRight( size_t nCol, const Style& rStyle ) 464 { 465 DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleRight" ); 466 for( size_t nRow = 0; nRow < mxImpl->mnHeight; ++nRow ) 467 SetCellStyleRight( nCol, nRow, rStyle ); 468 } 469 470 void Array::SetRowStyleTop( size_t nRow, const Style& rStyle ) 471 { 472 DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleTop" ); 473 for( size_t nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) 474 SetCellStyleTop( nCol, nRow, rStyle ); 475 } 476 477 void Array::SetRowStyleBottom( size_t nRow, const Style& rStyle ) 478 { 479 DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleBottom" ); 480 for( size_t nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) 481 SetCellStyleBottom( nCol, nRow, rStyle ); 482 } 483 484 const Style& Array::GetCellStyleLeft( size_t nCol, size_t nRow, bool bSimple ) const 485 { 486 // simple: always return own left style 487 if( bSimple ) 488 return CELL( nCol, nRow ).maLeft; 489 // outside clipping rows or overlapped in merged cells: invisible 490 if( !mxImpl->IsRowInClipRange( nRow ) || mxImpl->IsMergedOverlappedLeft( nCol, nRow ) ) 491 return OBJ_STYLE_NONE; 492 // left clipping border: always own left style 493 if( nCol == mxImpl->mnFirstClipCol ) 494 return ORIGCELL( nCol, nRow ).maLeft; 495 // right clipping border: always right style of left neighbor cell 496 if( nCol == mxImpl->mnLastClipCol + 1 ) 497 return ORIGCELL( nCol - 1, nRow ).maRight; 498 // outside clipping columns: invisible 499 if( !mxImpl->IsColInClipRange( nCol ) ) 500 return OBJ_STYLE_NONE; 501 // inside clipping range: maximum of own left style and right style of left neighbor cell 502 return std::max( ORIGCELL( nCol, nRow ).maLeft, ORIGCELL( nCol - 1, nRow ).maRight ); 503 } 504 505 const Style& Array::GetCellStyleRight( size_t nCol, size_t nRow, bool bSimple ) const 506 { 507 // simple: always return own right style 508 if( bSimple ) 509 return CELL( nCol, nRow ).maRight; 510 // outside clipping rows or overlapped in merged cells: invisible 511 if( !mxImpl->IsRowInClipRange( nRow ) || mxImpl->IsMergedOverlappedRight( nCol, nRow ) ) 512 return OBJ_STYLE_NONE; 513 // left clipping border: always left style of right neighbor cell 514 if( nCol + 1 == mxImpl->mnFirstClipCol ) 515 return ORIGCELL( nCol + 1, nRow ).maLeft; 516 // right clipping border: always own right style 517 if( nCol == mxImpl->mnLastClipCol ) 518 return ORIGCELL( nCol, nRow ).maRight; 519 // outside clipping columns: invisible 520 if( !mxImpl->IsColInClipRange( nCol ) ) 521 return OBJ_STYLE_NONE; 522 // inside clipping range: maximum of own right style and left style of right neighbor cell 523 return std::max( ORIGCELL( nCol, nRow ).maRight, ORIGCELL( nCol + 1, nRow ).maLeft ); 524 } 525 526 const Style& Array::GetCellStyleTop( size_t nCol, size_t nRow, bool bSimple ) const 527 { 528 // simple: always return own top style 529 if( bSimple ) 530 return CELL( nCol, nRow ).maTop; 531 // outside clipping columns or overlapped in merged cells: invisible 532 if( !mxImpl->IsColInClipRange( nCol ) || mxImpl->IsMergedOverlappedTop( nCol, nRow ) ) 533 return OBJ_STYLE_NONE; 534 // top clipping border: always own top style 535 if( nRow == mxImpl->mnFirstClipRow ) 536 return ORIGCELL( nCol, nRow ).maTop; 537 // bottom clipping border: always bottom style of top neighbor cell 538 if( nRow == mxImpl->mnLastClipRow + 1 ) 539 return ORIGCELL( nCol, nRow - 1 ).maBottom; 540 // outside clipping rows: invisible 541 if( !mxImpl->IsRowInClipRange( nRow ) ) 542 return OBJ_STYLE_NONE; 543 // inside clipping range: maximum of own top style and bottom style of top neighbor cell 544 return std::max( ORIGCELL( nCol, nRow ).maTop, ORIGCELL( nCol, nRow - 1 ).maBottom ); 545 } 546 547 const Style& Array::GetCellStyleBottom( size_t nCol, size_t nRow, bool bSimple ) const 548 { 549 // simple: always return own bottom style 550 if( bSimple ) 551 return CELL( nCol, nRow ).maBottom; 552 // outside clipping columns or overlapped in merged cells: invisible 553 if( !mxImpl->IsColInClipRange( nCol ) || mxImpl->IsMergedOverlappedBottom( nCol, nRow ) ) 554 return OBJ_STYLE_NONE; 555 // top clipping border: always top style of bottom neighbor cell 556 if( nRow + 1 == mxImpl->mnFirstClipRow ) 557 return ORIGCELL( nCol, nRow + 1 ).maTop; 558 // bottom clipping border: always own bottom style 559 if( nRow == mxImpl->mnLastClipRow ) 560 return ORIGCELL( nCol, nRow ).maBottom; 561 // outside clipping rows: invisible 562 if( !mxImpl->IsRowInClipRange( nRow ) ) 563 return OBJ_STYLE_NONE; 564 // inside clipping range: maximum of own bottom style and top style of bottom neighbor cell 565 return std::max( ORIGCELL( nCol, nRow ).maBottom, ORIGCELL( nCol, nRow + 1 ).maTop ); 566 } 567 568 const Style& Array::GetCellStyleTLBR( size_t nCol, size_t nRow, bool bSimple ) const 569 { 570 return bSimple ? CELL( nCol, nRow ).maTLBR : 571 (mxImpl->IsInClipRange( nCol, nRow ) ? ORIGCELL( nCol, nRow ).maTLBR : OBJ_STYLE_NONE); 572 } 573 574 const Style& Array::GetCellStyleBLTR( size_t nCol, size_t nRow, bool bSimple ) const 575 { 576 return bSimple ? CELL( nCol, nRow ).maBLTR : 577 (mxImpl->IsInClipRange( nCol, nRow ) ? ORIGCELL( nCol, nRow ).maBLTR : OBJ_STYLE_NONE); 578 } 579 580 const Style& Array::GetCellStyleTL( size_t nCol, size_t nRow ) const 581 { 582 // not in clipping range: always invisible 583 if( !mxImpl->IsInClipRange( nCol, nRow ) ) 584 return OBJ_STYLE_NONE; 585 // return style only for top-left cell 586 size_t nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); 587 size_t nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); 588 return ((nCol == nFirstCol) && (nRow == nFirstRow)) ? 589 CELL( nFirstCol, nFirstRow ).maTLBR : OBJ_STYLE_NONE; 590 } 591 592 const Style& Array::GetCellStyleBR( size_t nCol, size_t nRow ) const 593 { 594 // not in clipping range: always invisible 595 if( !mxImpl->IsInClipRange( nCol, nRow ) ) 596 return OBJ_STYLE_NONE; 597 // return style only for bottom-right cell 598 size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); 599 size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); 600 return ((nCol == nLastCol) && (nRow == nLastRow)) ? 601 CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), mxImpl->GetMergedFirstRow( nCol, nRow ) ).maTLBR : OBJ_STYLE_NONE; 602 } 603 604 const Style& Array::GetCellStyleBL( size_t nCol, size_t nRow ) const 605 { 606 // not in clipping range: always invisible 607 if( !mxImpl->IsInClipRange( nCol, nRow ) ) 608 return OBJ_STYLE_NONE; 609 // return style only for bottom-left cell 610 size_t nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); 611 size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); 612 return ((nCol == nFirstCol) && (nRow == nLastRow)) ? 613 CELL( nFirstCol, mxImpl->GetMergedFirstRow( nCol, nRow ) ).maBLTR : OBJ_STYLE_NONE; 614 } 615 616 const Style& Array::GetCellStyleTR( size_t nCol, size_t nRow ) const 617 { 618 // not in clipping range: always invisible 619 if( !mxImpl->IsInClipRange( nCol, nRow ) ) 620 return OBJ_STYLE_NONE; 621 // return style only for top-right cell 622 size_t nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); 623 size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); 624 return ((nCol == nLastCol) && (nRow == nFirstRow)) ? 625 CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), nFirstRow ).maBLTR : OBJ_STYLE_NONE; 626 } 627 628 // cell merging --------------------------------------------------------------- 629 630 void Array::SetMergedRange( size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow ) 631 { 632 DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetMergedRange" ); 633 DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetMergedRange" ); 634 #if OSL_DEBUG_LEVEL >= 2 635 { 636 bool bFound = false; 637 for( size_t nCurrCol = nFirstCol; !bFound && (nCurrCol <= nLastCol); ++nCurrCol ) 638 for( size_t nCurrRow = nFirstRow; !bFound && (nCurrRow <= nLastRow); ++nCurrRow ) 639 bFound = CELL( nCurrCol, nCurrRow ).IsMerged(); 640 DBG_FRAME_CHECK( !bFound, "SetMergedRange", "overlapping merged ranges" ); 641 } 642 #endif 643 if( mxImpl->IsValidPos( nFirstCol, nFirstRow ) && mxImpl->IsValidPos( nLastCol, nLastRow ) ) 644 lclSetMergedRange( mxImpl->maCells, mxImpl->mnWidth, nFirstCol, nFirstRow, nLastCol, nLastRow ); 645 } 646 647 void Array::RemoveMergedRange( size_t nCol, size_t nRow ) 648 { 649 DBG_FRAME_CHECK_COLROW( nCol, nRow, "RemoveMergedRange" ); 650 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt ) 651 { 652 Cell& rCell = CELLACC( aIt.Col(), aIt.Row() ); 653 rCell.mbMergeOrig = rCell.mbOverlapX = rCell.mbOverlapY = false; 654 rCell.mnAddLeft = rCell.mnAddRight = rCell.mnAddTop = rCell.mnAddBottom = 0; 655 } 656 } 657 658 void Array::SetAddMergedLeftSize( size_t nCol, size_t nRow, long nAddSize ) 659 { 660 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedLeftSize" ); 661 DBG_FRAME_CHECK( mxImpl->GetMergedFirstCol( nCol, nRow ) == 0, "SetAddMergedLeftSize", "additional border inside array" ); 662 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt ) 663 CELLACC( aIt.Col(), aIt.Row() ).mnAddLeft = nAddSize; 664 } 665 666 void Array::SetAddMergedRightSize( size_t nCol, size_t nRow, long nAddSize ) 667 { 668 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedRightSize" ); 669 DBG_FRAME_CHECK( mxImpl->GetMergedLastCol( nCol, nRow ) + 1 == mxImpl->mnWidth, "SetAddMergedRightSize", "additional border inside array" ); 670 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt ) 671 CELLACC( aIt.Col(), aIt.Row() ).mnAddRight = nAddSize; 672 } 673 674 void Array::SetAddMergedTopSize( size_t nCol, size_t nRow, long nAddSize ) 675 { 676 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedTopSize" ); 677 DBG_FRAME_CHECK( mxImpl->GetMergedFirstRow( nCol, nRow ) == 0, "SetAddMergedTopSize", "additional border inside array" ); 678 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt ) 679 CELLACC( aIt.Col(), aIt.Row() ).mnAddTop = nAddSize; 680 } 681 682 void Array::SetAddMergedBottomSize( size_t nCol, size_t nRow, long nAddSize ) 683 { 684 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedBottomSize" ); 685 DBG_FRAME_CHECK( mxImpl->GetMergedLastRow( nCol, nRow ) + 1 == mxImpl->mnHeight, "SetAddMergedBottomSize", "additional border inside array" ); 686 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt ) 687 CELLACC( aIt.Col(), aIt.Row() ).mnAddBottom = nAddSize; 688 } 689 690 bool Array::IsMerged( size_t nCol, size_t nRow ) const 691 { 692 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMerged" ); 693 return CELL( nCol, nRow ).IsMerged(); 694 } 695 696 bool Array::IsMergedOrigin( size_t nCol, size_t nRow ) const 697 { 698 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOrigin" ); 699 return CELL( nCol, nRow ).mbMergeOrig; 700 } 701 702 bool Array::IsMergedOverlapped( size_t nCol, size_t nRow ) const 703 { 704 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlapped" ); 705 return CELL( nCol, nRow ).IsOverlapped(); 706 } 707 708 bool Array::IsMergedOverlappedLeft( size_t nCol, size_t nRow ) const 709 { 710 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlappedLeft" ); 711 return mxImpl->IsMergedOverlappedLeft( nCol, nRow ); 712 } 713 714 bool Array::IsMergedOverlappedRight( size_t nCol, size_t nRow ) const 715 { 716 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlappedRight" ); 717 return mxImpl->IsMergedOverlappedRight( nCol, nRow ); 718 } 719 720 bool Array::IsMergedOverlappedTop( size_t nCol, size_t nRow ) const 721 { 722 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlappedTop" ); 723 return mxImpl->IsMergedOverlappedTop( nCol, nRow ); 724 } 725 726 bool Array::IsMergedOverlappedBottom( size_t nCol, size_t nRow ) const 727 { 728 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlappedBottom" ); 729 return mxImpl->IsMergedOverlappedBottom( nCol, nRow ); 730 } 731 732 void Array::GetMergedOrigin( size_t& rnFirstCol, size_t& rnFirstRow, size_t nCol, size_t nRow ) const 733 { 734 DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetMergedOrigin" ); 735 rnFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); 736 rnFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); 737 } 738 739 void Array::GetMergedSize( size_t& rnWidth, size_t& rnHeight, size_t nCol, size_t nRow ) const 740 { 741 size_t nFirstCol, nFirstRow, nLastCol, nLastRow; 742 GetMergedRange( nFirstCol, nFirstRow, nLastCol, nLastRow, nCol, nRow ); 743 rnWidth = nLastCol - nFirstCol + 1; 744 rnHeight = nLastRow - nFirstRow + 1; 745 } 746 747 void Array::GetMergedRange( size_t& rnFirstCol, size_t& rnFirstRow, 748 size_t& rnLastCol, size_t& rnLastRow, size_t nCol, size_t nRow ) const 749 { 750 GetMergedOrigin( rnFirstCol, rnFirstRow, nCol, nRow ); 751 rnLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); 752 rnLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); 753 } 754 755 // clipping ------------------------------------------------------------------- 756 757 void Array::SetClipRange( size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow ) 758 { 759 DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetClipRange" ); 760 DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetClipRange" ); 761 mxImpl->mnFirstClipCol = nFirstCol; 762 mxImpl->mnFirstClipRow = nFirstRow; 763 mxImpl->mnLastClipCol = nLastCol; 764 mxImpl->mnLastClipRow = nLastRow; 765 } 766 767 void Array::RemoveClipRange() 768 { 769 if( !mxImpl->maCells.empty() ) 770 SetClipRange( 0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1 ); 771 } 772 773 bool Array::IsInClipRange( size_t nCol, size_t nRow ) const 774 { 775 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsInClipRange" ); 776 return mxImpl->IsInClipRange( nCol, nRow ); 777 } 778 779 Rectangle Array::GetClipRangeRectangle() const 780 { 781 return Rectangle( 782 mxImpl->GetColPosition( mxImpl->mnFirstClipCol ), 783 mxImpl->GetRowPosition( mxImpl->mnFirstClipRow ), 784 mxImpl->GetColPosition( mxImpl->mnLastClipCol + 1 ), 785 mxImpl->GetRowPosition( mxImpl->mnLastClipRow + 1 ) ); 786 } 787 788 // cell coordinates ----------------------------------------------------------- 789 790 void Array::SetXOffset( long nXOffset ) 791 { 792 mxImpl->maXCoords[ 0 ] = nXOffset; 793 mxImpl->mbXCoordsDirty = true; 794 } 795 796 void Array::SetYOffset( long nYOffset ) 797 { 798 mxImpl->maYCoords[ 0 ] = nYOffset; 799 mxImpl->mbYCoordsDirty = true; 800 } 801 802 void Array::SetColWidth( size_t nCol, long nWidth ) 803 { 804 DBG_FRAME_CHECK_COL( nCol, "SetColWidth" ); 805 mxImpl->maWidths[ nCol ] = nWidth; 806 mxImpl->mbXCoordsDirty = true; 807 } 808 809 void Array::SetRowHeight( size_t nRow, long nHeight ) 810 { 811 DBG_FRAME_CHECK_ROW( nRow, "SetRowHeight" ); 812 mxImpl->maHeights[ nRow ] = nHeight; 813 mxImpl->mbYCoordsDirty = true; 814 } 815 816 void Array::SetAllColWidths( long nWidth ) 817 { 818 std::fill( mxImpl->maWidths.begin(), mxImpl->maWidths.end(), nWidth ); 819 mxImpl->mbXCoordsDirty = true; 820 } 821 822 void Array::SetAllRowHeights( long nHeight ) 823 { 824 std::fill( mxImpl->maHeights.begin(), mxImpl->maHeights.end(), nHeight ); 825 mxImpl->mbYCoordsDirty = true; 826 } 827 828 long Array::GetColPosition( size_t nCol ) const 829 { 830 DBG_FRAME_CHECK_COL_1( nCol, "GetColPosition" ); 831 return mxImpl->GetColPosition( nCol ); 832 } 833 834 long Array::GetRowPosition( size_t nRow ) const 835 { 836 DBG_FRAME_CHECK_ROW_1( nRow, "GetRowPosition" ); 837 return mxImpl->GetRowPosition( nRow ); 838 } 839 840 long Array::GetColWidth( size_t nCol ) const 841 { 842 DBG_FRAME_CHECK_COL( nCol, "GetColWidth" ); 843 return mxImpl->maWidths[ nCol ]; 844 } 845 846 long Array::GetColWidth( size_t nFirstCol, size_t nLastCol ) const 847 { 848 DBG_FRAME_CHECK_COL( nFirstCol, "GetColWidth" ); 849 DBG_FRAME_CHECK_COL( nLastCol, "GetColWidth" ); 850 return GetColPosition( nLastCol + 1 ) - GetColPosition( nFirstCol ); 851 } 852 853 long Array::GetRowHeight( size_t nRow ) const 854 { 855 DBG_FRAME_CHECK_ROW( nRow, "GetRowHeight" ); 856 return mxImpl->maHeights[ nRow ]; 857 } 858 859 long Array::GetRowHeight( size_t nFirstRow, size_t nLastRow ) const 860 { 861 DBG_FRAME_CHECK_ROW( nFirstRow, "GetRowHeight" ); 862 DBG_FRAME_CHECK_ROW( nLastRow, "GetRowHeight" ); 863 return GetRowPosition( nLastRow + 1 ) - GetRowPosition( nFirstRow ); 864 } 865 866 long Array::GetWidth() const 867 { 868 return GetColPosition( mxImpl->mnWidth ) - GetColPosition( 0 ); 869 } 870 871 long Array::GetHeight() const 872 { 873 return GetRowPosition( mxImpl->mnHeight ) - GetRowPosition( 0 ); 874 } 875 876 Point Array::GetCellPosition( size_t nCol, size_t nRow, bool bSimple ) const 877 { 878 size_t nFirstCol = bSimple ? nCol : mxImpl->GetMergedFirstCol( nCol, nRow ); 879 size_t nFirstRow = bSimple ? nRow : mxImpl->GetMergedFirstRow( nCol, nRow ); 880 return Point( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) ); 881 } 882 883 Size Array::GetCellSize( size_t nCol, size_t nRow, bool bSimple ) const 884 { 885 size_t nFirstCol = bSimple ? nCol : mxImpl->GetMergedFirstCol( nCol, nRow ); 886 size_t nFirstRow = bSimple ? nRow : mxImpl->GetMergedFirstRow( nCol, nRow ); 887 size_t nLastCol = bSimple ? nCol : mxImpl->GetMergedLastCol( nCol, nRow ); 888 size_t nLastRow = bSimple ? nRow : mxImpl->GetMergedLastRow( nCol, nRow ); 889 return Size( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 ); 890 } 891 892 Rectangle Array::GetCellRect( size_t nCol, size_t nRow, bool bSimple ) const 893 { 894 Rectangle aRect( GetCellPosition( nCol, nRow, bSimple ), GetCellSize( nCol, nRow, bSimple ) ); 895 896 // adjust rectangle for partly visible merged cells 897 const Cell& rCell = CELL( nCol, nRow ); 898 if( !bSimple && rCell.IsMerged() ) 899 { 900 aRect.Left() -= rCell.mnAddLeft; 901 aRect.Right() += rCell.mnAddRight; 902 aRect.Top() -= rCell.mnAddTop; 903 aRect.Bottom() += rCell.mnAddBottom; 904 } 905 return aRect; 906 } 907 908 // diagonal frame borders ----------------------------------------------------- 909 910 double Array::GetHorDiagAngle( size_t nCol, size_t nRow, bool bSimple ) const 911 { 912 DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetHorDiagAngle" ); 913 return mxImpl->GetHorDiagAngle( nCol, nRow, bSimple ); 914 } 915 916 double Array::GetVerDiagAngle( size_t nCol, size_t nRow, bool bSimple ) const 917 { 918 DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetVerDiagAngle" ); 919 return mxImpl->GetVerDiagAngle( nCol, nRow, bSimple ); 920 } 921 922 void Array::SetUseDiagDoubleClipping( bool bSet ) 923 { 924 mxImpl->mbDiagDblClip = bSet; 925 } 926 927 bool Array::GetUseDiagDoubleClipping() const 928 { 929 return mxImpl->mbDiagDblClip; 930 } 931 932 // mirroring ------------------------------------------------------------------ 933 934 void Array::MirrorSelfX( bool bMirrorStyles, bool bSwapDiag ) 935 { 936 CellVec aNewCells; 937 aNewCells.reserve( GetCellCount() ); 938 939 size_t nCol, nRow; 940 for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow ) 941 { 942 for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) 943 { 944 aNewCells.push_back( CELL( mxImpl->GetMirrorCol( nCol ), nRow ) ); 945 aNewCells.back().MirrorSelfX( bMirrorStyles, bSwapDiag ); 946 } 947 } 948 for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow ) 949 { 950 for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) 951 { 952 if( CELL( nCol, nRow ).mbMergeOrig ) 953 { 954 size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); 955 size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); 956 lclSetMergedRange( aNewCells, mxImpl->mnWidth, 957 mxImpl->GetMirrorCol( nLastCol ), nRow, 958 mxImpl->GetMirrorCol( nCol ), nLastRow ); 959 } 960 } 961 } 962 mxImpl->maCells.swap( aNewCells ); 963 964 std::reverse( mxImpl->maWidths.begin(), mxImpl->maWidths.end() ); 965 mxImpl->mbXCoordsDirty = true; 966 } 967 968 void Array::MirrorSelfY( bool bMirrorStyles, bool bSwapDiag ) 969 { 970 CellVec aNewCells; 971 aNewCells.reserve( GetCellCount() ); 972 973 size_t nCol, nRow; 974 for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow ) 975 { 976 for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) 977 { 978 aNewCells.push_back( CELL( nCol, mxImpl->GetMirrorRow( nRow ) ) ); 979 aNewCells.back().MirrorSelfY( bMirrorStyles, bSwapDiag ); 980 } 981 } 982 for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow ) 983 { 984 for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) 985 { 986 if( CELL( nCol, nRow ).mbMergeOrig ) 987 { 988 size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); 989 size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); 990 lclSetMergedRange( aNewCells, mxImpl->mnWidth, 991 nCol, mxImpl->GetMirrorRow( nLastRow ), 992 nLastCol, mxImpl->GetMirrorRow( nRow ) ); 993 } 994 } 995 } 996 mxImpl->maCells.swap( aNewCells ); 997 998 std::reverse( mxImpl->maHeights.begin(), mxImpl->maHeights.end() ); 999 mxImpl->mbYCoordsDirty = true; 1000 } 1001 1002 // drawing -------------------------------------------------------------------- 1003 1004 void Array::DrawCell( OutputDevice& rDev, size_t nCol, size_t nRow, const Color* pForceColor ) const 1005 { 1006 DrawRange( rDev, nCol, nRow, nCol, nRow, pForceColor ); 1007 } 1008 1009 void Array::DrawRange( OutputDevice& rDev, 1010 size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow, 1011 const Color* pForceColor ) const 1012 { 1013 DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "DrawRange" ); 1014 DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "DrawRange" ); 1015 1016 size_t nCol, nRow; 1017 1018 // *** diagonal frame borders *** 1019 1020 // set clipping region to clip partly visible merged cells 1021 rDev.Push( PUSH_CLIPREGION ); 1022 rDev.IntersectClipRegion( GetClipRangeRectangle() ); 1023 for( nRow = nFirstRow; nRow <= nLastRow; ++nRow ) 1024 { 1025 for( nCol = nFirstCol; nCol <= nLastCol; ++nCol ) 1026 { 1027 const Cell& rCell = CELL( nCol, nRow ); 1028 bool bOverlapX = rCell.mbOverlapX; 1029 bool bOverlapY = rCell.mbOverlapY; 1030 bool bFirstCol = nCol == nFirstCol; 1031 bool bFirstRow = nRow == nFirstRow; 1032 if( (!bOverlapX && !bOverlapY) || (bFirstCol && bFirstRow) || 1033 (!bOverlapY && bFirstCol) || (!bOverlapX && bFirstRow) ) 1034 { 1035 Rectangle aRect( GetCellRect( nCol, nRow ) ); 1036 if( (aRect.GetWidth() > 1) && (aRect.GetHeight() > 1) ) 1037 { 1038 size_t _nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); 1039 size_t _nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); 1040 size_t _nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); 1041 size_t _nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); 1042 1043 DrawDiagFrameBorders( rDev, aRect, 1044 GetCellStyleTLBR( _nFirstCol, _nFirstRow, true ), GetCellStyleBLTR( _nFirstCol, _nFirstRow, true ), 1045 GetCellStyleLeft( _nFirstCol, _nFirstRow ), GetCellStyleTop( _nFirstCol, _nFirstRow ), 1046 GetCellStyleRight( _nLastCol, _nLastRow ), GetCellStyleBottom( _nLastCol, _nLastRow ), 1047 GetCellStyleLeft( _nFirstCol, _nLastRow ), GetCellStyleBottom( _nFirstCol, _nLastRow ), 1048 GetCellStyleRight( _nLastCol, _nFirstRow ), GetCellStyleTop( _nLastCol, _nFirstRow ), 1049 pForceColor, mxImpl->mbDiagDblClip ); 1050 } 1051 } 1052 } 1053 } 1054 rDev.Pop(); // clip region 1055 1056 // *** horizontal frame borders *** 1057 1058 for( nRow = nFirstRow; nRow <= nLastRow + 1; ++nRow ) 1059 { 1060 double fAngle = mxImpl->GetHorDiagAngle( nFirstCol, nRow ); 1061 double fTAngle = mxImpl->GetHorDiagAngle( nFirstCol, nRow - 1 ); 1062 1063 // *Start*** variables store the data of the left end of the cached frame border 1064 Point aStartPos( mxImpl->GetColPosition( nFirstCol ), mxImpl->GetRowPosition( nRow ) ); 1065 const Style* pStart = &GetCellStyleTop( nFirstCol, nRow ); 1066 DiagStyle aStartLFromTR( GetCellStyleBL( nFirstCol, nRow - 1 ), fTAngle ); 1067 const Style* pStartLFromT = &GetCellStyleLeft( nFirstCol, nRow - 1 ); 1068 const Style* pStartLFromL = &GetCellStyleTop( nFirstCol - 1, nRow ); 1069 const Style* pStartLFromB = &GetCellStyleLeft( nFirstCol, nRow ); 1070 DiagStyle aStartLFromBR( GetCellStyleTL( nFirstCol, nRow ), fAngle ); 1071 1072 // *End*** variables store the data of the right end of the cached frame border 1073 DiagStyle aEndRFromTL( GetCellStyleBR( nFirstCol, nRow - 1 ), fTAngle ); 1074 const Style* pEndRFromT = &GetCellStyleRight( nFirstCol, nRow - 1 ); 1075 const Style* pEndRFromR = &GetCellStyleTop( nFirstCol + 1, nRow ); 1076 const Style* pEndRFromB = &GetCellStyleRight( nFirstCol, nRow ); 1077 DiagStyle aEndRFromBL( GetCellStyleTR( nFirstCol, nRow ), fAngle ); 1078 1079 for( nCol = nFirstCol + 1; nCol <= nLastCol; ++nCol ) 1080 { 1081 fAngle = mxImpl->GetHorDiagAngle( nCol, nRow ); 1082 fTAngle = mxImpl->GetHorDiagAngle( nCol, nRow - 1 ); 1083 1084 const Style& rCurr = *pEndRFromR; 1085 1086 DiagStyle aLFromTR( GetCellStyleBL( nCol, nRow - 1 ), fTAngle ); 1087 const Style& rLFromT = *pEndRFromT; 1088 const Style& rLFromL = *pStart; 1089 const Style& rLFromB = *pEndRFromB; 1090 DiagStyle aLFromBR( GetCellStyleTL( nCol, nRow ), fAngle ); 1091 1092 DiagStyle aRFromTL( GetCellStyleBR( nCol, nRow - 1 ), fTAngle ); 1093 const Style& rRFromT = GetCellStyleRight( nCol, nRow - 1 ); 1094 const Style& rRFromR = GetCellStyleTop( nCol + 1, nRow ); 1095 const Style& rRFromB = GetCellStyleRight( nCol, nRow ); 1096 DiagStyle aRFromBL( GetCellStyleTR( nCol, nRow ), fAngle ); 1097 1098 // check if current frame border can be connected to cached frame border 1099 if( !CheckFrameBorderConnectable( *pStart, rCurr, 1100 aEndRFromTL, rLFromT, aLFromTR, aEndRFromBL, rLFromB, aLFromBR ) ) 1101 { 1102 // draw previous frame border 1103 Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() ); 1104 if( pStart->Prim() && (aStartPos.X() <= aEndPos.X()) ) 1105 DrawHorFrameBorder( rDev, aStartPos, aEndPos, *pStart, 1106 aStartLFromTR, *pStartLFromT, *pStartLFromL, *pStartLFromB, aStartLFromBR, 1107 aEndRFromTL, *pEndRFromT, *pEndRFromR, *pEndRFromB, aEndRFromBL, pForceColor ); 1108 1109 // re-init "*Start***" variables 1110 aStartPos = aEndPos; 1111 pStart = &rCurr; 1112 aStartLFromTR = aLFromTR; 1113 pStartLFromT = &rLFromT; 1114 pStartLFromL = &rLFromL; 1115 pStartLFromB = &rLFromB; 1116 aStartLFromBR = aLFromBR; 1117 } 1118 1119 // store current styles in "*End***" variables 1120 aEndRFromTL = aRFromTL; 1121 pEndRFromT = &rRFromT; 1122 pEndRFromR = &rRFromR; 1123 pEndRFromB = &rRFromB; 1124 aEndRFromBL = aRFromBL; 1125 } 1126 1127 // draw last frame border 1128 Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() ); 1129 if( pStart->Prim() && (aStartPos.X() <= aEndPos.X()) ) 1130 DrawHorFrameBorder( rDev, aStartPos, aEndPos, *pStart, 1131 aStartLFromTR, *pStartLFromT, *pStartLFromL, *pStartLFromB, aStartLFromBR, 1132 aEndRFromTL, *pEndRFromT, *pEndRFromR, *pEndRFromB, aEndRFromBL, pForceColor ); 1133 } 1134 1135 // *** vertical frame borders *** 1136 1137 for( nCol = nFirstCol; nCol <= nLastCol + 1; ++nCol ) 1138 { 1139 double fAngle = mxImpl->GetVerDiagAngle( nCol, nFirstRow ); 1140 double fLAngle = mxImpl->GetVerDiagAngle( nCol - 1, nFirstRow ); 1141 1142 // *Start*** variables store the data of the top end of the cached frame border 1143 Point aStartPos( mxImpl->GetColPosition( nCol ), mxImpl->GetRowPosition( nFirstRow ) ); 1144 const Style* pStart = &GetCellStyleLeft( nCol, nFirstRow ); 1145 DiagStyle aStartTFromBL( GetCellStyleTR( nCol - 1, nFirstRow ), fLAngle ); 1146 const Style* pStartTFromL = &GetCellStyleTop( nCol - 1, nFirstRow ); 1147 const Style* pStartTFromT = &GetCellStyleLeft( nCol, nFirstRow - 1 ); 1148 const Style* pStartTFromR = &GetCellStyleTop( nCol, nFirstRow ); 1149 DiagStyle aStartTFromBR( GetCellStyleTL( nCol, nFirstRow ), fAngle ); 1150 1151 // *End*** variables store the data of the bottom end of the cached frame border 1152 DiagStyle aEndBFromTL( GetCellStyleBR( nCol - 1, nFirstRow ), fLAngle ); 1153 const Style* pEndBFromL = &GetCellStyleBottom( nCol - 1, nFirstRow ); 1154 const Style* pEndBFromB = &GetCellStyleLeft( nCol, nFirstRow + 1 ); 1155 const Style* pEndBFromR = &GetCellStyleBottom( nCol, nFirstRow ); 1156 DiagStyle aEndBFromTR( GetCellStyleBL( nCol, nFirstRow ), fAngle ); 1157 1158 for( nRow = nFirstRow + 1; nRow <= nLastRow; ++nRow ) 1159 { 1160 fAngle = mxImpl->GetVerDiagAngle( nCol, nRow ); 1161 fLAngle = mxImpl->GetVerDiagAngle( nCol - 1, nRow ); 1162 1163 const Style& rCurr = *pEndBFromB; 1164 1165 DiagStyle aTFromBL( GetCellStyleTR( nCol - 1, nRow ), fLAngle ); 1166 const Style& rTFromL = *pEndBFromL; 1167 const Style& rTFromT = *pStart; 1168 const Style& rTFromR = *pEndBFromR; 1169 DiagStyle aTFromBR( GetCellStyleTL( nCol, nRow ), fAngle ); 1170 1171 DiagStyle aBFromTL( GetCellStyleBR( nCol - 1, nRow ), fLAngle ); 1172 const Style& rBFromL = GetCellStyleBottom( nCol - 1, nRow ); 1173 const Style& rBFromB = GetCellStyleLeft( nCol, nRow + 1 ); 1174 const Style& rBFromR = GetCellStyleBottom( nCol, nRow ); 1175 DiagStyle aBFromTR( GetCellStyleBL( nCol, nRow ), fAngle ); 1176 1177 // check if current frame border can be connected to cached frame border 1178 if( !CheckFrameBorderConnectable( *pStart, rCurr, 1179 aEndBFromTL, rTFromL, aTFromBL, aEndBFromTR, rTFromR, aTFromBR ) ) 1180 { 1181 // draw previous frame border 1182 Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) ); 1183 if( pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()) ) 1184 DrawVerFrameBorder( rDev, aStartPos, aEndPos, *pStart, 1185 aStartTFromBL, *pStartTFromL, *pStartTFromT, *pStartTFromR, aStartTFromBR, 1186 aEndBFromTL, *pEndBFromL, *pEndBFromB, *pEndBFromR, aEndBFromTR, pForceColor ); 1187 1188 // re-init "*Start***" variables 1189 aStartPos = aEndPos; 1190 pStart = &rCurr; 1191 aStartTFromBL = aTFromBL; 1192 pStartTFromL = &rTFromL; 1193 pStartTFromT = &rTFromT; 1194 pStartTFromR = &rTFromR; 1195 aStartTFromBR = aTFromBR; 1196 } 1197 1198 // store current styles in "*End***" variables 1199 aEndBFromTL = aBFromTL; 1200 pEndBFromL = &rBFromL; 1201 pEndBFromB = &rBFromB; 1202 pEndBFromR = &rBFromR; 1203 aEndBFromTR = aBFromTR; 1204 } 1205 1206 // draw last frame border 1207 Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) ); 1208 if( pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()) ) 1209 DrawVerFrameBorder( rDev, aStartPos, aEndPos, *pStart, 1210 aStartTFromBL, *pStartTFromL, *pStartTFromT, *pStartTFromR, aStartTFromBR, 1211 aEndBFromTL, *pEndBFromL, *pEndBFromB, *pEndBFromR, aEndBFromTR, pForceColor ); 1212 } 1213 } 1214 1215 void Array::DrawArray( OutputDevice& rDev, const Color* pForceColor ) const 1216 { 1217 if( mxImpl->mnWidth && mxImpl->mnHeight ) 1218 DrawRange( rDev, 0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1, pForceColor ); 1219 } 1220 1221 // ---------------------------------------------------------------------------- 1222 1223 #undef ORIGCELLACC 1224 #undef ORIGCELL 1225 #undef CELLACC 1226 #undef CELL 1227 1228 // ---------------------------------------------------------------------------- 1229 1230 #undef DBG_FRAME_CHECK_ROW_1 1231 #undef DBG_FRAME_CHECK_COL_1 1232 #undef DBG_FRAME_CHECK_INDEX 1233 #undef DBG_FRAME_CHECK_COLROW 1234 #undef DBG_FRAME_CHECK_ROW 1235 #undef DBG_FRAME_CHECK_COL 1236 #undef DBG_FRAME_CHECK 1237 #undef DBG_FRAME_ERROR 1238 1239 // ============================================================================ 1240 1241 } // namespace frame 1242 } // namespace svx 1243 1244