00001 /* 00002 libwt - Vassilis Virvilis Toolkit - a widget library 00003 Copyright (C) 2006 Vassilis Virvilis <vasvir2@fastmail.fm> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Lesser General Public 00007 License as published by the Free Software Foundation; either 00008 version 2.1 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public 00016 License along with this library; if not, write to the 00017 Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, SA. 00019 */ 00020 00021 #ifndef WT_MATRIX_H 00022 #define WT_MATRIX_H 00023 00024 #include <vector> 00025 00026 #include <sigc++/signal.h> 00027 00028 namespace Wt { 00029 template<typename T> 00030 class Matrix : public std::vector< std::vector<T> > { 00031 public: 00032 typedef std::vector<T> Edge; 00033 typedef std::vector<Edge> MatrixBase; 00034 00035 typedef T value_type; 00036 00037 class iterator { 00038 public: 00039 iterator(Matrix* matrix_p = 0, int row = 0, int column = 0) : 00040 m_(matrix_p), 00041 row_(row), 00042 column_(column) { 00043 if (matrix_p) { 00044 if (row_ >= m_->numRows()) 00045 row_ = -1; 00046 if (column_ >= m_->numCols()) 00047 column_ = -1; 00048 } 00049 } 00050 bool operator==(const iterator& other) const { 00051 return (other.column_ == column_) && (other.row_ == row_); 00052 } 00053 bool operator!=(const iterator& other) const { 00054 return !(*this == other); 00055 } 00056 iterator& operator++() { 00057 const Matrix& matrix = *m_; 00058 if (column_ < matrix.numCols() - 1) { 00059 ++column_; 00060 } else { 00061 // end of column 00062 if (row_ < matrix.numRows() - 1) { 00063 // advance row 00064 ++row_; 00065 column_ = 0; 00066 } else { 00067 // end() 00068 row_ = -1; 00069 column_ = -1; 00070 } 00071 } 00072 return *this; 00073 } 00074 00075 T& operator*() const { 00076 Matrix& matrix = *m_; 00077 T& t = matrix[row_][column_]; 00078 return t; 00079 } 00080 T *operator->() const { 00081 Matrix& matrix = *m_; 00082 T* t = &matrix[row_][column_]; 00083 return t; 00084 } 00085 00086 int row() const { 00087 return row_; 00088 } 00089 00090 int column() const { 00091 return column_; 00092 } 00093 00094 private: 00095 Matrix *m_; 00096 int row_; 00097 int column_; 00098 }; 00099 00100 class const_iterator : public iterator { 00101 public: 00102 const_iterator(const Matrix* matrix_p = 0, 00103 int row = 0, int column = 0) : 00104 iterator(const_cast<Matrix*>(matrix_p), row, column) {} 00105 00106 const_iterator(const iterator& other) : 00107 iterator(other) {} 00108 }; 00109 00110 Matrix() : 00111 rows_(0), 00112 columns_(0) {} 00113 00114 int numRows() const { 00115 return rows_; 00116 } 00117 00118 int numCols() const { 00119 return columns_; 00120 } 00121 00122 bool empty() const { 00123 return !rows_ && !columns_; 00124 } 00125 00126 iterator begin() { 00127 return iterator(this); 00128 } 00129 00130 iterator end() { 00131 return iterator(this, -1, -1); 00132 } 00133 00134 const_iterator begin() const { 00135 return const_iterator(this); 00136 } 00137 00138 const_iterator end() const { 00139 return const_iterator(this, -1, -1); 00140 } 00141 00142 T& operator()(int r, int c) { 00143 const int old_rows = rows_; 00144 const int old_cols = columns_; 00145 int i; 00146 00147 if (r >= old_rows) { 00148 MatrixBase& m = *this; 00149 m.resize(r + 1); 00150 rows_ = r + 1; 00151 } 00152 00153 const int new_columns = std::max(c + 1, columns_); 00154 for (i = 0; i < rows_; i++) { 00155 (*this)[i].resize(new_columns); 00156 } 00157 00158 if (c >= columns_) { 00159 columns_ = c + 1; 00160 } 00161 00162 if (rows_ != old_rows || columns_ != old_cols) { 00163 gridSizeChanged.emit(old_rows, old_cols, rows_, columns_); 00164 } 00165 Matrix& self = *this; 00166 return self[r][c]; 00167 } 00168 00169 void push_back(const T& t) { 00170 Matrix& self = *this; 00171 int r, c; 00172 if (!rows_) { 00173 // start the matrix 00174 r = 0; 00175 c = 0; 00176 } else if (rows_ == 1) { 00177 // in the first line we keep adding columns 00178 r = 0; 00179 c = columns_; 00180 } else { 00181 int j; 00182 // we try to find the first empty item after the last non empty 00183 // if we can't find it before the end of the row we open a new row 00184 for (j = 0; j < columns_ && 00185 self[rows_ - 1][columns_ - 1 - j] == T(); j++) {} 00186 if (j == 0) { 00187 // this row is full, open new row 00188 r = rows_; 00189 c = 0; 00190 } else if (j == columns_) { 00191 // this row is empty, go at at start; 00192 r = rows_ - 1; 00193 c = 0; 00194 } else { 00195 r = rows_ - 1; 00196 c = columns_ - j; 00197 } 00198 } 00199 00200 self(r, c) = t; 00201 } 00202 00203 iterator erase(iterator it) { 00204 *it = T(); 00205 adjust(); 00206 return ++it; 00207 } 00208 00209 iterator find(iterator start, iterator finish, const T& t) const { 00210 iterator it = start; 00211 for (; it != finish; ++it) { 00212 if (t == *it) 00213 break; 00214 } 00215 return (it != finish) ? it : end(); 00216 } 00217 00218 void remove 00219 (const T& t) { 00220 iterator it = begin(); 00221 iterator e = end(); 00222 while (it != e) { 00223 if (t == *it) 00224 it = erase(it); 00225 else 00226 ++it; 00227 } 00228 } 00229 00230 sigc::signal4<void, int, int, int, int> gridSizeChanged; 00231 00232 protected: 00233 bool isRowEmpty(int row) { 00234 bool empty = true; 00235 00236 for (int c = 0; c < columns_; c++) { 00237 Matrix& self = *this; 00238 T empty_item; 00239 if (empty_item != self[row][c]) { 00240 empty = false; 00241 break; 00242 } 00243 } 00244 return empty; 00245 } 00246 00247 bool isColumnEmpty(int column) { 00248 bool empty = true; 00249 00250 for (int r = 0; r < rows_; r++) { 00251 Matrix& self = *this; 00252 T empty_item; 00253 if (empty_item != self[r][column]) { 00254 empty = false; 00255 break; 00256 } 00257 } 00258 return empty; 00259 } 00260 00261 void adjust() { 00262 const int old_rows = rows_; 00263 const int old_cols = columns_; 00264 int row_max, col_max; 00265 00266 //first find non empty row starting from end 00267 for (row_max = rows_ - 1; row_max >= 0 && 00268 isRowEmpty(row_max); row_max--) {} 00269 00270 //now the max column starting from end 00271 for (col_max = columns_ - 1; col_max >= 0 && 00272 isColumnEmpty(col_max); col_max--) {} 00273 00274 if (row_max < rows_ - 1 || col_max < columns_ - 1) { 00275 MatrixBase& m = *this; 00276 m.resize(row_max + 1); 00277 rows_ = row_max + 1; 00278 00279 if (col_max < columns_ - 1) { 00280 for (int r = 0; r < rows_; r++) { 00281 (*this)[r].resize(col_max + 1); 00282 } 00283 } 00284 columns_ = col_max + 1; 00285 } 00286 if (rows_ != old_rows || columns_ != old_cols) { 00287 gridSizeChanged.emit(old_rows, old_cols, rows_, columns_); 00288 } 00289 } 00290 00291 private: 00292 int rows_; 00293 int columns_; 00294 }; 00295 00296 } // namespace 00297 00298 #endif // WT_MATRIX_H
This document is licensed under the terms of the GNU Free Documentation License and may be freely distributed under the conditions given by this license.