summaryrefslogtreecommitdiff
path: root/src/gui/table.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/table.cpp')
-rw-r--r--src/gui/table.cpp419
1 files changed, 419 insertions, 0 deletions
diff --git a/src/gui/table.cpp b/src/gui/table.cpp
new file mode 100644
index 00000000..07f40f76
--- /dev/null
+++ b/src/gui/table.cpp
@@ -0,0 +1,419 @@
+/*
+ * The Mana World
+ * Copyright 2004 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <guichan/graphics.hpp>
+#include <guichan/actionlistener.hpp>
+#include "table.h"
+#include <cassert>
+
+
+
+class GuiTableActionListener : public gcn::ActionListener
+{
+public:
+ GuiTableActionListener(GuiTable *_table, gcn::Widget *_widget, int _row, int _column);
+
+ virtual ~GuiTableActionListener(void);
+
+ virtual void action(const gcn::ActionEvent& actionEvent);
+
+protected:
+ GuiTable *mTable;
+ int mRow;
+ int mColumn;
+ gcn::Widget *mWidget;
+};
+
+
+GuiTableActionListener::GuiTableActionListener(GuiTable *table, gcn::Widget *widget, int row, int column) :
+ mTable(table),
+ mRow(row),
+ mColumn(column),
+ mWidget(widget)
+{
+ if (widget) {
+ widget->addActionListener(this);
+ widget->_setParent(table);
+ }
+}
+
+GuiTableActionListener::~GuiTableActionListener(void)
+{
+ if (mWidget) {
+ mWidget->removeActionListener(this);
+ mWidget->_setParent(NULL);
+ }
+}
+
+void
+GuiTableActionListener::action(const gcn::ActionEvent& actionEvent)
+{
+ mTable->setSelected(mRow, mColumn);
+ mTable->distributeActionEvent();
+}
+
+
+GuiTable::GuiTable(TableModel *initial_model) :
+ mLinewiseMode(false),
+ mModel(NULL),
+ mSelectedRow(0),
+ mSelectedColumn(0),
+ mTopWidget(NULL)
+{
+ setModel(initial_model);
+ addMouseListener(this);
+ addKeyListener(this);
+}
+
+GuiTable::~GuiTable(void)
+{
+ delete mModel;
+}
+
+TableModel *
+GuiTable::getModel(void) const
+{
+ return mModel;
+}
+
+void
+GuiTable::setModel(TableModel *new_model)
+{
+ if (mModel) {
+ uninstallActionListeners();
+ mModel->removeListener(this);
+ }
+
+ mModel = new_model;
+ installActionListeners();
+
+ new_model->installListener(this);
+ recomputeDimensions();
+}
+
+void
+GuiTable::recomputeDimensions(void)
+{
+ int rows_nr = mModel->getRows();
+ int columns_nr = mModel->getColumns();
+ int width = 0;
+ int height = 0;
+
+ if (mSelectedRow >= rows_nr)
+ mSelectedRow = rows_nr - 1;
+
+ if (mSelectedColumn >= columns_nr)
+ mSelectedColumn = columns_nr - 1;
+
+ for (int i = 0; i < columns_nr; i++)
+ width += getColumnWidth(i);
+
+ height = getRowHeight() * rows_nr;
+
+ setWidth(width);
+ setHeight(height);
+}
+
+void
+GuiTable::setSelected(int row, int column)
+{
+ mSelectedColumn = column;
+ mSelectedRow = row;
+}
+
+int
+GuiTable::getSelectedRow(void)
+{
+ return mSelectedRow;
+}
+
+int
+GuiTable::getSelectedColumn(void)
+{
+ return mSelectedColumn;
+}
+
+void
+GuiTable::setLinewiseSelection(bool linewise)
+{
+ mLinewiseMode = linewise;
+}
+
+int
+GuiTable::getRowHeight(void)
+{
+ if (mModel)
+ return mModel->getRowHeight() + 1; // border
+ else
+ return 0;
+}
+
+int
+GuiTable::getColumnWidth(int i)
+{
+ if (mModel)
+ return mModel->getColumnWidth(i) + 1; // border
+ else
+ return 0;
+}
+
+void
+GuiTable::uninstallActionListeners(void)
+{
+ for (std::vector<GuiTableActionListener *>::const_iterator it = action_listeners.begin(); it != action_listeners.end(); it++)
+ delete *it;
+ action_listeners.clear();
+}
+
+void
+GuiTable::installActionListeners(void)
+{
+ int rows = mModel->getRows();
+ int columns = mModel->getColumns();
+
+ for (int row = 0; row < rows; ++row)
+ for (int column = 0; column < columns; ++column) {
+ gcn::Widget *widget = mModel->getElementAt(row, column);
+ action_listeners.push_back(new GuiTableActionListener(this, widget,
+ row, column));
+ }
+
+ _setFocusHandler(_getFocusHandler()); // propagate focus handler to widgets
+}
+
+// -- widget ops
+void
+GuiTable::draw(gcn::Graphics* graphics)
+{
+ graphics->setColor(getBackgroundColor());
+ graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight()));
+
+ if (!mModel)
+ return;
+
+ // First, determine how many rows we need to draw, and where we should start.
+ int first_row = -(getY() / getRowHeight());
+
+ if (first_row < 0)
+ first_row = 0;
+
+ int rows_nr = 1 + (getHeight() / getRowHeight()); // May overestimate by one.
+
+ int max_rows_nr = mModel->getRows() - first_row; // clip if neccessary:
+ if (max_rows_nr < rows_nr)
+ rows_nr = max_rows_nr;
+
+ // Now determine the first and last column
+ // Take the easy way out; these are usually bounded and all visible.
+ int first_column = 0;
+ int last_column = mModel->getColumns() - 1;
+
+ // Set up everything for drawing
+ int height = getRowHeight();
+ int y_offset = first_row * height;
+
+ for (int r = first_row; r < first_row + rows_nr; ++r) {
+ int x_offset = 0;
+
+ for (int c = first_column; c <= last_column; ++c) {
+ gcn::Widget *widget = mModel->getElementAt(r, c);
+ int width = getColumnWidth(c);
+ if (widget) {
+ gcn::Rectangle bounds(x_offset, y_offset, width, height);
+
+ if (widget == mTopWidget) {
+ bounds.height = widget->getHeight();
+ bounds.width = widget->getWidth();
+ }
+
+ widget->setDimension(bounds);
+
+ graphics->pushClipArea(bounds);
+ widget->draw(graphics);
+ graphics->popClipArea();
+
+ if (!mLinewiseMode
+ && c == mSelectedColumn
+ && r == mSelectedRow)
+ graphics->drawRectangle(bounds);
+ }
+
+ x_offset += width;
+ }
+
+ if (mLinewiseMode
+ && r == mSelectedRow)
+ graphics->drawRectangle(gcn::Rectangle(0, y_offset,
+ x_offset, height));
+
+ y_offset += height;
+ }
+
+ if (mTopWidget) {
+ gcn::Rectangle bounds = mTopWidget->getDimension();
+ graphics->pushClipArea(bounds);
+ mTopWidget->draw(graphics);
+ graphics->popClipArea();
+ }
+}
+
+void
+GuiTable::logic(void)
+{
+}
+
+void
+GuiTable::moveToTop(gcn::Widget *widget)
+{
+ gcn::Widget::moveToTop(widget);
+ this->mTopWidget = widget;
+}
+
+void
+GuiTable::moveToBottom(gcn::Widget *widget)
+{
+ gcn::Widget::moveToBottom(widget);
+ if (widget == this->mTopWidget)
+ this->mTopWidget = NULL;
+}
+
+gcn::Rectangle
+GuiTable::getChildrenArea(void)
+{
+ return gcn::Rectangle(0, 0, getWidth(), getHeight());
+}
+
+// -- KeyListener notifications
+void
+GuiTable::keyPressed(gcn::KeyEvent& keyEvent)
+{
+}
+
+
+// -- MouseListener notifications
+void
+GuiTable::mousePressed(gcn::MouseEvent& mouseEvent)
+{
+ if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) {
+ int row = getRowForY(mouseEvent.getY());
+ int column = getColumnForX(mouseEvent.getX());
+
+ if (row > -1 && column > -1) {
+ mSelectedColumn = column;
+ mSelectedRow = row;
+ }
+
+ distributeActionEvent();
+ }
+}
+
+void
+GuiTable::mouseWheelMovedUp(gcn::MouseEvent& mouseEvent)
+{
+}
+
+void
+GuiTable::mouseWheelMovedDown(gcn::MouseEvent& mouseEvent)
+{
+}
+
+void
+GuiTable::mouseDragged(gcn::MouseEvent& mouseEvent)
+{
+}
+
+// -- TableModelListener notifications
+void
+GuiTable::modelUpdated(bool completed)
+{
+ if (completed) {
+ recomputeDimensions();
+ installActionListeners();
+ } else // before the update?
+ uninstallActionListeners();
+}
+
+gcn::Widget *
+GuiTable::getWidgetAt(int x, int y)
+{
+ int row = getRowForY(y);
+ int column = getColumnForX(x);
+
+ if (mTopWidget
+ && mTopWidget->getDimension().isPointInRect(x, y))
+ return mTopWidget;
+
+ if (row > -1
+ && column > -1) {
+ gcn::Widget *w = mModel->getElementAt(row, column);
+ if (w->isFocusable())
+ return w;
+ else
+ return NULL; // Grab the event locally
+ } else
+ return NULL;
+}
+
+int
+GuiTable::getRowForY(int y)
+{
+ int row = y / getRowHeight();
+
+ if (row < 0
+ || row >= mModel->getRows())
+ return -1;
+ else
+ return row;
+}
+
+int
+GuiTable::getColumnForX(int x)
+{
+ int column;
+ int delta = 0;
+
+ for (column = 0; column < mModel->getColumns(); column++) {
+ delta += getColumnWidth(column);
+ if (x <= delta)
+ break;
+ }
+
+ if (column < 0
+ || column >= mModel->getColumns())
+ return -1;
+ else
+ return column;
+}
+
+
+void
+GuiTable::_setFocusHandler(gcn::FocusHandler* focusHandler)
+{
+ gcn::Widget::_setFocusHandler(focusHandler);
+
+ if (mModel)
+ for (int r = 0; r < mModel->getRows(); ++r)
+ for (int c = 0; c < mModel->getColumns(); ++c) {
+ gcn::Widget *w = mModel->getElementAt(r, c);
+ if (w)
+ w->_setFocusHandler(focusHandler);
+ }
+}