Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

# table.hpp

    00001 // table.hpp
    00002
    00003 // Copyright (C) 2004 Steven Weiß (steven11@gmx.de)
    00004 //
    00005 // Permission to copy, use, sell and distribute this software is granted
    00006 // provided this copyright notice appears in all copies.
    00007 // Permission to modify the code and to distribute modified code is granted
    00008 // provided this copyright notice appears in all copies, and a notice
    00009 // that the code was modified is included with the copyright notice.
    00010 //
    00011 // This software is provided "as is" without express or implied warranty,
    00012 // and with no claim as to its suitability for any purpose.
    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;                      // forward declarations
    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());      // coordinates must be correct
    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           // ensure the coordinates won't be less than 0 (-> they are unsigned!)
    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);               // 0 is not possible
    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);               // 0 is not possible
    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      // Base class of cell_proxy. this class is the implementation shared by both cell_proxy-specializations
    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_;                    // coordinates of the cell
    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_);         // cell isn't in a range so create one exclusively for this cell ;-)
    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 }    // namespace detail
    00300
    00301 // ========================================================================================================== //
    00302
    00312 // there are two specializations:
    00313 //        one for a non-const table: the user is allowed to change the cell's data
    00314 //        one for a const table: the user has only read-access to the cell
    00315 template <class Table> class cell_proxy;
    00316
    00317 // specialization for a non-const table
    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      // a cell_proxy based on a const Table should be constructible by this non-const cell_proxy.
    00326      // it needs access to table_ so it's our friend ;-)
    00327      friend class cell_proxy<const Table>;
    00328
    00329      // only a forward_proxy is allowed to create an object of this class ;-)
    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      // conversion to CellData
    00364      operator const cell_data() const { return Base::get_cell_data(table_); }
    00365 };
    00366
    00367 // specialization for a const table
    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      // only a forward_proxy is allowed to create an object of this class ;-)
    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      // conversion to CellData
    00407      operator const cell_data() const { return Base::get_cell_data(table_); }
    00408 };
    00409
    00410 // ========================================================================================================= //
    00411
    00412 namespace detail {
    00413      // proxy class which returns a cell_proxy-object for the cell [col_idx][row_idx]. this indirection is necessary because
    00414      // operator[] has only one dimension -> operator[] of table returns a forward_proxy so this creates two dimensions ;-)
    00415      template <class Table>
    00416      class forward_proxy
    00417      {
    00418           Table& matrix_;
    00419           unsigned col_;
    00420
    00421           // only a table is allowed to construct an object of this class ;-)
    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           // forward to cell_proxy
    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 }    // namespace detail
    00440
    00441 // ========================================================================================================= //
    00442
    00455 template <class CellData>
    00456 class table
    00457 {
    00458 public:
    00459      // typedef's
    00460      typedef double factor;             // factor which indicates the height, width and position of cells. they are
    00461                                              // only logical -> you have to define a default value which will be multiplied with the factor
    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      // cell_proxy_base is a friend (needs access to our matrix). cell_type is also a friend (needs to change a cell)
    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) ),                 // init with default 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      // copy c'tor
    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           // copy cells (exception safe)
    00532           else if (rows != row_count() || cols != col_count()) {
    00533                self temp(def_cell_data_, cols, rows);
    00534
    00535                // set row heights and copy cell data
    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                // set column widths
    00542                for (unsigned col = 0; col < cols && col < col_count(); ++col)
    00543                     temp.col_width(col, col_width(col));
    00544
    00545                // copy ranges
    00546                temp.pMerges_->reserve(pMerges_->size());
    00547                for (MergeColl::iterator it = pMerges_->begin(); it != pMerges_->end(); ++it)
    00548                {
    00549                     // if table shrinks some ranges can be deleted
    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()) );        // shrink if necessary
    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());                  // must be in bounds
    00602           (*pRowHeights_) [row] = height_factor;
    00603      }
    00604
    00609      factor row_height(unsigned row) const
    00610      {
    00611           _ASSERTE(row < pRowHeights_->size());                  // must be in bounds
    00612           return (*pRowHeights_) [row];
    00613      }
    00614
    00619      void col_width(unsigned col, factor width_factor)
    00620      {
    00621           _ASSERTE(col < pColWidths_->size());                   // must be in bounds
    00622           (*pColWidths_) [col] = width_factor;
    00623      }
    00624
    00629      factor col_width(unsigned col) const
    00630      {
    00631           _ASSERTE(col < pColWidths_->size());                   // must be in bounds
    00632           return (*pColWidths_) [col];
    00633      }
    00634
    00639      void insert_row(unsigned row)
    00640      {
    00641           row = min(row, row_count());
    00642
    00643           // copy cells (exception safe)
    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           // copy merges
    00655           temp.pMerges_->reserve(pMerges_->size());
    00656           for (MergeColl::iterator it = pMerges_->begin(); it != pMerges_->end(); ++it) {
    00657                // if a row is inserted the ranges are likely to be changed
    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           // ensure exception safety ;-)
    00670           swap(temp);
    00671      }
    00672
    00677      void insert_col(unsigned col)
    00678      {
    00679           col = min(col, col_count());
    00680
    00681           // copy cells
    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           // copy merges
    00693           temp.pMerges_->reserve(pMerges_->size());
    00694           for (MergeColl::iterator it = pMerges_->begin(); it != pMerges_->end(); ++it) {
    00695                // if a column is inserted the ranges are likely to be changed
    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           // ensure exception safety ;-)
    00708           swap(temp);
    00709      }
    00710
    00713      void remove_col(unsigned col)
    00714      {
    00715           _ASSERTE(col < col_count());
    00716
    00717           // take care of the merged cells
    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)                 // if range is only in this column remove it
    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;          // go to next row which isn't in this range
    00732                          }
    00733                          if (left == col)                             // if first column of range is removed move the range
    00734                               range.move(-1, 0);
    00735                     }
    00736                }
    00737           }
    00738
    00739           // erase cells - but from last to first so that the index is always correct.
    00740           // note: because row is unsigned we have to be aware of the underflow when decreasing 0!!!
    00741           for (unsigned row = row_count(); row > 0; --row)
    00742                pMatrix_->erase( pMatrix_->begin() + cell_idx(COORDS(col, row - 1)) );
    00743
    00744           // erase column
    00745           pColWidths_->erase(pColWidths_->begin() + col);
    00746      }
    00747
    00750      void remove_row(unsigned row)
    00751      {
    00752           _ASSERTE(row < row_count());
    00753
    00754           // take care of the merged cells
    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)                 // if range is only in this row remove it
    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;          // go to next column which isn't in this range
    00769                          }
    00770                          if (top == row)                                   // if first row of range is removed move the range
    00771                               range.move(0, -1);
    00772                     }
    00773                }
    00774           }
    00775
    00776           // erase cells - but from last to first so that the index is always correct.
    00777           // note: because col is unsigned we have to be aware of the underflow when decreasing 0!!!
    00778           for (unsigned col = col_count(); col > 0; --col)
    00779                pMatrix_->erase( pMatrix_->begin() + cell_idx(COORDS(col - 1, row)) );
    00780
    00781           // erase row
    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      // applies a merge-operation recursively
    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                // if merges intersect add them and call this function recursive
    00832                if (range.is_intersecting(r2)) {
    00833                     cell_range temp = range + r2;
    00834                     if (temp != range) {
    00835                          pMerges_->erase(pMerges_->begin() + i);      // erase from collection
    00836                          --i;
    00837                          return apply_merge_recursive(temp);
    00838                     }
    00839                }
    00840           }
    00841
    00842           return range;
    00843      }
    00844
    00845      // returns the index of cell with the passed coordinates in the vector matrix_
    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())); // index must be in bounds
    00850           return ret;
    00851      }
    00852
    00853
    00854 private:
    00855      // members
    00856      typedef std::vector<cell_data> Matrix;
    00857      typedef std::auto_ptr<Matrix> MatrixPtr;
    00858      MatrixPtr pMatrix_;                                    // the Matrix: saves the data
    00859      cell_data def_cell_data_;                              // default 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_;                         // saves the height and width of the rows/columns
    00866      ColWidthCollPtr  pColWidths_;
    00867
    00868      typedef std::vector<cell_range>   MergeColl;
    00869      typedef std::auto_ptr<MergeColl>  MergeCollPtr;
    00870      MergeCollPtr pMerges_;                                 // collection of the merged cells
    00871
    00872
    00873 private:
    00874      // returns the cell range of the cell with the passed coordinates
    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 }    // namespace bg_wnd
    00889 } }  // namespace win32::gui

| by Steven Weiss. You can contact me at steven11@gmx.de.