From 0c7a728ea5c63769c59e7cdbd13fc56cf3dd63fc Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Fri, 12 Aug 2011 04:21:44 +0300 Subject: Rename file name table to correct guitable. --- src/CMakeLists.txt | 4 +- src/Makefile.am | 4 +- src/gui/botcheckerwindow.cpp | 2 +- src/gui/setup_relations.cpp | 2 +- src/gui/textcommandeditor.cpp | 2 +- src/gui/widgets/guitable.cpp | 595 ++++++++++++++++++++++++++++++++++++++++++ src/gui/widgets/guitable.h | 196 ++++++++++++++ src/gui/widgets/table.cpp | 595 ------------------------------------------ src/gui/widgets/table.h | 196 -------------- 9 files changed, 798 insertions(+), 798 deletions(-) create mode 100644 src/gui/widgets/guitable.cpp create mode 100644 src/gui/widgets/guitable.h delete mode 100644 src/gui/widgets/table.cpp delete mode 100644 src/gui/widgets/table.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 655d4896c..fba255c1c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -197,8 +197,8 @@ SET(SRCS gui/widgets/tab.h gui/widgets/tabbedarea.cpp gui/widgets/tabbedarea.h - gui/widgets/table.cpp - gui/widgets/table.h + gui/widgets/guitable.cpp + gui/widgets/guitable.h gui/widgets/tablemodel.cpp gui/widgets/tablemodel.h gui/widgets/textbox.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 8bacf6803..697575b97 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -200,8 +200,8 @@ manaplus_SOURCES += gui/widgets/avatarlistbox.cpp \ gui/widgets/tab.h \ gui/widgets/tabbedarea.cpp \ gui/widgets/tabbedarea.h \ - gui/widgets/table.cpp \ - gui/widgets/table.h \ + gui/widgets/guitable.cpp \ + gui/widgets/guitable.h \ gui/widgets/tablemodel.cpp \ gui/widgets/tablemodel.h \ gui/widgets/textbox.cpp \ diff --git a/src/gui/botcheckerwindow.cpp b/src/gui/botcheckerwindow.cpp index aa44df2f3..2851d3d1d 100644 --- a/src/gui/botcheckerwindow.cpp +++ b/src/gui/botcheckerwindow.cpp @@ -36,7 +36,7 @@ #include "gui/widgets/label.h" #include "gui/widgets/layout.h" #include "gui/widgets/layouthelper.h" -#include "gui/widgets/table.h" +#include "gui/widgets/guitable.h" #include "actorspritemanager.h" #include "configuration.h" diff --git a/src/gui/setup_relations.cpp b/src/gui/setup_relations.cpp index 93887b133..489d5a818 100644 --- a/src/gui/setup_relations.cpp +++ b/src/gui/setup_relations.cpp @@ -36,7 +36,7 @@ #include "gui/widgets/label.h" #include "gui/widgets/layouthelper.h" #include "gui/widgets/scrollarea.h" -#include "gui/widgets/table.h" +#include "gui/widgets/guitable.h" #include "gui/widgets/textfield.h" #include "utils/dtor.h" diff --git a/src/gui/textcommandeditor.cpp b/src/gui/textcommandeditor.cpp index 1f1273600..8cf9fa398 100644 --- a/src/gui/textcommandeditor.cpp +++ b/src/gui/textcommandeditor.cpp @@ -38,7 +38,7 @@ #include "gui/widgets/layout.h" #include "gui/widgets/layouthelper.h" #include "gui/widgets/radiobutton.h" -#include "gui/widgets/table.h" +#include "gui/widgets/guitable.h" #include "gui/widgets/textfield.h" #include "configuration.h" diff --git a/src/gui/widgets/guitable.cpp b/src/gui/widgets/guitable.cpp new file mode 100644 index 000000000..e25e0bb8c --- /dev/null +++ b/src/gui/widgets/guitable.cpp @@ -0,0 +1,595 @@ +/* + * The ManaPlus Client + * Copyright (C) 2008-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#include "gui/widgets/guitable.h" + +#include "client.h" +#include "configuration.h" + +#include "gui/sdlinput.h" +#include "gui/theme.h" + +#include "utils/dtor.h" + +#include +#include +#include + +#include "debug.h" + +float GuiTable::mAlpha = 1.0; + +class GuiTableActionListener : public gcn::ActionListener +{ +public: + GuiTableActionListener(GuiTable *_table, gcn::Widget *_widget, + int _row, int _column); + + virtual ~GuiTableActionListener(); + + 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() +{ + if (mWidget) + { + mWidget->removeActionListener(this); + mWidget->_setParent(NULL); + } +} + +void GuiTableActionListener::action(const gcn::ActionEvent + &actionEvent A_UNUSED) +{ + mTable->setSelected(mRow, mColumn); + mTable->distributeActionEvent(); +} + + +GuiTable::GuiTable(TableModel *initial_model, gcn::Color background, + bool opacity) : + mLinewiseMode(false), + mWrappingEnabled(false), + mOpaque(opacity), + mBackgroundColor(background), + mModel(NULL), + mSelectedRow(0), + mSelectedColumn(0), + mTopWidget(NULL) +{ + setModel(initial_model); + setFocusable(true); + + addMouseListener(this); + addKeyListener(this); +} + +GuiTable::~GuiTable() +{ + uninstallActionListeners(); + delete mModel; + mModel = 0; +} + +TableModel *GuiTable::getModel() const +{ + return mModel; +} + +void GuiTable::setModel(TableModel *new_model) +{ + if (mModel) + { + uninstallActionListeners(); + mModel->removeListener(this); + } + + mModel = new_model; + installActionListeners(); + + if (new_model) + { + new_model->installListener(this); + recomputeDimensions(); + } +} + +void GuiTable::recomputeDimensions() +{ + if (!mModel) + return; + + 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() const +{ + return mSelectedRow; +} + +int GuiTable::getSelectedColumn() const +{ + return mSelectedColumn; +} + +void GuiTable::setLinewiseSelection(bool linewise) +{ + mLinewiseMode = linewise; +} + +int GuiTable::getRowHeight() const +{ + if (mModel) + return mModel->getRowHeight() + 1; // border + else + return 0; +} + +int GuiTable::getColumnWidth(int i) const +{ + if (mModel) + return mModel->getColumnWidth(i) + 1; // border + else + return 0; +} + +void GuiTable::setSelectedRow(int selected) +{ + if (!mModel) + { + mSelectedRow = -1; + } + else + { + if (selected < 0 && !mWrappingEnabled) + { + mSelectedRow = -1; + } + else if (selected >= mModel->getRows() && mWrappingEnabled) + { + mSelectedRow = 0; + } + else if ((selected >= mModel->getRows() && !mWrappingEnabled) || + (selected < 0 && mWrappingEnabled)) + { + mSelectedRow = mModel->getRows() - 1; + } + else + { + mSelectedRow = selected; + } + } +} + +void GuiTable::setSelectedColumn(int selected) +{ + if (!mModel) + { + mSelectedColumn = -1; + } + else + { + if ((selected >= mModel->getColumns() && mWrappingEnabled) || + (selected < 0 && !mWrappingEnabled)) + { + mSelectedColumn = 0; + } + else if ((selected >= mModel->getColumns() && !mWrappingEnabled) || + (selected < 0 && mWrappingEnabled)) + { + mSelectedColumn = mModel->getColumns() - 1; + } + else + { + mSelectedColumn = selected; + } + } +} + +void GuiTable::uninstallActionListeners() +{ + delete_all(mActionListeners); + mActionListeners.clear(); +} + +void GuiTable::installActionListeners() +{ + if (!mModel) + return; + + 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); + if (widget) + { + mActionListeners.push_back(new GuiTableActionListener( + this, widget, row, column)); + } + } + } + + _setFocusHandler(_getFocusHandler()); // propagate focus handler to widgets +} + +// -- widget ops +void GuiTable::draw(gcn::Graphics* graphics) +{ + if (!mModel || !getRowHeight()) + return; + + if (Client::getGuiAlpha() != mAlpha) + mAlpha = Client::getGuiAlpha(); + + if (mOpaque) + { + graphics->setColor(Theme::getThemeColor(Theme::BACKGROUND, + static_cast(mAlpha * 255.0f))); + graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight())); + } + + // 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; + + unsigned rows_nr = 1 + (getHeight() / getRowHeight()); // May overestimate + // by one. + + unsigned max_rows_nr; + if (mModel->getRows() < first_row) + max_rows_nr = 0; + else + 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. + unsigned first_column = 0; + unsigned last_column1 = mModel->getColumns(); + + // Set up everything for drawing + int height = getRowHeight(); + int y_offset = first_row * height; + + for (unsigned r = first_row; r < first_row + rows_nr; ++r) + { + int x_offset = 0; + + for (unsigned c = first_column; c + 1 <= last_column1; ++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->setColor(Theme::getThemeColor(Theme::HIGHLIGHT, + static_cast(mAlpha * 255.0f))); + + if (mSelectedRow > 0) + { + if (mLinewiseMode && r == (unsigned)mSelectedRow && c == 0) + { + graphics->fillRectangle(gcn::Rectangle(0, y_offset, + getWidth(), height)); + } + else if (!mLinewiseMode && mSelectedColumn > 0 + && c == (unsigned)mSelectedColumn + && r == (unsigned)mSelectedRow) + { + graphics->fillRectangle(gcn::Rectangle( + x_offset, y_offset, width, height)); + } + } + graphics->pushClipArea(bounds); + widget->draw(graphics); + graphics->popClipArea(); + } + + x_offset += width; + } + + y_offset += height; + } + + if (mTopWidget) + { + gcn::Rectangle bounds = mTopWidget->getDimension(); + graphics->pushClipArea(bounds); + mTopWidget->draw(graphics); + graphics->popClipArea(); + } +} + +void GuiTable::moveToTop(gcn::Widget *widget) +{ + gcn::Widget::moveToTop(widget); + mTopWidget = widget; +} + +void GuiTable::moveToBottom(gcn::Widget *widget) +{ + gcn::Widget::moveToBottom(widget); + if (widget == mTopWidget) + mTopWidget = NULL; +} + +gcn::Rectangle GuiTable::getChildrenArea() +{ + return gcn::Rectangle(0, 0, getWidth(), getHeight()); +} + +// -- KeyListener notifications +void GuiTable::keyPressed(gcn::KeyEvent& keyEvent) +{ + gcn::Key key = keyEvent.getKey(); + + if (key.getValue() == Key::ENTER || key.getValue() == Key::SPACE) + { + distributeActionEvent(); + keyEvent.consume(); + } + else if (key.getValue() == Key::UP) + { + setSelectedRow(mSelectedRow - 1); + keyEvent.consume(); + } + else if (key.getValue() == Key::DOWN) + { + setSelectedRow(mSelectedRow + 1); + keyEvent.consume(); + } + else if (key.getValue() == Key::LEFT) + { + setSelectedColumn(mSelectedColumn - 1); + keyEvent.consume(); + } + else if (key.getValue() == Key::RIGHT) + { + setSelectedColumn(mSelectedColumn + 1); + keyEvent.consume(); + } + else if (key.getValue() == Key::HOME) + { + setSelectedRow(0); + setSelectedColumn(0); + keyEvent.consume(); + } + else if (key.getValue() == Key::END && mModel) + { + setSelectedRow(mModel->getRows() - 1); + setSelectedColumn(mModel->getColumns() - 1); + keyEvent.consume(); + } +} + +// -- MouseListener notifications +void GuiTable::mousePressed(gcn::MouseEvent& mouseEvent) +{ + if (!mModel) + return; + + if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) + { + int row = getRowForY(mouseEvent.getY()); + int column = getColumnForX(mouseEvent.getX()); + + if (row > -1 && column > -1 && + row < mModel->getRows() && column < mModel->getColumns()) + { + mSelectedColumn = column; + mSelectedRow = row; + } + + distributeActionEvent(); + } +} + +void GuiTable::mouseWheelMovedUp(gcn::MouseEvent& mouseEvent) +{ + if (isFocused()) + { + if (getSelectedRow() > 0 || (getSelectedRow() == 0 + && mWrappingEnabled)) + { + setSelectedRow(getSelectedRow() - 1); + } + + mouseEvent.consume(); + } +} + +void GuiTable::mouseWheelMovedDown(gcn::MouseEvent& mouseEvent) +{ + if (isFocused()) + { + setSelectedRow(getSelectedRow() + 1); + + mouseEvent.consume(); + } +} + +void GuiTable::mouseDragged(gcn::MouseEvent& mouseEvent) +{ + if (mouseEvent.getButton() != gcn::MouseEvent::LEFT) + return; + + // Make table selection update on drag + const int x = std::max(0, mouseEvent.getX()); + const int y = std::max(0, mouseEvent.getY()); + + setSelectedRow(getRowForY(y)); + setSelectedColumn(getColumnForX(x)); +} + +// -- TableModelListener notifications +void GuiTable::modelUpdated(bool completed) +{ + if (completed) + { + recomputeDimensions(); + installActionListeners(); + } + else + { // before the update? + mTopWidget = NULL; // No longer valid in general + 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 (mModel && row > -1 && column > -1) + { + gcn::Widget *w = mModel->getElementAt(row, column); + if (w && w->isFocusable()) + return w; + else + return NULL; // Grab the event locally + } + else + return NULL; +} + +int GuiTable::getRowForY(int y) const +{ + int row = -1; + + if (getRowHeight() > 0) + row = y / getRowHeight(); + + if (!mModel || row < 0 || row >= mModel->getRows()) + return -1; + else + return row; +} + +int GuiTable::getColumnForX(int x) const +{ + if (!mModel) + return -1; + + 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) +{ +// add check for focusHandler. may be need remove it? + + if (!mModel || !focusHandler) + return; + + 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); + } + } + } +} diff --git a/src/gui/widgets/guitable.h b/src/gui/widgets/guitable.h new file mode 100644 index 000000000..c4fab6a0d --- /dev/null +++ b/src/gui/widgets/guitable.h @@ -0,0 +1,196 @@ +/* + * The ManaPlus Client + * Copyright (C) 2008-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * Copyright (C) 2011 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program 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. + * + * This program 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 this program. If not, see . + */ + +#ifndef TABLE_H +#define TABLE_H + +#include "gui/widgets/tablemodel.h" + +#include +#include +#include + +#include + +#ifdef __GNUC__ +#define A_UNUSED __attribute__ ((unused)) +#else +#define A_UNUSED +#endif + +class GuiTableActionListener; + +/** + * A table, with rows and columns made out of sub-widgets. Largely inspired by + * (and can be thought of as a generalisation of) the guichan listbox + * implementation. + * + * Normally you want this within a ScrollArea. + * + * \ingroup GUI + */ +class GuiTable : public gcn::Widget, + public gcn::MouseListener, + public gcn::KeyListener, + public TableModelListener +{ + // so that the action listener can call distributeActionEvent + friend class GuiTableActionListener; + +public: + GuiTable(TableModel * initial_model = NULL, + gcn::Color background = 0xffffff, + bool opacity = true); + + virtual ~GuiTable(); + + /** + * Retrieves the active table model + */ + TableModel *getModel() const; + + /** + * Sets the table model + * + * Note that actions issued by widgets returned from the model will update + * the table selection, but only AFTER any event handlers installed within + * the widget have been triggered. To be notified after such an update, add + * an action listener to the table instead. + */ + void setModel(TableModel *m); + + void setSelected(int row, int column); + + int getSelectedRow() const; + + int getSelectedColumn() const; + + void setSelectedRow(int selected); + + void setSelectedColumn(int selected); + + bool isWrappingEnabled() const + { return mWrappingEnabled; } + + void setWrappingEnabled(bool wrappingEnabled) + { mWrappingEnabled = wrappingEnabled; } + + gcn::Rectangle getChildrenArea(); + + /** + * Toggle whether to use linewise selection mode, in which the table selects + * an entire line at a time, rather than a single cell. + * + * Note that column information is tracked even in linewise selection mode; + * this mode therefore only affects visualisation. + * + * Disabled by default. + * + * \param linewise: Whether to enable linewise selection mode + */ + void setLinewiseSelection(bool linewise); + + // Inherited from Widget + virtual void draw(gcn::Graphics* graphics); + + virtual gcn::Widget *getWidgetAt(int x, int y); + + virtual void moveToTop(gcn::Widget *child); + + virtual void moveToBottom(gcn::Widget *child); + + virtual void _setFocusHandler(gcn::FocusHandler* focusHandler); + + // Inherited from KeyListener + virtual void keyPressed(gcn::KeyEvent& keyEvent); + + /** + * Sets the table to be opaque, that is sets the table + * to display its background. + * + * @param opaque True if the table should be opaque, false otherwise. + */ + virtual void setOpaque(bool opaque) + { mOpaque = opaque; } + + /** + * Checks if the table is opaque, that is if the table area displays its + * background. + * + * @return True if the table is opaque, false otherwise. + */ + virtual bool isOpaque() const + { return mOpaque; } + + // Inherited from MouseListener + virtual void mousePressed(gcn::MouseEvent& mouseEvent); + + virtual void mouseWheelMovedUp(gcn::MouseEvent& mouseEvent); + + virtual void mouseWheelMovedDown(gcn::MouseEvent& mouseEvent); + + virtual void mouseDragged(gcn::MouseEvent& mouseEvent); + + // Constraints inherited from TableModelListener + virtual void modelUpdated(bool); + +protected: + /** Frees all action listeners on inner widgets. */ + virtual void uninstallActionListeners(); + /** Installs all action listeners on inner widgets. */ + virtual void installActionListeners(); + + virtual int getRowHeight() const; + virtual int getColumnWidth(int i) const; + +private: + int getRowForY(int y) const; // -1 on error + int getColumnForX(int x) const; // -1 on error + void recomputeDimensions(); + bool mLinewiseMode; + bool mWrappingEnabled; + bool mOpaque; + + static float mAlpha; + + /** + * Holds the background color of the table. + */ + gcn::Color mBackgroundColor; + + TableModel *mModel; + + int mSelectedRow; + int mSelectedColumn; + + /** Number of frames to skip upwards when drawing the selected widget. */ + int mPopFramesNr; + + /** If someone moves a fresh widget to the top, we must display it. */ + gcn::Widget *mTopWidget; + + /** Vector for compactness; used as a list in practice. */ + std::vector mActionListeners; +}; + + +#endif // TABLE_H diff --git a/src/gui/widgets/table.cpp b/src/gui/widgets/table.cpp deleted file mode 100644 index 04ae41ad7..000000000 --- a/src/gui/widgets/table.cpp +++ /dev/null @@ -1,595 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2008-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program 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. - * - * This program 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 this program. If not, see . - */ - -#include "gui/widgets/table.h" - -#include "client.h" -#include "configuration.h" - -#include "gui/sdlinput.h" -#include "gui/theme.h" - -#include "utils/dtor.h" - -#include -#include -#include - -#include "debug.h" - -float GuiTable::mAlpha = 1.0; - -class GuiTableActionListener : public gcn::ActionListener -{ -public: - GuiTableActionListener(GuiTable *_table, gcn::Widget *_widget, - int _row, int _column); - - virtual ~GuiTableActionListener(); - - 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() -{ - if (mWidget) - { - mWidget->removeActionListener(this); - mWidget->_setParent(NULL); - } -} - -void GuiTableActionListener::action(const gcn::ActionEvent - &actionEvent A_UNUSED) -{ - mTable->setSelected(mRow, mColumn); - mTable->distributeActionEvent(); -} - - -GuiTable::GuiTable(TableModel *initial_model, gcn::Color background, - bool opacity) : - mLinewiseMode(false), - mWrappingEnabled(false), - mOpaque(opacity), - mBackgroundColor(background), - mModel(NULL), - mSelectedRow(0), - mSelectedColumn(0), - mTopWidget(NULL) -{ - setModel(initial_model); - setFocusable(true); - - addMouseListener(this); - addKeyListener(this); -} - -GuiTable::~GuiTable() -{ - uninstallActionListeners(); - delete mModel; - mModel = 0; -} - -TableModel *GuiTable::getModel() const -{ - return mModel; -} - -void GuiTable::setModel(TableModel *new_model) -{ - if (mModel) - { - uninstallActionListeners(); - mModel->removeListener(this); - } - - mModel = new_model; - installActionListeners(); - - if (new_model) - { - new_model->installListener(this); - recomputeDimensions(); - } -} - -void GuiTable::recomputeDimensions() -{ - if (!mModel) - return; - - 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() const -{ - return mSelectedRow; -} - -int GuiTable::getSelectedColumn() const -{ - return mSelectedColumn; -} - -void GuiTable::setLinewiseSelection(bool linewise) -{ - mLinewiseMode = linewise; -} - -int GuiTable::getRowHeight() const -{ - if (mModel) - return mModel->getRowHeight() + 1; // border - else - return 0; -} - -int GuiTable::getColumnWidth(int i) const -{ - if (mModel) - return mModel->getColumnWidth(i) + 1; // border - else - return 0; -} - -void GuiTable::setSelectedRow(int selected) -{ - if (!mModel) - { - mSelectedRow = -1; - } - else - { - if (selected < 0 && !mWrappingEnabled) - { - mSelectedRow = -1; - } - else if (selected >= mModel->getRows() && mWrappingEnabled) - { - mSelectedRow = 0; - } - else if ((selected >= mModel->getRows() && !mWrappingEnabled) || - (selected < 0 && mWrappingEnabled)) - { - mSelectedRow = mModel->getRows() - 1; - } - else - { - mSelectedRow = selected; - } - } -} - -void GuiTable::setSelectedColumn(int selected) -{ - if (!mModel) - { - mSelectedColumn = -1; - } - else - { - if ((selected >= mModel->getColumns() && mWrappingEnabled) || - (selected < 0 && !mWrappingEnabled)) - { - mSelectedColumn = 0; - } - else if ((selected >= mModel->getColumns() && !mWrappingEnabled) || - (selected < 0 && mWrappingEnabled)) - { - mSelectedColumn = mModel->getColumns() - 1; - } - else - { - mSelectedColumn = selected; - } - } -} - -void GuiTable::uninstallActionListeners() -{ - delete_all(mActionListeners); - mActionListeners.clear(); -} - -void GuiTable::installActionListeners() -{ - if (!mModel) - return; - - 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); - if (widget) - { - mActionListeners.push_back(new GuiTableActionListener( - this, widget, row, column)); - } - } - } - - _setFocusHandler(_getFocusHandler()); // propagate focus handler to widgets -} - -// -- widget ops -void GuiTable::draw(gcn::Graphics* graphics) -{ - if (!mModel || !getRowHeight()) - return; - - if (Client::getGuiAlpha() != mAlpha) - mAlpha = Client::getGuiAlpha(); - - if (mOpaque) - { - graphics->setColor(Theme::getThemeColor(Theme::BACKGROUND, - static_cast(mAlpha * 255.0f))); - graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight())); - } - - // 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; - - unsigned rows_nr = 1 + (getHeight() / getRowHeight()); // May overestimate - // by one. - - unsigned max_rows_nr; - if (mModel->getRows() < first_row) - max_rows_nr = 0; - else - 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. - unsigned first_column = 0; - unsigned last_column1 = mModel->getColumns(); - - // Set up everything for drawing - int height = getRowHeight(); - int y_offset = first_row * height; - - for (unsigned r = first_row; r < first_row + rows_nr; ++r) - { - int x_offset = 0; - - for (unsigned c = first_column; c + 1 <= last_column1; ++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->setColor(Theme::getThemeColor(Theme::HIGHLIGHT, - static_cast(mAlpha * 255.0f))); - - if (mSelectedRow > 0) - { - if (mLinewiseMode && r == (unsigned)mSelectedRow && c == 0) - { - graphics->fillRectangle(gcn::Rectangle(0, y_offset, - getWidth(), height)); - } - else if (!mLinewiseMode && mSelectedColumn > 0 - && c == (unsigned)mSelectedColumn - && r == (unsigned)mSelectedRow) - { - graphics->fillRectangle(gcn::Rectangle( - x_offset, y_offset, width, height)); - } - } - graphics->pushClipArea(bounds); - widget->draw(graphics); - graphics->popClipArea(); - } - - x_offset += width; - } - - y_offset += height; - } - - if (mTopWidget) - { - gcn::Rectangle bounds = mTopWidget->getDimension(); - graphics->pushClipArea(bounds); - mTopWidget->draw(graphics); - graphics->popClipArea(); - } -} - -void GuiTable::moveToTop(gcn::Widget *widget) -{ - gcn::Widget::moveToTop(widget); - mTopWidget = widget; -} - -void GuiTable::moveToBottom(gcn::Widget *widget) -{ - gcn::Widget::moveToBottom(widget); - if (widget == mTopWidget) - mTopWidget = NULL; -} - -gcn::Rectangle GuiTable::getChildrenArea() -{ - return gcn::Rectangle(0, 0, getWidth(), getHeight()); -} - -// -- KeyListener notifications -void GuiTable::keyPressed(gcn::KeyEvent& keyEvent) -{ - gcn::Key key = keyEvent.getKey(); - - if (key.getValue() == Key::ENTER || key.getValue() == Key::SPACE) - { - distributeActionEvent(); - keyEvent.consume(); - } - else if (key.getValue() == Key::UP) - { - setSelectedRow(mSelectedRow - 1); - keyEvent.consume(); - } - else if (key.getValue() == Key::DOWN) - { - setSelectedRow(mSelectedRow + 1); - keyEvent.consume(); - } - else if (key.getValue() == Key::LEFT) - { - setSelectedColumn(mSelectedColumn - 1); - keyEvent.consume(); - } - else if (key.getValue() == Key::RIGHT) - { - setSelectedColumn(mSelectedColumn + 1); - keyEvent.consume(); - } - else if (key.getValue() == Key::HOME) - { - setSelectedRow(0); - setSelectedColumn(0); - keyEvent.consume(); - } - else if (key.getValue() == Key::END && mModel) - { - setSelectedRow(mModel->getRows() - 1); - setSelectedColumn(mModel->getColumns() - 1); - keyEvent.consume(); - } -} - -// -- MouseListener notifications -void GuiTable::mousePressed(gcn::MouseEvent& mouseEvent) -{ - if (!mModel) - return; - - if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) - { - int row = getRowForY(mouseEvent.getY()); - int column = getColumnForX(mouseEvent.getX()); - - if (row > -1 && column > -1 && - row < mModel->getRows() && column < mModel->getColumns()) - { - mSelectedColumn = column; - mSelectedRow = row; - } - - distributeActionEvent(); - } -} - -void GuiTable::mouseWheelMovedUp(gcn::MouseEvent& mouseEvent) -{ - if (isFocused()) - { - if (getSelectedRow() > 0 || (getSelectedRow() == 0 - && mWrappingEnabled)) - { - setSelectedRow(getSelectedRow() - 1); - } - - mouseEvent.consume(); - } -} - -void GuiTable::mouseWheelMovedDown(gcn::MouseEvent& mouseEvent) -{ - if (isFocused()) - { - setSelectedRow(getSelectedRow() + 1); - - mouseEvent.consume(); - } -} - -void GuiTable::mouseDragged(gcn::MouseEvent& mouseEvent) -{ - if (mouseEvent.getButton() != gcn::MouseEvent::LEFT) - return; - - // Make table selection update on drag - const int x = std::max(0, mouseEvent.getX()); - const int y = std::max(0, mouseEvent.getY()); - - setSelectedRow(getRowForY(y)); - setSelectedColumn(getColumnForX(x)); -} - -// -- TableModelListener notifications -void GuiTable::modelUpdated(bool completed) -{ - if (completed) - { - recomputeDimensions(); - installActionListeners(); - } - else - { // before the update? - mTopWidget = NULL; // No longer valid in general - 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 (mModel && row > -1 && column > -1) - { - gcn::Widget *w = mModel->getElementAt(row, column); - if (w && w->isFocusable()) - return w; - else - return NULL; // Grab the event locally - } - else - return NULL; -} - -int GuiTable::getRowForY(int y) const -{ - int row = -1; - - if (getRowHeight() > 0) - row = y / getRowHeight(); - - if (!mModel || row < 0 || row >= mModel->getRows()) - return -1; - else - return row; -} - -int GuiTable::getColumnForX(int x) const -{ - if (!mModel) - return -1; - - 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) -{ -// add check for focusHandler. may be need remove it? - - if (!mModel || !focusHandler) - return; - - 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); - } - } - } -} diff --git a/src/gui/widgets/table.h b/src/gui/widgets/table.h deleted file mode 100644 index c4fab6a0d..000000000 --- a/src/gui/widgets/table.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2008-2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program 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. - * - * This program 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 this program. If not, see . - */ - -#ifndef TABLE_H -#define TABLE_H - -#include "gui/widgets/tablemodel.h" - -#include -#include -#include - -#include - -#ifdef __GNUC__ -#define A_UNUSED __attribute__ ((unused)) -#else -#define A_UNUSED -#endif - -class GuiTableActionListener; - -/** - * A table, with rows and columns made out of sub-widgets. Largely inspired by - * (and can be thought of as a generalisation of) the guichan listbox - * implementation. - * - * Normally you want this within a ScrollArea. - * - * \ingroup GUI - */ -class GuiTable : public gcn::Widget, - public gcn::MouseListener, - public gcn::KeyListener, - public TableModelListener -{ - // so that the action listener can call distributeActionEvent - friend class GuiTableActionListener; - -public: - GuiTable(TableModel * initial_model = NULL, - gcn::Color background = 0xffffff, - bool opacity = true); - - virtual ~GuiTable(); - - /** - * Retrieves the active table model - */ - TableModel *getModel() const; - - /** - * Sets the table model - * - * Note that actions issued by widgets returned from the model will update - * the table selection, but only AFTER any event handlers installed within - * the widget have been triggered. To be notified after such an update, add - * an action listener to the table instead. - */ - void setModel(TableModel *m); - - void setSelected(int row, int column); - - int getSelectedRow() const; - - int getSelectedColumn() const; - - void setSelectedRow(int selected); - - void setSelectedColumn(int selected); - - bool isWrappingEnabled() const - { return mWrappingEnabled; } - - void setWrappingEnabled(bool wrappingEnabled) - { mWrappingEnabled = wrappingEnabled; } - - gcn::Rectangle getChildrenArea(); - - /** - * Toggle whether to use linewise selection mode, in which the table selects - * an entire line at a time, rather than a single cell. - * - * Note that column information is tracked even in linewise selection mode; - * this mode therefore only affects visualisation. - * - * Disabled by default. - * - * \param linewise: Whether to enable linewise selection mode - */ - void setLinewiseSelection(bool linewise); - - // Inherited from Widget - virtual void draw(gcn::Graphics* graphics); - - virtual gcn::Widget *getWidgetAt(int x, int y); - - virtual void moveToTop(gcn::Widget *child); - - virtual void moveToBottom(gcn::Widget *child); - - virtual void _setFocusHandler(gcn::FocusHandler* focusHandler); - - // Inherited from KeyListener - virtual void keyPressed(gcn::KeyEvent& keyEvent); - - /** - * Sets the table to be opaque, that is sets the table - * to display its background. - * - * @param opaque True if the table should be opaque, false otherwise. - */ - virtual void setOpaque(bool opaque) - { mOpaque = opaque; } - - /** - * Checks if the table is opaque, that is if the table area displays its - * background. - * - * @return True if the table is opaque, false otherwise. - */ - virtual bool isOpaque() const - { return mOpaque; } - - // Inherited from MouseListener - virtual void mousePressed(gcn::MouseEvent& mouseEvent); - - virtual void mouseWheelMovedUp(gcn::MouseEvent& mouseEvent); - - virtual void mouseWheelMovedDown(gcn::MouseEvent& mouseEvent); - - virtual void mouseDragged(gcn::MouseEvent& mouseEvent); - - // Constraints inherited from TableModelListener - virtual void modelUpdated(bool); - -protected: - /** Frees all action listeners on inner widgets. */ - virtual void uninstallActionListeners(); - /** Installs all action listeners on inner widgets. */ - virtual void installActionListeners(); - - virtual int getRowHeight() const; - virtual int getColumnWidth(int i) const; - -private: - int getRowForY(int y) const; // -1 on error - int getColumnForX(int x) const; // -1 on error - void recomputeDimensions(); - bool mLinewiseMode; - bool mWrappingEnabled; - bool mOpaque; - - static float mAlpha; - - /** - * Holds the background color of the table. - */ - gcn::Color mBackgroundColor; - - TableModel *mModel; - - int mSelectedRow; - int mSelectedColumn; - - /** Number of frames to skip upwards when drawing the selected widget. */ - int mPopFramesNr; - - /** If someone moves a fresh widget to the top, we must display it. */ - gcn::Widget *mTopWidget; - - /** Vector for compactness; used as a list in practice. */ - std::vector mActionListeners; -}; - - -#endif // TABLE_H -- cgit v1.2.3-70-g09d2