diff --git a/ChangeLog b/ChangeLog index e02509b..406df5e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ Version 1.1.0 ============= +* SDLImage::convertToDisplayFormat now throws an exception if conversion fails. +* Fixed text drawn outside of a TextField. +* Fixed focus issues when having a TextField inside a Tab. +* Fixed selecting with arrow keys when DropDown is open skipping items +* Fixed DropDown inside a TabbedArea looking odd when dropped down. * BasicContainer and Widget has been merged making every Widget a possible container. The merge makes it a lot easier to implement container widgets. With the merge there is no need diff --git a/TODO b/TODO index 0d222c7..3324f7a 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,3 @@ -* Continue rebasing from 636e1837a62cb3126d6a8554856c1219160161a9 * Add a focus listener interface. * Make focus apply synchronously. * Graphics and input objects for DirectX. diff --git a/include/guisan/gui.hpp b/include/guisan/gui.hpp index 67267d2..98ae961 100644 --- a/include/guisan/gui.hpp +++ b/include/guisan/gui.hpp @@ -77,17 +77,23 @@ namespace gcn /** * @mainpage * @section Introduction - * This documentation is mostly intended as a reference to the API. If you want to get started with Guichan, we suggest you check out the programs in the examples directory of the Guichan release. + * This documentation is mostly intended as a reference to the API. + * If you want to get started with Guisan, + * we suggest you check out the programs + * in the examples directory of the Guisan release. * @n * @n - * This documentation is, and will always be, work in progress. If you find any errors, typos or inconsistencies, or if you feel something needs to be explained in more detail - don't hesitate to tell us. + * This documentation is, and will always be, work in progress. + * If you find any errors, typos or inconsistencies, + * or if you feel something needs to be explained in more detail, + * don't hesitate to tell us. */ /** * Contains a Guisan GUI. This is the core class of Guisan to which * implementations of back ends are passed, to make Guisan work with * a specific library, and to where the top widget (root widget of GUI) - * is added. If you want to be able to have more then one widget in your + * is added. If you want to be able to have more then one widget in your * GUI, the top widget should be a container. * * A Gui object cannot work properly without passing back end @@ -300,7 +306,7 @@ namespace gcn virtual void handleMouseReleased(const MouseInput& mouseInput); /** - * Handles modal focus. Modal focus needs to be checked at + * Handles modal focus. Modal focus needs to be checked at * each logic iteration as it might be necessary to distribute * mouse entered or mouse exited events. * @@ -309,8 +315,8 @@ namespace gcn virtual void handleModalFocus(); /** - * Handles modal mouse input focus. Modal mouse input focus needs - * to be checked at each logic iteration as it might be necessary to + * Handles modal mouse input focus. Modal mouse input focus needs + * to be checked at each logic iteration as it might be necessary to * distribute mouse entered or mouse exited events. * * @since 0.8.0 @@ -318,7 +324,7 @@ namespace gcn virtual void handleModalMouseInputFocus(); /** - * Handles modal focus gained. If modal focus has been gaind it might + * Handles modal focus gained. If modal focus has been gained it might * be necessary to distribute mouse entered or mouse exited events. * * @since 0.8.0 @@ -326,7 +332,7 @@ namespace gcn virtual void handleModalFocusGained(); /** - * Handles modal mouse input focus gained. If modal focus has been gaind + * Handles modal mouse input focus gained. If modal focus has been gained * it might be necessary to distribute mouse entered or mouse exited events. * * @since 0.8.0 @@ -343,7 +349,7 @@ namespace gcn * @param fource indicates whether the distribution should be forced or not. * A forced distribution distributes the event even if a widget * is not enabled, not visible, another widget has modal - * focus or another widget has modal mouse input focus. + * focus or another widget has modal mouse input focus. * Default value is false. * @param toSourceOnly indicates whether the distribution should be to the * source widget only or to it's parent's mouse listeners diff --git a/include/guisan/key.hpp b/include/guisan/key.hpp index ff213ff..a10c5cb 100644 --- a/include/guisan/key.hpp +++ b/include/guisan/key.hpp @@ -147,7 +147,8 @@ namespace gcn Space = ' ', Tab = '\t', Enter = '\n', - LeftAlt = 1000, + // Negative values, to avoid conflicts with higher character codes + LeftAlt = -1000, RightAlt, LeftShift, RightShift, diff --git a/include/guisan/text.hpp b/include/guisan/text.hpp index f712dc1..5de90d0 100644 --- a/include/guisan/text.hpp +++ b/include/guisan/text.hpp @@ -328,19 +328,19 @@ namespace gcn * Holds the position of the caret. This variable should * always be valid. */ - unsigned int mCaretPosition; + unsigned int mCaretPosition = 0; /** * Holds the row the caret is in. This variable should always * be valid. */ - unsigned int mCaretRow; + unsigned int mCaretRow = 0; /** * Holds the column the caret is in. This variable should always * be valid. */ - unsigned int mCaretColumn; + unsigned int mCaretColumn = 0; }; } // namespace gcn #endif diff --git a/include/guisan/widgets/tabbedarea.hpp b/include/guisan/widgets/tabbedarea.hpp index 7a0811d..cad650e 100644 --- a/include/guisan/widgets/tabbedarea.hpp +++ b/include/guisan/widgets/tabbedarea.hpp @@ -122,6 +122,13 @@ namespace gcn */ bool isOpaque() const; + /** + * Checks if the tabbed area is active or not. + * + * @return true if the tabbed area is active, false otherwise. + */ + bool isTabActive() const; + /** * Adds a tab to the tabbed area. The newly created tab will be * automatically deleted by the tabbed area when it is removed. @@ -158,6 +165,13 @@ namespace gcn */ virtual void removeTab(Tab* tab); + /** + * Returns the number of tabs in this tabbed area. + * + * @since 1.1.0 + */ + int getNumberOfTabs() const; + /** * Checks if a tab given an index is selected or not. * @@ -286,6 +300,11 @@ namespace gcn * True if the tabbed area is opaque, false otherwise. */ bool mOpaque; + + /** + * True if the tabbed area is active, false otherwise. + */ + bool tabActive; }; } diff --git a/src/sdl/sdlimage.cpp b/src/sdl/sdlimage.cpp index 582758a..752fdda 100644 --- a/src/sdl/sdlimage.cpp +++ b/src/sdl/sdlimage.cpp @@ -174,6 +174,11 @@ namespace gcn SDL_FreeSurface(mSurface); mSurface = NULL; + if (tmp == NULL) + { + throw GCN_EXCEPTION("Unable to convert image to display format."); + } + if (hasPink) { SDL_SetColorKey(tmp, SDL_TRUE, @@ -191,7 +196,7 @@ namespace gcn SDL_SetTextureBlendMode(tmpTexture, SDL_BLENDMODE_BLEND); SDL_DestroyTexture(mTexture); mTexture = tmpTexture; - } + } } void SDLImage::free() diff --git a/src/text.cpp b/src/text.cpp index 672aad1..c91b03c 100644 --- a/src/text.cpp +++ b/src/text.cpp @@ -52,12 +52,12 @@ namespace gcn { - Text::Text() : mCaretPosition(0), mCaretColumn(0), mCaretRow(0) + Text::Text() { mRows.emplace_back(); } - Text::Text(const std::string& content) : mCaretPosition(0), mCaretColumn(0), mCaretRow(0) + Text::Text(const std::string& content) { std::string::size_type pos, lastPos = 0; int length; diff --git a/src/widget.cpp b/src/widget.cpp index 8edf6a6..ada3bb9 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -672,8 +672,7 @@ namespace gcn x -= r.x; y -= r.y; - std::list::const_reverse_iterator iter; - for (iter = mChildren.rbegin(); iter != mChildren.rend(); iter++) + for (auto iter = mChildren.rbegin(); iter != mChildren.rend(); ++iter) { Widget* widget = (*iter); if (widget->isVisible() && widget->getDimension().isContaining(x, y)) @@ -1016,17 +1015,15 @@ namespace gcn void Widget::focusPrevious() { - std::list::const_reverse_iterator iter; - - for (iter = mChildren.rbegin(); iter != mChildren.rend(); iter++) + auto iter = mChildren.rbegin(); + for (; iter != mChildren.rend(); ++iter) { if ((*iter)->isFocused()) { break; } } - - std::list::const_reverse_iterator end = iter; + const auto end = iter; iter++; if (iter == mChildren.rend()) diff --git a/src/widgets/button.cpp b/src/widgets/button.cpp index aba2da1..2ecc327 100644 --- a/src/widgets/button.cpp +++ b/src/widgets/button.cpp @@ -224,6 +224,10 @@ namespace gcn void Button::mousePressed(MouseEvent& mouseEvent) { + if (mouseEvent.isConsumed()) + { + return; + } if (mouseEvent.getButton() == MouseEvent::Left) { mMousePressed = true; diff --git a/src/widgets/tab.cpp b/src/widgets/tab.cpp index 2d5223e..38509e5 100644 --- a/src/widgets/tab.cpp +++ b/src/widgets/tab.cpp @@ -71,7 +71,7 @@ namespace gcn Tab::Tab() : mTabbedArea(NULL), mHasMouse(false) { mLabel = new Label(); - mLabel->setPosition(4, 4); + mLabel->setPosition(6, 6); add(mLabel); setFrameSize(1); @@ -85,7 +85,7 @@ namespace gcn void Tab::adjustSize() { - setSize(mLabel->getWidth() + 8, mLabel->getHeight() + 8); + setSize(mLabel->getWidth() + 12, mLabel->getHeight() + 12); if (mTabbedArea != NULL) { @@ -159,12 +159,16 @@ namespace gcn graphics->setColor(baseColor); graphics->fillRectangle(Rectangle(0, 0, currentClipArea.width, currentClipArea.height)); - if (mTabbedArea != NULL && mTabbedArea->isFocused() && mTabbedArea->isTabSelected(this)) + if (mTabbedArea != NULL && mTabbedArea->isFocused() && mTabbedArea->isTabSelected(this) + // && mHasMouse) + && mTabbedArea->isTabActive()) { graphics->setColor(Color(0x000000)); graphics->drawRectangle( Rectangle(2, 2, currentClipArea.width - 4, currentClipArea.height - 4)); } + mLabel->setAlignment(Graphics::Center); + mLabel->_draw(graphics); graphics->popClipArea(); } diff --git a/src/widgets/tabbedarea.cpp b/src/widgets/tabbedarea.cpp index 84f79e9..457bd58 100644 --- a/src/widgets/tabbedarea.cpp +++ b/src/widgets/tabbedarea.cpp @@ -197,6 +197,11 @@ namespace gcn adjustTabPositions(); } + int TabbedArea::getNumberOfTabs() const + { + return mTabs.size(); + } + bool TabbedArea::isTabSelected(unsigned int index) const { if (index >= mTabs.size()) @@ -272,6 +277,11 @@ namespace gcn return mOpaque; } + bool TabbedArea::isTabActive() const + { + return tabActive; + } + void TabbedArea::draw(Graphics *graphics) { const Color& faceColor = getBaseColor(); @@ -313,7 +323,15 @@ namespace gcn mTabContainer->getHeight()); } - //drawChildren(graphics); + // Draw the widget from a select tab. + for (const auto& p : mTabs) + { + p.first->_draw(graphics); + if (p.first == mSelectedTab) + { + p.second->_draw(graphics); + } + } } void TabbedArea::adjustSize() @@ -351,8 +369,11 @@ namespace gcn Tab* tab = mTabs[i].first; tab->setPosition(x, maxTabHeight - tab->getHeight()); - x += tab->getWidth(); + + Widget* widget = mTabs[i].second; + widget->setX(mWidgetContainer->getX()); + widget->setY(mWidgetContainer->getY()); } } @@ -461,6 +482,17 @@ namespace gcn if (tab != NULL) { setSelectedTab(tab); + tabActive = true; + mouseEvent.consume(); + } + else + { + widget = mWidgetContainer->getWidgetAt(mouseEvent.getX(), mouseEvent.getY()); + if (widget == NULL) + { + mouseEvent.consume(); + } + tabActive = false; } } @@ -475,10 +507,7 @@ namespace gcn void TabbedArea::death(const Event& event) { - Widget* source = event.getSource(); - Tab* tab = dynamic_cast(source); - - if (tab != NULL) + if (Tab* tab = dynamic_cast(event.getSource())) { removeTab(tab); }