00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #pragma once
00016 #include <background_wnd/detail/include.hpp>
00017
00018
00019 namespace win32 { namespace gui {
00020 namespace bg_wnd {
00021
00022 template <class CellData> class table;
00023
00024 namespace detail {
00025 template <class Table> class forward_proxy;
00026 }
00027
00028
00029
00033 class COORDS
00034 {
00035 unsigned col_;
00036 unsigned row_;
00037
00038 public:
00040 COORDS(unsigned col, unsigned row) : col_(col), row_(row)
00041 {}
00042
00044 void row(unsigned r)
00045 {
00046 row_ = r;
00047 }
00048
00050 unsigned row() const
00051 {
00052 return row_;
00053 }
00054
00056 void col(unsigned c)
00057 {
00058 col_ = c;
00059 }
00060
00062 unsigned col() const
00063 {
00064 return col_;
00065 }
00066
00068 void move(int horz, int vert)
00069 {
00070 col_ += horz;
00071 row_ += vert;
00072 }
00073
00075 bool operator== (COORDS coords) const
00076 {
00077 return row_ == coords.row() && col_ == coords.col();
00078 }
00079
00081 bool operator!= (COORDS coords) const
00082 {
00083 return ! operator== (coords);
00084 }
00085
00087 void swap(COORDS& coords)
00088 {
00089 std::swap(row_, coords.row_);
00090 std::swap(col_, coords.col_);
00091 }
00092 };
00093
00094
00095
00099 class cell_range
00100 {
00101 COORDS top_left_;
00102 COORDS bottom_right_;
00103
00104 inline static bool between(unsigned val, unsigned start, unsigned end)
00105 {
00106 return (start <= val && val <= end);
00107 }
00108
00109 public:
00111 cell_range(COORDS topleft, COORDS bottomright)
00112 : top_left_(topleft), bottom_right_(bottomright)
00113 {
00114 _ASSERTE(top_left_.col() <= bottom_right_.col());
00115 _ASSERTE(top_left_.row() <= bottom_right_.row());
00116 }
00117
00124 cell_range(COORDS topleft, unsigned horz_count, unsigned vert_count)
00125 : top_left_( topleft ),
00126 bottom_right_( topleft.col() + ((horz_count == 0) ? 0 : horz_count - 1), topleft.row() + ((vert_count == 0) ? 0 : vert_count - 1) )
00127 {}
00128
00130 bool is_intersecting(const cell_range& range) const
00131 {
00132 bool bHorz = between(range.top_left_.col(), top_left_.col(), bottom_right_.col()) ||
00133 between(range.bottom_right_.col(), top_left_.col(), bottom_right_.col()) ||
00134 between(top_left_.col(), range.top_left_.col(), range.bottom_right_.col()) ||
00135 between(bottom_right_.col(), range.top_left_.col(), range.bottom_right_.col());
00136
00137 bool bVert = between(range.top_left_.row(), top_left_.row(), bottom_right_.row()) ||
00138 between(range.bottom_right_.row(), top_left_.row(), bottom_right_.row()) ||
00139 between(top_left_.row(), range.top_left_.row(), range.bottom_right_.row()) ||
00140 between(bottom_right_.row(), range.top_left_.row(), range.bottom_right_.row());
00141 return bHorz && bVert;
00142 }
00143
00145 cell_range operator+ (const cell_range& range) const
00146 {
00147 cell_range m_ret(*this);
00148 m_ret += range;
00149 return m_ret;
00150 }
00151
00153 void operator+= (const cell_range& range)
00154 {
00155 top_left_.col( min(top_left_.col(), range.top_left_.col()) );
00156 top_left_.row( min(top_left_.row(), range.top_left_.row()) );
00157 bottom_right_.col( max(bottom_right_.col(), range.bottom_right_.col()) );
00158 bottom_right_.row( max(bottom_right_.row(), range.bottom_right_.row()) );
00159 }
00160
00162 bool operator== (const cell_range& range) const
00163 {
00164 return top_left_ == range.top_left_ &&
00165 bottom_right_ == range.bottom_right_;
00166 }
00167
00169 bool operator!= (const cell_range& range) const
00170 {
00171 return ! operator==(range);
00172 }
00173
00175 COORDS top_left() const
00176 {
00177 return top_left_;
00178 }
00179
00181 COORDS bottom_right() const
00182 {
00183 return bottom_right_;
00184 }
00185
00187 void move(int horz, int vert)
00188 {
00189
00190 int horz_amount = top_left_.col() + horz;
00191 int vert_amount = top_left_.row() + vert;
00192 if (horz_amount < 0)
00193 horz -= horz_amount;
00194 if (vert_amount < 0)
00195 vert -= vert_amount;
00196
00197 top_left_.move(horz, vert);
00198 bottom_right_.move(horz, vert);
00199 }
00200
00202 void horz_count(unsigned count)
00203 {
00204 _ASSERTE(count > 0);
00205 bottom_right_.col( top_left_.col() + (count - 1) );
00206 }
00207
00209 unsigned horz_count() const
00210 {
00211 return (bottom_right_.col() - top_left_.col()) + 1;
00212 }
00213
00215 void vert_count(unsigned count)
00216 {
00217 _ASSERTE(count > 0);
00218 bottom_right_.row( top_left_.row() + (count - 1) );
00219 }
00220
00222 unsigned vert_count() const
00223 {
00224 return (bottom_right_.row() - top_left_.row()) + 1;
00225 }
00226 };
00227
00228
00229
00230
00231 namespace detail {
00232
00233
00234 template <class CellData>
00235 class cell_proxy_base
00236 {
00237 protected:
00238 typedef CellData cell_data;
00239 typedef table<CellData> Table;
00240 typedef typename Table::factor factor;
00241
00242 COORDS coords_;
00243
00244 cell_proxy_base(COORDS coords) : coords_(coords)
00245 {}
00246
00247 inline factor log_left(const Table& table) const
00248 {
00249 factor x = 0;
00250 unsigned begin_col = range(table).top_left().col();
00251 for (unsigned c = 0; c < begin_col; ++c)
00252 x += table.col_width(c);
00253 return x;
00254 }
00255
00256 inline factor log_top(const Table& table) const
00257 {
00258 factor y = 0;
00259 unsigned begin_row = range(table).top_left().row();
00260 for (unsigned r = 0; r < begin_row; ++r)
00261 y += table.row_height(r);
00262 return y;
00263 }
00264
00265 inline factor log_width(const Table& table) const
00266 {
00267 factor width = 0;
00268 unsigned begin_col = range(table).top_left().col();
00269 unsigned end_col = range(table).bottom_right().col();
00270 for (unsigned c = begin_col; c <= end_col; ++c)
00271 width += table.col_width(c);
00272 return width;
00273 }
00274
00275 inline factor log_height(const Table& table) const
00276 {
00277 factor height = 0;
00278 unsigned begin_row = range(table).top_left().row();
00279 unsigned end_row = range(table).bottom_right().row();
00280 for (unsigned r = begin_row; r <= end_row; ++r)
00281 height += table.row_height(r);
00282 return height;
00283 }
00284
00285 const cell_range range(const Table& table) const
00286 {
00287 typename Table::MergeColl::iterator it_range = table.find_cell_range(coords_);
00288 if (it_range != table.pMerges_->end())
00289 return *it_range;
00290 else
00291 return cell_range(coords_, coords_);
00292 }
00293
00294 inline const cell_data get_cell_data(const Table& table) const
00295 {
00296 return (*table.pMatrix_) [ table.cell_idx(coords_) ];
00297 }
00298 };
00299 }
00300
00301
00302
00312
00313
00314
00315 template <class Table> class cell_proxy;
00316
00317
00318 template <class CellData>
00319 class cell_proxy<table<CellData> > : private detail::cell_proxy_base<CellData>
00320 {
00321 typedef detail::cell_proxy_base<CellData> Base;
00322
00323 Table& table_;
00324
00325
00326
00327 friend class cell_proxy<const Table>;
00328
00329
00330 friend class detail::forward_proxy<Table>;
00331 cell_proxy(Table& table, COORDS coords) : Base(coords), table_(table)
00332 {}
00333
00334 public:
00335 typedef typename Base::cell_data cell_data;
00336
00338 cell_proxy(const cell_proxy& cell) : Base(cell.coords_), table_(cell.table_)
00339 {}
00340
00342 const cell_proxy& operator= (const cell_data& data)
00343 {
00344 (*table_.pMatrix_) [ table_.cell_idx(coords_) ] = data;
00345 return *this;
00346 }
00347
00349 factor log_left() const { return Base::log_left(table_); }
00350
00352 factor log_top() const { return Base::log_top(table_); }
00353
00355 factor log_width() const { return Base::log_width(table_); }
00356
00358 factor log_height() const { return Base::log_height(table_); }
00359
00361 const cell_range range() const { return Base::range(table_); }
00362
00363
00364 operator const cell_data() const { return Base::get_cell_data(table_); }
00365 };
00366
00367
00368 template <class CellData>
00369 class cell_proxy<const table<CellData> > : private detail::cell_proxy_base<CellData>
00370 {
00371 typedef detail::cell_proxy_base<CellData> Base;
00372
00373 const Table& table_;
00374
00375
00376 friend class detail::forward_proxy<const Table>;
00377 cell_proxy(const Table& t, COORDS coords) : Base(coords), table_(t)
00378 {}
00379
00380 public:
00381 typedef typename Base::cell_data cell_data;
00382
00384 cell_proxy(const cell_proxy& cell) : Base(cell.coords_), table_(cell.table_)
00385 {}
00386
00388 cell_proxy(const cell_proxy<Table>& cell) : Base(cell.coords_), table_(cell.table_)
00389 {}
00390
00392 factor log_left() const { return Base::log_left(table_); }
00393
00395 factor log_top() const { return Base::log_top(table_); }
00396
00398 factor log_width() const { return Base::log_width(table_); }
00399
00401 factor log_height() const { return Base::log_height(table_); }
00402
00404 const cell_range range() const { return Base::range(table_); }
00405
00406
00407 operator const cell_data() const { return Base::get_cell_data(table_); }
00408 };
00409
00410
00411
00412 namespace detail {
00413
00414
00415 template <class Table>
00416 class forward_proxy
00417 {
00418 Table& matrix_;
00419 unsigned col_;
00420
00421
00422 typedef typename Table::cell_data cell_data;
00423 friend class table<cell_data>;
00424 forward_proxy(Table& table, unsigned col) : matrix_(table), col_(col)
00425 {}
00426
00427 public:
00428
00429 inline cell_proxy<Table> operator[] (unsigned row)
00430 {
00431 return cell_proxy<Table> (matrix_, COORDS(col_, row));
00432 }
00433
00434 inline const cell_proxy<Table> operator[] (unsigned row) const
00435 {
00436 return cell_proxy<Table> (matrix_, COORDS(col_, row));
00437 }
00438 };
00439 }
00440
00441
00442
00455 template <class CellData>
00456 class table
00457 {
00458 public:
00459
00460 typedef double factor;
00461
00462 typedef CellData cell_data;
00463 typedef table<CellData> self;
00464
00465 typedef cell_proxy<self> cell_type;
00466 typedef const cell_proxy<const self> const_cell_type;
00467
00468
00469 friend class detail::cell_proxy_base<CellData>;
00470 friend class cell_type;
00471
00472
00477 table(const cell_data& def_cell_data) : pMatrix_(new Matrix()), pRowHeights_(new RowHeightColl()), pColWidths_(new ColWidthColl()), pMerges_(new MergeColl()), def_cell_data_(def_cell_data)
00478 {}
00479
00486 table(const cell_data& def_cell_data, unsigned cols, unsigned rows)
00487 : pMatrix_( new Matrix(cols * rows, def_cell_data) ),
00488 pColWidths_(new ColWidthColl(cols, 1)),
00489 pRowHeights_(new RowHeightColl(rows, 1)),
00490 pMerges_(new MergeColl()), def_cell_data_(def_cell_data)
00491 {}
00492
00493
00494 table(const table& t)
00495 : pMatrix_( new Matrix(*t.pMatrix_.get()) ),
00496 pColWidths_( new ColWidthColl(*t.pColWidths_.get()) ),
00497 pRowHeights_( new RowHeightColl(*t.pRowHeights_.get()) ),
00498 pMerges_( new MergeColl(*t.pMerges_.get()) ),
00499 def_cell_data_(t.def_cell_data_)
00500 {}
00501
00502 virtual ~table()
00503 {}
00504
00505 const table& operator= (const table& t)
00506 {
00507 if (this != &t) {
00508 table temp(t);
00509 swap(temp);
00510 }
00511 return *this;
00512 }
00513
00516 const cell_data default_cell_data() const
00517 {
00518 return def_cell_data_;
00519 }
00520
00523 void dimensions(unsigned cols, unsigned rows)
00524 {
00525 if (rows == 0 || cols == 0) {
00526 pMatrix_->clear();
00527 pRowHeights_->clear();
00528 pColWidths_->clear();
00529 pMerges_->clear();
00530 }
00531
00532 else if (rows != row_count() || cols != col_count()) {
00533 self temp(def_cell_data_, cols, rows);
00534
00535
00536 for (unsigned row = 0; row < rows && row < row_count(); ++row) {
00537 temp.row_height(row, row_height(row));
00538 for (unsigned col = 0; col < cols && col < col_count(); ++col)
00539 temp[col][row] = (*this) [col][row];
00540 }
00541
00542 for (unsigned col = 0; col < cols && col < col_count(); ++col)
00543 temp.col_width(col, col_width(col));
00544
00545
00546 temp.pMerges_->reserve(pMerges_->size());
00547 for (MergeColl::iterator it = pMerges_->begin(); it != pMerges_->end(); ++it)
00548 {
00549
00550 cell_range range = *it;
00551 unsigned left = range.top_left().col();
00552 unsigned top = range.top_left().row();
00553
00554 if (cols <= left || rows <= top)
00555 continue;
00556
00557 range.horz_count( min(cols - left, range.horz_count()) );
00558 range.vert_count( min(rows - top, range.vert_count()) );
00559
00560 temp.pMerges_->push_back( range );
00561 }
00562
00563 swap(temp);
00564 }
00565 }
00566
00569 inline unsigned row_count() const
00570 {
00571 return static_cast<unsigned> (pRowHeights_->size());
00572 }
00573
00576 inline unsigned col_count() const
00577 {
00578 return static_cast<unsigned> (pColWidths_->size());
00579 }
00580
00583 inline detail::forward_proxy<self> operator[] (unsigned col)
00584 {
00585 return detail::forward_proxy<self> (*this, col);
00586 }
00587
00590 inline const detail::forward_proxy<const self> operator[] (unsigned col) const
00591 {
00592 return detail::forward_proxy<const self> (*this, col);
00593 }
00594
00599 void row_height(unsigned row, factor height_factor)
00600 {
00601 _ASSERTE(row < pRowHeights_->size());
00602 (*pRowHeights_) [row] = height_factor;
00603 }
00604
00609 factor row_height(unsigned row) const
00610 {
00611 _ASSERTE(row < pRowHeights_->size());
00612 return (*pRowHeights_) [row];
00613 }
00614
00619 void col_width(unsigned col, factor width_factor)
00620 {
00621 _ASSERTE(col < pColWidths_->size());
00622 (*pColWidths_) [col] = width_factor;
00623 }
00624
00629 factor col_width(unsigned col) const
00630 {
00631 _ASSERTE(col < pColWidths_->size());
00632 return (*pColWidths_) [col];
00633 }
00634
00639 void insert_row(unsigned row)
00640 {
00641 row = min(row, row_count());
00642
00643
00644 self temp(def_cell_data_, col_count(), row_count() + 1);
00645 for (unsigned c = 0; c < col_count(); ++c) {
00646 for (unsigned r = 0; r < row_count() + 1; ++r) {
00647 if (r < row)
00648 temp[c][r] = (*this) [c][r];
00649 else if (r > row)
00650 temp[c][r] = (*this) [c][r - 1];
00651 }
00652 }
00653
00654
00655 temp.pMerges_->reserve(pMerges_->size());
00656 for (MergeColl::iterator it = pMerges_->begin(); it != pMerges_->end(); ++it) {
00657
00658 cell_range range = *it;
00659 unsigned top = range.top_left().row();
00660 unsigned bottom = range.bottom_right().row();
00661 if (row <= top)
00662 range.move(0, 1);
00663 else if (top < row && row <= bottom)
00664 range.vert_count(range.vert_count() + 1);
00665
00666 temp.pMerges_->push_back( range );
00667 }
00668
00669
00670 swap(temp);
00671 }
00672
00677 void insert_col(unsigned col)
00678 {
00679 col = min(col, col_count());
00680
00681
00682 self temp(def_cell_data_, col_count() + 1, row_count());
00683 for (unsigned r = 0; r < row_count(); ++r) {
00684 for (unsigned c = 0; c < col_count() + 1; ++c) {
00685 if (c < col)
00686 temp[c][r] = (*this) [c][r];
00687 else if (c > col)
00688 temp[c][r] = (*this) [c - 1][r];
00689 }
00690 }
00691
00692
00693 temp.pMerges_->reserve(pMerges_->size());
00694 for (MergeColl::iterator it = pMerges_->begin(); it != pMerges_->end(); ++it) {
00695
00696 cell_range range = *it;
00697 unsigned left = range.top_left().col();
00698 unsigned right = range.bottom_right().col();
00699 if (col <= left)
00700 range.move(1, 0);
00701 else if (left < col && col <= right)
00702 range.horz_count(range.horz_count() + 1);
00703
00704 temp.pMerges_->push_back( range );
00705 }
00706
00707
00708 swap(temp);
00709 }
00710
00713 void remove_col(unsigned col)
00714 {
00715 _ASSERTE(col < col_count());
00716
00717
00718 for (unsigned row = 0; row < row_count(); ++row) {
00719 MergeColl::iterator it_range = find_cell_range(COORDS(col, row));
00720 if (it_range != pMerges_->end()) {
00721 cell_range& range = *it_range;
00722
00723 if (range.horz_count() == 1)
00724 pMerges_->erase(it_range);
00725 else {
00726 unsigned left = range.top_left().col();
00727 unsigned right = range.bottom_right().col();
00728
00729 if (left <= col && col <= right) {
00730 range.horz_count(range.horz_count() - 1);
00731 row += range.vert_count() - 1;
00732 }
00733 if (left == col)
00734 range.move(-1, 0);
00735 }
00736 }
00737 }
00738
00739
00740
00741 for (unsigned row = row_count(); row > 0; --row)
00742 pMatrix_->erase( pMatrix_->begin() + cell_idx(COORDS(col, row - 1)) );
00743
00744
00745 pColWidths_->erase(pColWidths_->begin() + col);
00746 }
00747
00750 void remove_row(unsigned row)
00751 {
00752 _ASSERTE(row < row_count());
00753
00754
00755 for (unsigned col = 0; col < col_count(); ++col) {
00756 MergeColl::iterator it_range = find_cell_range(COORDS(col, row));
00757 if (it_range != pMerges_->end()) {
00758 cell_range& range = *it_range;
00759
00760 if (range.vert_count() == 1)
00761 pMerges_->erase(it_range);
00762 else {
00763 unsigned top = range.top_left().row();
00764 unsigned bottom = range.bottom_right().row();
00765
00766 if (top <= row && row <= bottom) {
00767 range.vert_count(range.vert_count() - 1);
00768 col += range.horz_count() - 1;
00769 }
00770 if (top == row)
00771 range.move(0, -1);
00772 }
00773 }
00774 }
00775
00776
00777
00778 for (unsigned col = col_count(); col > 0; --col)
00779 pMatrix_->erase( pMatrix_->begin() + cell_idx(COORDS(col - 1, row)) );
00780
00781
00782 pRowHeights_->erase(pRowHeights_->begin() + row);
00783 }
00784
00787 void merge_cells(const cell_range& range)
00788 {
00789 cell_range r = apply_merge_recursive(range);
00790 pMerges_->push_back(r);
00791 }
00792
00795 void unmerge_cells(const cell_range& range)
00796 {
00797 MergeColl::iterator it_range = std::find(pMerges_->begin(), pMerges_->end(), range);
00798 if (it_range != pMerges_->end())
00799 pMerges_->erase(it_range);
00800 }
00801
00804 void unmerge_cells(COORDS coords)
00805 {
00806 MergeColl::iterator it_range = find_cell_range(coords);
00807 if (it_range != pMerges_->end())
00808 pMerges_->erase(it_range);
00809 }
00810
00813 void swap(self& t)
00814 {
00815 std::swap(pMatrix_, t.pMatrix_);
00816 std::swap(pRowHeights_, t.pRowHeights_);
00817 std::swap(pColWidths_, t.pColWidths_);
00818 std::swap(def_cell_data_, t.def_cell_data_);
00819 std::swap(pMerges_, t.pMerges_);
00820 }
00821
00822 private:
00823
00824 cell_range apply_merge_recursive(const cell_range& range)
00825 {
00826 for (unsigned i = 0; i < pMerges_->size(); ++i) {
00827 cell_range& r2 = (*pMerges_) [i];
00828 if (range == r2)
00829 continue;
00830
00831
00832 if (range.is_intersecting(r2)) {
00833 cell_range temp = range + r2;
00834 if (temp != range) {
00835 pMerges_->erase(pMerges_->begin() + i);
00836 --i;
00837 return apply_merge_recursive(temp);
00838 }
00839 }
00840 }
00841
00842 return range;
00843 }
00844
00845
00846 inline unsigned cell_idx(COORDS coords) const
00847 {
00848 unsigned ret = coords.col() + coords.row() * col_count();
00849 _ASSERTE(ret < (row_count() * col_count()));
00850 return ret;
00851 }
00852
00853
00854 private:
00855
00856 typedef std::vector<cell_data> Matrix;
00857 typedef std::auto_ptr<Matrix> MatrixPtr;
00858 MatrixPtr pMatrix_;
00859 cell_data def_cell_data_;
00860
00861 typedef std::vector<factor> RowHeightColl;
00862 typedef RowHeightColl ColWidthColl;
00863 typedef std::auto_ptr<RowHeightColl> RowHeightCollPtr;
00864 typedef std::auto_ptr<ColWidthColl> ColWidthCollPtr;
00865 RowHeightCollPtr pRowHeights_;
00866 ColWidthCollPtr pColWidths_;
00867
00868 typedef std::vector<cell_range> MergeColl;
00869 typedef std::auto_ptr<MergeColl> MergeCollPtr;
00870 MergeCollPtr pMerges_;
00871
00872
00873 private:
00874
00875 MergeColl::iterator find_cell_range(COORDS coords) const
00876 {
00877 cell_range this_cell(coords, coords);
00878 for (MergeColl::iterator it = pMerges_->begin(); it != pMerges_->end(); ++it) {
00879 if (this_cell.is_intersecting(*it))
00880 return it;
00881 }
00882
00883 return pMerges_->end();
00884 }
00885 };
00886
00887
00888 }
00889 } }