00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "gui/palette.h"
00023 #include "gui/table.h"
00024 #include "gui/sdlinput.h"
00025
00026 #include "configuration.h"
00027
00028 #include "utils/dtor.h"
00029
00030 #include <guichan/actionlistener.hpp>
00031 #include <guichan/graphics.hpp>
00032 #include <guichan/key.hpp>
00033
00034 float GuiTable::mAlpha = 1.0;
00035
00036 class GuiTableActionListener : public gcn::ActionListener
00037 {
00038 public:
00039 GuiTableActionListener(GuiTable *_table, gcn::Widget *_widget, int _row, int _column);
00040
00041 virtual ~GuiTableActionListener();
00042
00043 virtual void action(const gcn::ActionEvent& actionEvent);
00044
00045 protected:
00046 GuiTable *mTable;
00047 int mRow;
00048 int mColumn;
00049 gcn::Widget *mWidget;
00050 };
00051
00052
00053 GuiTableActionListener::GuiTableActionListener(GuiTable *table, gcn::Widget *widget, int row, int column) :
00054 mTable(table),
00055 mRow(row),
00056 mColumn(column),
00057 mWidget(widget)
00058 {
00059 if (widget)
00060 {
00061 widget->addActionListener(this);
00062 widget->_setParent(table);
00063 }
00064 }
00065
00066 GuiTableActionListener::~GuiTableActionListener()
00067 {
00068 if (mWidget)
00069 {
00070 mWidget->removeActionListener(this);
00071 mWidget->_setParent(NULL);
00072 }
00073 }
00074
00075 void GuiTableActionListener::action(const gcn::ActionEvent& actionEvent)
00076 {
00077 mTable->setSelected(mRow, mColumn);
00078 mTable->distributeActionEvent();
00079 }
00080
00081
00082 GuiTable::GuiTable(TableModel *initial_model, gcn::Color background,
00083 bool opacity) :
00084 mLinewiseMode(false),
00085 mWrappingEnabled(false),
00086 mOpaque(opacity),
00087 mBackgroundColor(background),
00088 mModel(NULL),
00089 mSelectedRow(0),
00090 mSelectedColumn(0),
00091 mTopWidget(NULL)
00092 {
00093 setModel(initial_model);
00094 setFocusable(true);
00095
00096 addMouseListener(this);
00097 addKeyListener(this);
00098 }
00099
00100 GuiTable::~GuiTable()
00101 {
00102 uninstallActionListeners();
00103 delete mModel;
00104 }
00105
00106 TableModel *GuiTable::getModel() const
00107 {
00108 return mModel;
00109 }
00110
00111 void GuiTable::setModel(TableModel *new_model)
00112 {
00113 if (mModel)
00114 {
00115 uninstallActionListeners();
00116 mModel->removeListener(this);
00117 }
00118
00119 mModel = new_model;
00120 installActionListeners();
00121
00122 if (new_model)
00123 {
00124 new_model->installListener(this);
00125 recomputeDimensions();
00126 }
00127 }
00128
00129 void GuiTable::recomputeDimensions()
00130 {
00131 int rows_nr = mModel->getRows();
00132 int columns_nr = mModel->getColumns();
00133 int width = 0;
00134 int height = 0;
00135
00136 if (mSelectedRow >= rows_nr)
00137 mSelectedRow = rows_nr - 1;
00138
00139 if (mSelectedColumn >= columns_nr)
00140 mSelectedColumn = columns_nr - 1;
00141
00142 for (int i = 0; i < columns_nr; i++)
00143 width += getColumnWidth(i);
00144
00145 height = getRowHeight() * rows_nr;
00146
00147 setWidth(width);
00148 setHeight(height);
00149 }
00150
00151 void GuiTable::setSelected(int row, int column)
00152 {
00153 mSelectedColumn = column;
00154 mSelectedRow = row;
00155 }
00156
00157 int GuiTable::getSelectedRow()
00158 {
00159 return mSelectedRow;
00160 }
00161
00162 int GuiTable::getSelectedColumn()
00163 {
00164 return mSelectedColumn;
00165 }
00166
00167 void GuiTable::setLinewiseSelection(bool linewise)
00168 {
00169 mLinewiseMode = linewise;
00170 }
00171
00172 int GuiTable::getRowHeight()
00173 {
00174 if (mModel)
00175 return mModel->getRowHeight() + 1;
00176 else
00177 return 0;
00178 }
00179
00180 int GuiTable::getColumnWidth(int i)
00181 {
00182 if (mModel)
00183 return mModel->getColumnWidth(i) + 1;
00184 else
00185 return 0;
00186 }
00187
00188 void GuiTable::setSelectedRow(int selected)
00189 {
00190 if (!mModel)
00191 {
00192 mSelectedRow = -1;
00193 }
00194 else
00195 {
00196 if (selected < 0 && !mWrappingEnabled)
00197 {
00198 mSelectedRow = -1;
00199 }
00200 else if (selected >= mModel->getRows() && mWrappingEnabled)
00201 {
00202 mSelectedRow = 0;
00203 }
00204 else if ((selected >= mModel->getRows() && !mWrappingEnabled) ||
00205 (selected < 0 && mWrappingEnabled))
00206 {
00207 mSelectedRow = mModel->getRows() - 1;
00208 }
00209 else
00210 {
00211 mSelectedRow = selected;
00212 }
00213 }
00214 }
00215
00216 void GuiTable::setSelectedColumn(int selected)
00217 {
00218 if (!mModel)
00219 {
00220 mSelectedColumn = -1;
00221 }
00222 else
00223 {
00224 if ((selected >= mModel->getColumns() && mWrappingEnabled) ||
00225 (selected < 0 && !mWrappingEnabled))
00226 {
00227 mSelectedColumn = 0;
00228 }
00229 else if ((selected >= mModel->getColumns() && !mWrappingEnabled) ||
00230 (selected < 0 && mWrappingEnabled))
00231 {
00232 mSelectedColumn = mModel->getColumns() - 1;
00233 }
00234 else
00235 {
00236 mSelectedColumn = selected;
00237 }
00238 }
00239 }
00240
00241 void GuiTable::uninstallActionListeners(void)
00242 {
00243 delete_all(mActionListeners);
00244 mActionListeners.clear();
00245 }
00246
00247 void GuiTable::installActionListeners()
00248 {
00249 if (!mModel)
00250 return;
00251
00252 int rows = mModel->getRows();
00253 int columns = mModel->getColumns();
00254
00255 for (int row = 0; row < rows; ++row)
00256 for (int column = 0; column < columns; ++column)
00257 {
00258 gcn::Widget *widget = mModel->getElementAt(row, column);
00259 mActionListeners.push_back(new GuiTableActionListener(this, widget,
00260 row, column));
00261 }
00262
00263 _setFocusHandler(_getFocusHandler());
00264 }
00265
00266
00267 void GuiTable::draw(gcn::Graphics* graphics)
00268 {
00269 if (!mModel)
00270 return;
00271
00272 if (config.getValue("guialpha", 0.8) != mAlpha)
00273 mAlpha = config.getValue("guialpha", 0.8);
00274
00275 if (mOpaque)
00276 {
00277 graphics->setColor(guiPalette->getColor(Palette::BACKGROUND,
00278 (int)(mAlpha * 255.0f)));
00279 graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight()));
00280 }
00281
00282
00283 int first_row = -(getY() / getRowHeight());
00284
00285 if (first_row < 0)
00286 first_row = 0;
00287
00288 int rows_nr = 1 + (getHeight() / getRowHeight());
00289
00290 int max_rows_nr = mModel->getRows() - first_row;
00291 if (max_rows_nr < rows_nr)
00292 rows_nr = max_rows_nr;
00293
00294
00295
00296 int first_column = 0;
00297 int last_column = mModel->getColumns() - 1;
00298
00299
00300 int height = getRowHeight();
00301 int y_offset = first_row * height;
00302
00303 for (int r = first_row; r < first_row + rows_nr; ++r)
00304 {
00305 int x_offset = 0;
00306
00307 for (int c = first_column; c <= last_column; ++c)
00308 {
00309 gcn::Widget *widget = mModel->getElementAt(r, c);
00310 int width = getColumnWidth(c);
00311 if (widget)
00312 {
00313 gcn::Rectangle bounds(x_offset, y_offset, width, height);
00314
00315 if (widget == mTopWidget)
00316 {
00317 bounds.height = widget->getHeight();
00318 bounds.width = widget->getWidth();
00319 }
00320
00321 widget->setDimension(bounds);
00322
00323 graphics->setColor(guiPalette->getColor(Palette::HIGHLIGHT,
00324 (int)(mAlpha * 255.0f)));
00325
00326 if (mLinewiseMode && r == mSelectedRow && c == 0)
00327 {
00328 graphics->fillRectangle(gcn::Rectangle(0, y_offset,
00329 getWidth(), height));
00330 }
00331 else if (!mLinewiseMode &&
00332 c == mSelectedColumn && r == mSelectedRow)
00333 {
00334 graphics->fillRectangle(gcn::Rectangle(x_offset, y_offset,
00335 width, height));
00336 }
00337
00338 graphics->pushClipArea(bounds);
00339 widget->draw(graphics);
00340 graphics->popClipArea();
00341 }
00342
00343 x_offset += width;
00344 }
00345
00346 y_offset += height;
00347 }
00348
00349 if (mTopWidget)
00350 {
00351 gcn::Rectangle bounds = mTopWidget->getDimension();
00352 graphics->pushClipArea(bounds);
00353 mTopWidget->draw(graphics);
00354 graphics->popClipArea();
00355 }
00356 }
00357
00358 void GuiTable::moveToTop(gcn::Widget *widget)
00359 {
00360 gcn::Widget::moveToTop(widget);
00361 mTopWidget = widget;
00362 }
00363
00364 void GuiTable::moveToBottom(gcn::Widget *widget)
00365 {
00366 gcn::Widget::moveToBottom(widget);
00367 if (widget == mTopWidget)
00368 mTopWidget = NULL;
00369 }
00370
00371 gcn::Rectangle GuiTable::getChildrenArea()
00372 {
00373 return gcn::Rectangle(0, 0, getWidth(), getHeight());
00374 }
00375
00376
00377 void GuiTable::keyPressed(gcn::KeyEvent& keyEvent)
00378 {
00379 gcn::Key key = keyEvent.getKey();
00380
00381 if (key.getValue() == Key::ENTER || key.getValue() == Key::SPACE)
00382 {
00383 distributeActionEvent();
00384 keyEvent.consume();
00385 }
00386 else if (key.getValue() == Key::UP)
00387 {
00388 setSelectedRow(mSelectedRow - 1);
00389 keyEvent.consume();
00390 }
00391 else if (key.getValue() == Key::DOWN)
00392 {
00393 setSelectedRow(mSelectedRow + 1);
00394 keyEvent.consume();
00395 }
00396 else if (key.getValue() == Key::LEFT)
00397 {
00398 setSelectedColumn(mSelectedColumn - 1);
00399 keyEvent.consume();
00400 }
00401 else if (key.getValue() == Key::RIGHT)
00402 {
00403 setSelectedColumn(mSelectedColumn + 1);
00404 keyEvent.consume();
00405 }
00406 else if (key.getValue() == Key::HOME)
00407 {
00408 setSelectedRow(0);
00409 setSelectedColumn(0);
00410 keyEvent.consume();
00411 }
00412 else if (key.getValue() == Key::END)
00413 {
00414 setSelectedRow(mModel->getRows() - 1);
00415 setSelectedColumn(mModel->getColumns() - 1);
00416 keyEvent.consume();
00417 }
00418 }
00419
00420
00421 void GuiTable::mousePressed(gcn::MouseEvent& mouseEvent)
00422 {
00423 if (mouseEvent.getButton() == gcn::MouseEvent::LEFT)
00424 {
00425 int row = getRowForY(mouseEvent.getY());
00426 int column = getColumnForX(mouseEvent.getX());
00427
00428 if (row > -1 && column > -1 &&
00429 row < mModel->getRows() && column < mModel->getColumns())
00430 {
00431 mSelectedColumn = column;
00432 mSelectedRow = row;
00433 }
00434
00435 distributeActionEvent();
00436 }
00437 }
00438
00439 void GuiTable::mouseWheelMovedUp(gcn::MouseEvent& mouseEvent)
00440 {
00441 if (isFocused())
00442 {
00443 if (getSelectedRow() > 0 || (getSelectedRow() == 0 && mWrappingEnabled))
00444 {
00445 setSelectedRow(getSelectedRow() - 1);
00446 }
00447
00448 mouseEvent.consume();
00449 }
00450 }
00451
00452 void GuiTable::mouseWheelMovedDown(gcn::MouseEvent& mouseEvent)
00453 {
00454 if (isFocused())
00455 {
00456 setSelectedRow(getSelectedRow() + 1);
00457
00458 mouseEvent.consume();
00459 }
00460 }
00461
00462 void GuiTable::mouseDragged(gcn::MouseEvent& mouseEvent)
00463 {
00464 }
00465
00466
00467 void GuiTable::modelUpdated(bool completed)
00468 {
00469 if (completed)
00470 {
00471 recomputeDimensions();
00472 installActionListeners();
00473 }
00474 else
00475 {
00476 mTopWidget = NULL;
00477 uninstallActionListeners();
00478 }
00479 }
00480
00481 gcn::Widget *GuiTable::getWidgetAt(int x, int y)
00482 {
00483 int row = getRowForY(y);
00484 int column = getColumnForX(x);
00485
00486 if (mTopWidget && mTopWidget->getDimension().isPointInRect(x, y))
00487 return mTopWidget;
00488
00489 if (row > -1 && column > -1)
00490 {
00491 gcn::Widget *w = mModel->getElementAt(row, column);
00492 if (w && w->isFocusable())
00493 return w;
00494 else
00495 return NULL;
00496 }
00497 else
00498 return NULL;
00499 }
00500
00501 int GuiTable::getRowForY(int y)
00502 {
00503 int row = y / getRowHeight();
00504
00505 if (row < 0 || row >= mModel->getRows())
00506 return -1;
00507 else
00508 return row;
00509 }
00510
00511 int GuiTable::getColumnForX(int x)
00512 {
00513 int column;
00514 int delta = 0;
00515
00516 for (column = 0; column < mModel->getColumns(); column++)
00517 {
00518 delta += getColumnWidth(column);
00519 if (x <= delta)
00520 break;
00521 }
00522
00523 if (column < 0 || column >= mModel->getColumns())
00524 return -1;
00525 else
00526 return column;
00527 }
00528
00529 void GuiTable::_setFocusHandler(gcn::FocusHandler* focusHandler)
00530 {
00531 gcn::Widget::_setFocusHandler(focusHandler);
00532
00533 if (mModel) {
00534 for (int r = 0; r < mModel->getRows(); ++r) {
00535 for (int c = 0; c < mModel->getColumns(); ++c) {
00536 gcn::Widget *w = mModel->getElementAt(r, c);
00537 if (w)
00538 w->_setFocusHandler(focusHandler);
00539 }
00540 }
00541 }
00542 }