diff --git a/changes.diff b/changes.diff new file mode 100644 index 0000000..bf6467d --- /dev/null +++ b/changes.diff @@ -0,0 +1,498 @@ +diff --git a/src/client/gui/components/GuiElementContainer.cpp b/src/client/gui/components/GuiElementContainer.cpp +index 9cfbb09..4fdaf22 100755 +--- a/src/client/gui/components/GuiElementContainer.cpp ++++ b/src/client/gui/components/GuiElementContainer.cpp +@@ -35,6 +35,17 @@ void GuiElementContainer::removeChild( GuiElement* element ) { + children.erase(it); + } + ++bool GuiElementContainer::containsPointInChildren(int x, int y) const { ++ for (std::vector::const_iterator it = children.begin(); it != children.end(); ++it) { ++ GuiElement* child = *it; ++ if (child == NULL || !child->visible) continue; ++ if (child->pointInside(x, y)) return true; ++ const GuiElementContainer* container = dynamic_cast(child); ++ if (container != NULL && container->containsPointInChildren(x, y)) return true; ++ } ++ return false; ++} ++ + void GuiElementContainer::tick( Minecraft* minecraft ) { + for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { + (*it)->tick(minecraft); +diff --git a/src/client/gui/components/GuiElementContainer.h b/src/client/gui/components/GuiElementContainer.h +index d20f9d3..06df761 100755 +--- a/src/client/gui/components/GuiElementContainer.h ++++ b/src/client/gui/components/GuiElementContainer.h +@@ -5,16 +5,17 @@ + class Tesselator; + class Minecraft; + +-class GuiElementContainer : public GuiElement { +-public: +- GuiElementContainer(bool active=false, bool visible=true, int x = 0, int y = 0, int width=24, int height=24); +- virtual ~GuiElementContainer(); +- virtual void render(Minecraft* minecraft, int xm, int ym); +- virtual void setupPositions(); +- virtual void addChild(GuiElement* element); +- virtual void removeChild(GuiElement* element); +- +- virtual void tick( Minecraft* minecraft ); ++class GuiElementContainer : public GuiElement { ++public: ++ GuiElementContainer(bool active=false, bool visible=true, int x = 0, int y = 0, int width=24, int height=24); ++ virtual ~GuiElementContainer(); ++ virtual void render(Minecraft* minecraft, int xm, int ym); ++ virtual void setupPositions(); ++ virtual void addChild(GuiElement* element); ++ virtual void removeChild(GuiElement* element); ++ bool containsPointInChildren(int x, int y) const; ++ ++ virtual void tick( Minecraft* minecraft ); + + virtual void mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ); + virtual void mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ); +diff --git a/src/client/gui/components/OptionsGroup.cpp b/src/client/gui/components/OptionsGroup.cpp +index 54212d5..61695bb 100755 +--- a/src/client/gui/components/OptionsGroup.cpp ++++ b/src/client/gui/components/OptionsGroup.cpp +@@ -1,115 +1,230 @@ +-#include "OptionsGroup.h" +-#include "../../Minecraft.h" +-#include "ImageButton.h" +-#include "OptionsItem.h" +-#include "Slider.h" +-#include "../../../locale/I18n.h" +-#include "TextOption.h" +-#include "KeyOption.h" +- +-OptionsGroup::OptionsGroup( std::string labelID ) { +- label = I18n::get(labelID); +-} +- +-void OptionsGroup::setupPositions() { +- // First we write the header and then we add the items +- int curY = y + 18; +- for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { +- (*it)->width = width - 5; +- +- (*it)->y = curY; +- (*it)->x = x + 10; +- (*it)->setupPositions(); +- curY += (*it)->height + 3; +- } +- height = curY; +-} +- +-void OptionsGroup::render( Minecraft* minecraft, int xm, int ym ) { +- float padX = 10.0f; +- float padY = 5.0f; +- +- minecraft->font->draw(label, (float)x + padX, (float)y + padY, 0xffffffff, false); +- +- super::render(minecraft, xm, ym); +-} +- +-OptionsGroup& OptionsGroup::addOptionItem(OptionId optId, Minecraft* minecraft ) { +- auto option = minecraft->options.getOpt(optId); +- +- if (option == nullptr) return *this; +- +- // TODO: do a options key class to check it faster via dynamic_cast +- if (option->getStringId().find("options.key") != std::string::npos) createKey(optId, minecraft); +- else if (dynamic_cast(option)) createToggle(optId, minecraft); +- else if (dynamic_cast(option)) createProgressSlider(optId, minecraft); +- else if (dynamic_cast(option)) createStepSlider(optId, minecraft); +- else if (dynamic_cast(option)) createTextbox(optId, minecraft); +- +- return *this; +-} +- +-// TODO: wrap this copypaste shit into templates +- +-void OptionsGroup::createToggle(OptionId optId, Minecraft* minecraft ) { +- ImageDef def; +- +- def.setSrc(IntRectangle(160, 206, 39, 20)); +- def.name = "gui/touchgui.png"; +- def.width = 39 * 0.7f; +- def.height = 20 * 0.7f; +- +- OptionButton* element = new OptionButton(optId); +- element->setImageDef(def, true); +- element->updateImage(&minecraft->options); +- +- std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); +- +- OptionsItem* item = new OptionsItem(optId, itemLabel, element); +- +- addChild(item); +- setupPositions(); +-} +- +-void OptionsGroup::createProgressSlider(OptionId optId, Minecraft* minecraft ) { +- Slider* element = new SliderFloat(minecraft, optId); +- element->width = 100; +- element->height = 20; +- +- std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); +- OptionsItem* item = new OptionsItem(optId, itemLabel, element); +- addChild(item); +- setupPositions(); +-} +- +-void OptionsGroup::createStepSlider(OptionId optId, Minecraft* minecraft ) { +- Slider* element = new SliderInt(minecraft, optId); +- element->width = 100; +- element->height = 20; +- std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); +- OptionsItem* item = new OptionsItem(optId, itemLabel, element); +- addChild(item); +- setupPositions(); +-} +- +-void OptionsGroup::createTextbox(OptionId optId, Minecraft* minecraft) { +- TextBox* element = new TextOption(minecraft, optId); +- element->width = 100; +- element->height = 20; +- +- std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); +- OptionsItem* item = new OptionsItem(optId, itemLabel, element); +- addChild(item); +- setupPositions(); +-} +- +-void OptionsGroup::createKey(OptionId optId, Minecraft* minecraft) { +- KeyOption* element = new KeyOption(minecraft, optId); +- element->width = 50; +- element->height = 20; +- +- std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); +- OptionsItem* item = new OptionsItem(optId, itemLabel, element); +- addChild(item); +- setupPositions(); +-} +\ No newline at end of file ++#include "OptionsGroup.h" ++#include "../../Minecraft.h" ++#include "ImageButton.h" ++#include "OptionsItem.h" ++#include "Slider.h" ++#include "../../../locale/I18n.h" ++#include "TextOption.h" ++#include "KeyOption.h" ++#include ++#include "../Gui.h" ++#include "../Screen.h" ++#include "../../../platform/input/Mouse.h" ++#include "../../../util/Mth.h" ++ ++OptionsGroup::OptionsGroup( std::string labelID ) ++: contentHeight(0), ++ scrollOffsetY(0.0f), ++ maxScrollOffsetY(0.0f), ++ trackingScrollGesture(false), ++ scrollingGesture(false), ++ touchDispatched(false), ++ dragStartX(0), ++ dragStartY(0), ++ lastDragY(0), ++ touchStartX(0), ++ touchStartY(0) { ++ label = I18n::get(labelID); ++} ++ ++void OptionsGroup::setupPositions() { ++ const int labelHeight = 18; ++ const int bottomPadding = 36; ++ const float requestedScroll = scrollOffsetY; ++ const int scrollOffset = (int)requestedScroll; ++ int curY = y + labelHeight - scrollOffset; ++ const int contentStartY = y + labelHeight; ++ ++ // First we write the header and then we add the items ++ for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { ++ (*it)->width = width - 5; ++ ++ (*it)->y = curY; ++ (*it)->x = x + 10; ++ (*it)->setupPositions(); ++ curY += (*it)->height + 3; ++ } ++ curY += bottomPadding; ++ contentHeight = std::max(0, curY - contentStartY + scrollOffset); ++ maxScrollOffsetY = std::max(0, contentHeight - (height - labelHeight)); ++ const float clampedScroll = Mth::clamp(requestedScroll, 0.0f, maxScrollOffsetY); ++ if (clampedScroll != requestedScroll) { ++ scrollOffsetY = clampedScroll; ++ setupPositions(); ++ } ++} ++ ++void OptionsGroup::render( Minecraft* minecraft, int xm, int ym ) { ++ float padX = 10.0f; ++ float padY = 5.0f; ++ const int labelHeight = 18; ++ ++ minecraft->font->draw(label, (float)x + padX, (float)y + padY, 0xffffffff, false); ++ ++ glEnable2(GL_SCISSOR_TEST); ++ glScissor( ++ Gui::GuiScale * x, ++ minecraft->height - Gui::GuiScale * (y + height), ++ Gui::GuiScale * width, ++ Gui::GuiScale * (height - labelHeight) ++ ); ++ ++ super::render(minecraft, xm, ym); ++ glDisable2(GL_SCISSOR_TEST); ++} ++ ++void OptionsGroup::tick(Minecraft* minecraft) { ++ int xm = Mouse::getX(); ++ int ym = Mouse::getY(); ++ if (minecraft->screen != NULL) { ++ minecraft->screen->toGUICoordinate(xm, ym); ++ } ++ ++ bool leftDown = Mouse::isButtonDown(MouseAction::ACTION_LEFT); ++ ++ if (trackingScrollGesture && leftDown) { ++ int dy = ym - lastDragY; ++ int dx = xm - dragStartX; ++ if (!scrollingGesture) { ++ int totalDx = xm - dragStartX; ++ int totalDy = ym - dragStartY; ++ if (std::abs(totalDx) >= ScrollStartThreshold || std::abs(totalDy) >= ScrollStartThreshold) { ++ if (std::abs(totalDy) >= std::abs(totalDx)) { ++ scrollingGesture = true; ++ } else if (!touchDispatched) { ++ super::mouseClicked(minecraft, touchStartX, touchStartY, MouseAction::ACTION_LEFT); ++ touchDispatched = true; ++ } ++ } ++ } ++ if (scrollingGesture && dy != 0) { ++ scrollByPixels((float)dy); ++ } ++ lastDragY = ym; ++ } ++ super::tick(minecraft); ++} ++ ++void OptionsGroup::mouseClicked(Minecraft* minecraft, int x, int y, int buttonNum) { ++ trackingScrollGesture = false; ++ scrollingGesture = false; ++ touchDispatched = false; ++ ++ if (buttonNum == MouseAction::ACTION_LEFT && pointInside(x, y)) { ++ trackingScrollGesture = true; ++ dragStartX = x; ++ dragStartY = y; ++ lastDragY = y; ++ touchStartX = x; ++ touchStartY = y; ++ return; ++ } ++ ++ super::mouseClicked(minecraft, x, y, buttonNum); ++} ++ ++void OptionsGroup::mouseReleased(Minecraft* minecraft, int x, int y, int buttonNum) { ++ bool wasScrolling = scrollingGesture; ++ bool wasTracking = trackingScrollGesture; ++ trackingScrollGesture = false; ++ scrollingGesture = false; ++ if (buttonNum == MouseAction::ACTION_LEFT && wasTracking && !touchDispatched && pointInside(touchStartX, touchStartY)) { ++ super::mouseClicked(minecraft, touchStartX, touchStartY, buttonNum); ++ touchDispatched = true; ++ } ++ ++ if (!wasScrolling) { ++ super::mouseReleased(minecraft, x, y, buttonNum); ++ } ++} ++ ++void OptionsGroup::scrollByPixels(float deltaY) { ++ if (deltaY == 0.0f || maxScrollOffsetY <= 0.0f) return; ++ ++ scrollOffsetY = Mth::clamp(scrollOffsetY - deltaY, 0.0f, maxScrollOffsetY); ++ setupPositions(); ++} ++ ++bool OptionsGroup::isScrollingGestureActive() const { ++ return trackingScrollGesture || scrollingGesture; ++} ++ ++OptionsGroup& OptionsGroup::addOptionItem(OptionId optId, Minecraft* minecraft ) { ++ auto option = minecraft->options.getOpt(optId); ++ ++ if (option == nullptr) return *this; ++ ++ // TODO: do a options key class to check it faster via dynamic_cast ++ if (option->getStringId().find("options.key") != std::string::npos) createKey(optId, minecraft); ++ else if (dynamic_cast(option)) createToggle(optId, minecraft); ++ else if (dynamic_cast(option)) createProgressSlider(optId, minecraft); ++ else if (dynamic_cast(option)) createStepSlider(optId, minecraft); ++ else if (dynamic_cast(option)) createTextbox(optId, minecraft); ++ ++ return *this; ++} ++ ++// TODO: wrap this copypaste shit into templates ++ ++void OptionsGroup::createToggle(OptionId optId, Minecraft* minecraft ) { ++ ImageDef def; ++ ++ def.setSrc(IntRectangle(160, 206, 39, 20)); ++ def.name = "gui/touchgui.png"; ++ def.width = 39 * 0.7f; ++ def.height = 20 * 0.7f; ++ ++ OptionButton* element = new OptionButton(optId); ++ element->setImageDef(def, true); ++ element->updateImage(&minecraft->options); ++ ++ std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); ++ ++ OptionsItem* item = new OptionsItem(optId, itemLabel, element); ++ ++ addChild(item); ++ setupPositions(); ++} ++ ++void OptionsGroup::createProgressSlider(OptionId optId, Minecraft* minecraft ) { ++ Slider* element = new SliderFloat(minecraft, optId); ++ element->width = 100; ++ element->height = 20; ++ ++ std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); ++ OptionsItem* item = new OptionsItem(optId, itemLabel, element); ++ addChild(item); ++ setupPositions(); ++} ++ ++void OptionsGroup::createStepSlider(OptionId optId, Minecraft* minecraft ) { ++ Slider* element = new SliderInt(minecraft, optId); ++ element->width = 100; ++ element->height = 20; ++ std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); ++ OptionsItem* item = new OptionsItem(optId, itemLabel, element); ++ addChild(item); ++ setupPositions(); ++} ++ ++void OptionsGroup::createTextbox(OptionId optId, Minecraft* minecraft) { ++ TextBox* element = new TextOption(minecraft, optId); ++ element->width = 100; ++ element->height = 20; ++ ++ std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); ++ OptionsItem* item = new OptionsItem(optId, itemLabel, element); ++ addChild(item); ++ setupPositions(); ++} ++ ++void OptionsGroup::createKey(OptionId optId, Minecraft* minecraft) { ++ KeyOption* element = new KeyOption(minecraft, optId); ++ element->width = 50; ++ element->height = 20; ++ ++ std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); ++ OptionsItem* item = new OptionsItem(optId, itemLabel, element); ++ addChild(item); ++ setupPositions(); ++} +diff --git a/src/client/gui/components/OptionsGroup.h b/src/client/gui/components/OptionsGroup.h +index 24d28bd..ac90e3d 100755 +--- a/src/client/gui/components/OptionsGroup.h ++++ b/src/client/gui/components/OptionsGroup.h +@@ -11,22 +11,39 @@ + class Font; + class Minecraft; + +-class OptionsGroup: public GuiElementContainer { +- typedef GuiElementContainer super; +-public: +- OptionsGroup(std::string labelID); +- virtual void setupPositions(); +- virtual void render(Minecraft* minecraft, int xm, int ym); +- OptionsGroup& addOptionItem(OptionId optId, Minecraft* minecraft); +-protected: ++class OptionsGroup: public GuiElementContainer { ++ typedef GuiElementContainer super; ++public: ++ OptionsGroup(std::string labelID); ++ virtual void setupPositions(); ++ virtual void render(Minecraft* minecraft, int xm, int ym); ++ virtual void tick(Minecraft* minecraft); ++ virtual void mouseClicked(Minecraft* minecraft, int x, int y, int buttonNum); ++ virtual void mouseReleased(Minecraft* minecraft, int x, int y, int buttonNum); ++ OptionsGroup& addOptionItem(OptionId optId, Minecraft* minecraft); ++ void scrollByPixels(float deltaY); ++ bool isScrollingGestureActive() const; ++protected: + + void createToggle(OptionId optId, Minecraft* minecraft); + void createProgressSlider(OptionId optId, Minecraft* minecraft); + void createStepSlider(OptionId optId, Minecraft* minecraft); + void createTextbox(OptionId optId, Minecraft* minecraft); +- void createKey(OptionId optId, Minecraft* minecraft); +- +- std::string label; +-}; ++ void createKey(OptionId optId, Minecraft* minecraft); ++ ++ std::string label; ++ int contentHeight; ++ float scrollOffsetY; ++ float maxScrollOffsetY; ++ bool trackingScrollGesture; ++ bool scrollingGesture; ++ bool touchDispatched; ++ int dragStartX; ++ int dragStartY; ++ int lastDragY; ++ int touchStartX; ++ int touchStartY; ++ static const int ScrollStartThreshold = 5; ++}; + + #endif /*NET_MINECRAFT_CLIENT_GUI_COMPONENTS__OptionsGroup_H__*/ +diff --git a/src/client/gui/screens/OptionsScreen.cpp b/src/client/gui/screens/OptionsScreen.cpp +index 88fbb63..b58f3fe 100755 +--- a/src/client/gui/screens/OptionsScreen.cpp ++++ b/src/client/gui/screens/OptionsScreen.cpp +@@ -121,6 +121,7 @@ void OptionsScreen::setupPositions() { + (*it)->x = categoryButtons[0]->width; + (*it)->y = bHeader->height; + (*it)->width = width - categoryButtons[0]->width; ++ (*it)->height = height - bHeader->height; + + (*it)->setupPositions(); + } +@@ -253,6 +254,12 @@ void OptionsScreen::mouseReleased(int x, int y, int buttonNum) { + super::mouseReleased(x, y, buttonNum); + } + ++void OptionsScreen::mouseWheel(int dx, int dy, int xm, int ym) { ++ if (currentOptionsGroup != NULL && currentOptionsGroup->pointInside(xm, ym) && dy != 0) { ++ currentOptionsGroup->scrollByPixels((float)dy * 18.0f); ++ } ++} ++ + void OptionsScreen::keyPressed(int eventKey) { + if (currentOptionsGroup != NULL) + currentOptionsGroup->keyPressed(minecraft, eventKey); +diff --git a/src/client/gui/screens/OptionsScreen.h b/src/client/gui/screens/OptionsScreen.h +index b02c7b8..dd1e73e 100755 +--- a/src/client/gui/screens/OptionsScreen.h ++++ b/src/client/gui/screens/OptionsScreen.h +@@ -27,6 +27,7 @@ public: + + virtual void mouseClicked(int x, int y, int buttonNum); + virtual void mouseReleased(int x, int y, int buttonNum); ++ virtual void mouseWheel(int dx, int dy, int xm, int ym); + virtual void keyPressed(int eventKey); + virtual void charPressed(char inputChar); + diff --git a/data/images/gui/gui_blocks.png b/data/images/gui/gui_blocks.png index fa4df26..9fa2d85 100755 Binary files a/data/images/gui/gui_blocks.png and b/data/images/gui/gui_blocks.png differ diff --git a/data/images/terrain.png b/data/images/terrain.png index 7991d0a..39b7119 100755 Binary files a/data/images/terrain.png and b/data/images/terrain.png differ diff --git a/src/client/gui/components/GuiElementContainer.cpp b/src/client/gui/components/GuiElementContainer.cpp index 9cfbb09..4fdaf22 100755 --- a/src/client/gui/components/GuiElementContainer.cpp +++ b/src/client/gui/components/GuiElementContainer.cpp @@ -35,6 +35,17 @@ void GuiElementContainer::removeChild( GuiElement* element ) { children.erase(it); } +bool GuiElementContainer::containsPointInChildren(int x, int y) const { + for (std::vector::const_iterator it = children.begin(); it != children.end(); ++it) { + GuiElement* child = *it; + if (child == NULL || !child->visible) continue; + if (child->pointInside(x, y)) return true; + const GuiElementContainer* container = dynamic_cast(child); + if (container != NULL && container->containsPointInChildren(x, y)) return true; + } + return false; +} + void GuiElementContainer::tick( Minecraft* minecraft ) { for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { (*it)->tick(minecraft); diff --git a/src/client/gui/components/GuiElementContainer.h b/src/client/gui/components/GuiElementContainer.h index d20f9d3..06df761 100755 --- a/src/client/gui/components/GuiElementContainer.h +++ b/src/client/gui/components/GuiElementContainer.h @@ -5,16 +5,17 @@ class Tesselator; class Minecraft; -class GuiElementContainer : public GuiElement { -public: - GuiElementContainer(bool active=false, bool visible=true, int x = 0, int y = 0, int width=24, int height=24); - virtual ~GuiElementContainer(); - virtual void render(Minecraft* minecraft, int xm, int ym); - virtual void setupPositions(); - virtual void addChild(GuiElement* element); - virtual void removeChild(GuiElement* element); - - virtual void tick( Minecraft* minecraft ); +class GuiElementContainer : public GuiElement { +public: + GuiElementContainer(bool active=false, bool visible=true, int x = 0, int y = 0, int width=24, int height=24); + virtual ~GuiElementContainer(); + virtual void render(Minecraft* minecraft, int xm, int ym); + virtual void setupPositions(); + virtual void addChild(GuiElement* element); + virtual void removeChild(GuiElement* element); + bool containsPointInChildren(int x, int y) const; + + virtual void tick( Minecraft* minecraft ); virtual void mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ); virtual void mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ); diff --git a/src/client/gui/components/OptionsGroup.cpp b/src/client/gui/components/OptionsGroup.cpp index 54212d5..b9c7264 100755 --- a/src/client/gui/components/OptionsGroup.cpp +++ b/src/client/gui/components/OptionsGroup.cpp @@ -6,14 +6,36 @@ #include "../../../locale/I18n.h" #include "TextOption.h" #include "KeyOption.h" +#include +#include "../Gui.h" +#include "../Screen.h" +#include "../../../platform/input/Mouse.h" +#include "../../../util/Mth.h" -OptionsGroup::OptionsGroup( std::string labelID ) { +OptionsGroup::OptionsGroup( std::string labelID ) +: contentHeight(0), + scrollOffsetY(0.0f), + maxScrollOffsetY(0.0f), + trackingScrollGesture(false), + scrollingGesture(false), + touchDispatched(false), + dragStartX(0), + dragStartY(0), + lastDragY(0), + touchStartX(0), + touchStartY(0) { label = I18n::get(labelID); } void OptionsGroup::setupPositions() { + const int labelHeight = 18; + const int bottomPadding = 36; + const float requestedScroll = scrollOffsetY; + const int scrollOffset = (int)requestedScroll; + int curY = y + labelHeight - scrollOffset; + const int contentStartY = y + labelHeight; + // First we write the header and then we add the items - int curY = y + 18; for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { (*it)->width = width - 5; @@ -22,16 +44,109 @@ void OptionsGroup::setupPositions() { (*it)->setupPositions(); curY += (*it)->height + 3; } - height = curY; + curY += bottomPadding; + contentHeight = std::max(0, curY - contentStartY + scrollOffset); + maxScrollOffsetY = std::max(0, contentHeight - (height - labelHeight)); + const float clampedScroll = Mth::clamp(requestedScroll, 0.0f, maxScrollOffsetY); + if (clampedScroll != requestedScroll) { + scrollOffsetY = clampedScroll; + setupPositions(); + } } void OptionsGroup::render( Minecraft* minecraft, int xm, int ym ) { float padX = 10.0f; float padY = 5.0f; + const int labelHeight = 18; minecraft->font->draw(label, (float)x + padX, (float)y + padY, 0xffffffff, false); + glEnable2(GL_SCISSOR_TEST); + glScissor( + Gui::GuiScale * x, + minecraft->height - Gui::GuiScale * (y + height), + Gui::GuiScale * width, + Gui::GuiScale * (height - labelHeight) + ); + super::render(minecraft, xm, ym); + glDisable2(GL_SCISSOR_TEST); +} + +void OptionsGroup::tick(Minecraft* minecraft) { + int xm = Mouse::getX(); + int ym = Mouse::getY(); + if (minecraft->screen != NULL) { + minecraft->screen->toGUICoordinate(xm, ym); + } + + bool leftDown = Mouse::isButtonDown(MouseAction::ACTION_LEFT); + + if (trackingScrollGesture && leftDown) { + int dy = ym - lastDragY; + int dx = xm - dragStartX; + if (!scrollingGesture) { + int totalDx = xm - dragStartX; + int totalDy = ym - dragStartY; + if (std::abs(totalDx) >= ScrollStartThreshold || std::abs(totalDy) >= ScrollStartThreshold) { + if (std::abs(totalDy) >= std::abs(totalDx)) { + scrollingGesture = true; + } else if (!touchDispatched) { + super::mouseClicked(minecraft, touchStartX, touchStartY, MouseAction::ACTION_LEFT); + touchDispatched = true; + } + } + } + if (scrollingGesture && dy != 0) { + scrollByPixels((float)dy); + } + lastDragY = ym; + } + super::tick(minecraft); +} + +void OptionsGroup::mouseClicked(Minecraft* minecraft, int x, int y, int buttonNum) { + trackingScrollGesture = false; + scrollingGesture = false; + touchDispatched = false; + + if (buttonNum == MouseAction::ACTION_LEFT && pointInside(x, y)) { + trackingScrollGesture = true; + dragStartX = x; + dragStartY = y; + lastDragY = y; + touchStartX = x; + touchStartY = y; + return; + } + + super::mouseClicked(minecraft, x, y, buttonNum); +} + +void OptionsGroup::mouseReleased(Minecraft* minecraft, int x, int y, int buttonNum) { + bool wasScrolling = scrollingGesture; + bool wasTracking = trackingScrollGesture; + trackingScrollGesture = false; + scrollingGesture = false; + if (buttonNum == MouseAction::ACTION_LEFT && wasTracking && !touchDispatched && pointInside(touchStartX, touchStartY)) { + super::mouseClicked(minecraft, touchStartX, touchStartY, buttonNum); + touchDispatched = true; + } + + if (!wasScrolling) { + super::mouseReleased(minecraft, x, y, buttonNum); + } +} + +void OptionsGroup::scrollByPixels(float deltaY) { + if (deltaY == 0.0f || maxScrollOffsetY <= 0.0f) return; + + scrollOffsetY = Mth::clamp(scrollOffsetY - deltaY, 0.0f, maxScrollOffsetY); + setupPositions(); +} + +bool OptionsGroup::isScrollingGestureActive() const { + return trackingScrollGesture || scrollingGesture; } OptionsGroup& OptionsGroup::addOptionItem(OptionId optId, Minecraft* minecraft ) { @@ -112,4 +227,4 @@ void OptionsGroup::createKey(OptionId optId, Minecraft* minecraft) { OptionsItem* item = new OptionsItem(optId, itemLabel, element); addChild(item); setupPositions(); -} \ No newline at end of file +} diff --git a/src/client/gui/components/OptionsGroup.h b/src/client/gui/components/OptionsGroup.h index 24d28bd..ac90e3d 100755 --- a/src/client/gui/components/OptionsGroup.h +++ b/src/client/gui/components/OptionsGroup.h @@ -11,22 +11,39 @@ class Font; class Minecraft; -class OptionsGroup: public GuiElementContainer { - typedef GuiElementContainer super; -public: - OptionsGroup(std::string labelID); - virtual void setupPositions(); - virtual void render(Minecraft* minecraft, int xm, int ym); - OptionsGroup& addOptionItem(OptionId optId, Minecraft* minecraft); -protected: +class OptionsGroup: public GuiElementContainer { + typedef GuiElementContainer super; +public: + OptionsGroup(std::string labelID); + virtual void setupPositions(); + virtual void render(Minecraft* minecraft, int xm, int ym); + virtual void tick(Minecraft* minecraft); + virtual void mouseClicked(Minecraft* minecraft, int x, int y, int buttonNum); + virtual void mouseReleased(Minecraft* minecraft, int x, int y, int buttonNum); + OptionsGroup& addOptionItem(OptionId optId, Minecraft* minecraft); + void scrollByPixels(float deltaY); + bool isScrollingGestureActive() const; +protected: void createToggle(OptionId optId, Minecraft* minecraft); void createProgressSlider(OptionId optId, Minecraft* minecraft); void createStepSlider(OptionId optId, Minecraft* minecraft); void createTextbox(OptionId optId, Minecraft* minecraft); - void createKey(OptionId optId, Minecraft* minecraft); - - std::string label; -}; + void createKey(OptionId optId, Minecraft* minecraft); + + std::string label; + int contentHeight; + float scrollOffsetY; + float maxScrollOffsetY; + bool trackingScrollGesture; + bool scrollingGesture; + bool touchDispatched; + int dragStartX; + int dragStartY; + int lastDragY; + int touchStartX; + int touchStartY; + static const int ScrollStartThreshold = 5; +}; #endif /*NET_MINECRAFT_CLIENT_GUI_COMPONENTS__OptionsGroup_H__*/ diff --git a/src/client/gui/screens/OptionsScreen.cpp b/src/client/gui/screens/OptionsScreen.cpp index 77d5a5f..68a2875 100755 --- a/src/client/gui/screens/OptionsScreen.cpp +++ b/src/client/gui/screens/OptionsScreen.cpp @@ -121,6 +121,7 @@ void OptionsScreen::setupPositions() { (*it)->x = categoryButtons[0]->width; (*it)->y = bHeader->height; (*it)->width = width - categoryButtons[0]->width; + (*it)->height = height - bHeader->height; (*it)->setupPositions(); } @@ -258,6 +259,12 @@ void OptionsScreen::mouseReleased(int x, int y, int buttonNum) { super::mouseReleased(x, y, buttonNum); } +void OptionsScreen::mouseWheel(int dx, int dy, int xm, int ym) { + if (currentOptionsGroup != NULL && currentOptionsGroup->pointInside(xm, ym) && dy != 0) { + currentOptionsGroup->scrollByPixels((float)dy * 18.0f); + } +} + void OptionsScreen::keyPressed(int eventKey) { if (currentOptionsGroup != NULL) currentOptionsGroup->keyPressed(minecraft, eventKey); diff --git a/src/client/gui/screens/OptionsScreen.h b/src/client/gui/screens/OptionsScreen.h index b02c7b8..dd1e73e 100755 --- a/src/client/gui/screens/OptionsScreen.h +++ b/src/client/gui/screens/OptionsScreen.h @@ -27,6 +27,7 @@ public: virtual void mouseClicked(int x, int y, int buttonNum); virtual void mouseReleased(int x, int y, int buttonNum); + virtual void mouseWheel(int dx, int dy, int xm, int ym); virtual void keyPressed(int eventKey); virtual void charPressed(char inputChar); diff --git a/src/client/renderer/entity/ItemRenderer.cpp b/src/client/renderer/entity/ItemRenderer.cpp index d103fcc..c4e9de1 100755 --- a/src/client/renderer/entity/ItemRenderer.cpp +++ b/src/client/renderer/entity/ItemRenderer.cpp @@ -130,12 +130,13 @@ static const signed short _18[] = {79, 80, 81, -1, 79, 80, 81, -1, 79, 80, 81, - static const signed short _24[] = {11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; static const signed short _35[] = {52, 59, 58, 57, 56, 55, 54, 53, 67, 66, 65, 64, 63, 62, 61, 60}; static const signed short _44[] = {28, 32, 30, 29, 31, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; +static const signed short _31[] = {37, 82, -1, 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; static const signed short _98[] = {1, 2, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; static const signed short _155[] = {34, 36, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; static const signed short _263[] = {230, 151, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; static const signed short _351[] = {-1, 152, 154, -1, 193, 215, 216, -1, -1, 217, 218, 219, 220, 221, 222, 144}; -static const signed short _mapper[] = {-1, 7, 9, 8, 0, 5, -2, -1, -1, -1, -1, -1, 14, 15, 39, 38, 37, -2, -2, -1, 49, 41, 46, -1, -2, -1, -1, -1, -1, -1, 235, -1, -1, -1, -1, -2, -1, 134, 135, 136, 137, 43, 44, -1, -2, 6, 76, 71, 4, 47, 129, -1, -1, 22, 74, -1, 40, 45, 72, -1, -1, 75, -1, -1, -1, 128, -1, 21, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, 48, 77, 10, 236, -1, 69, -1, 20, -1, 50, -1, -1, -1, -1, -1, -1, 68, -1, -2, -1, -1, -1, 130, 78, -1, -1, -1, 70, 23, 25, -1, -1, 19, -1, 26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, -1, 51, -1, -1, -1, -1, -1, 82, -1, -1, 174, 173, 175, 231, 234, 147, 190, -2, 153, 150, 149, 146, 185, 166, 164, 167, 186, 170, 169, 171, 187, 177, 176, 178, 165, 195, 194, 188, 181, 180, 182, 189, 191, 228, 168, 172, 145, 179, 183, 142, 233, 232, 198, 200, 201, 202, -1, -1, -1, -1, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 192, 156, 157, 133, -1, 148, 131, -1, -1, -1, -1, -1, -1, -1, 226, -1, 199, -1, 159, 158, 138, 224, 225, -1, -1, -1, -1, -1, -1, -1, 227, -1, -1, -2, 223, 229, -1, 132, -1, -1, -1, 184, 196, -1, 143, 160, 161, 162, 163, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 155, 197}; +static const signed short _mapper[] = {-1, 7, 9, 8, 0, 5, -2, -1, -1, -1, -1, -1, 14, 15, 39, 38, 37, -2, -2, -1, 49, 41, 46, -1, -2, -1, -1, -1, -1, -1, 235, -2, -1, -1, -1, -2, -1, 134, 135, 136, 137, 43, 44, -1, -2, 6, 76, 71, 4, 47, 129, -1, -1, 22, 74, -1, 40, 45, 72, -1, -1, 75, -1, -1, -1, 128, -1, 21, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, 48, 77, 10, 236, -1, 69, -1, 20, -1, 50, -1, -1, -1, -1, -1, -1, 68, -1, -2, -1, -1, -1, 130, 78, -1, -1, -1, 70, 23, 25, -1, -1, 19, -1, 26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, -1, 51, -1, -1, -1, -1, -1, 82, -1, -1, 174, 173, 175, 231, 234, 147, 190, -2, 153, 150, 149, 146, 185, 166, 164, 167, 186, 170, 169, 171, 187, 177, 176, 178, 165, 195, 194, 188, 181, 180, 182, 189, 191, 228, 168, 172, 145, 179, 183, 142, 233, 232, 198, 200, 201, 202, -1, -1, -1, -1, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 192, 156, 157, 133, -1, 148, 131, -1, -1, -1, -1, -1, -1, -1, 226, -1, 199, -1, 159, 158, 138, 224, 225, -1, -1, -1, -1, -1, -1, -1, 227, -1, -1, -2, 223, 229, -1, 132, -1, -1, -1, 184, 196, -1, 143, 160, 161, 162, 163, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 155, 197}; #define IRMAPCASE(x) case x: return _##x [item->getAuxValue() & 15] @@ -153,6 +154,7 @@ int ItemRenderer::getAtlasPos(const ItemInstance* item) { IRMAPCASE(17); IRMAPCASE(18); IRMAPCASE(24); + IRMAPCASE(31); IRMAPCASE(35); IRMAPCASE(44); IRMAPCASE(98); diff --git a/src/world/entity/player/Inventory.cpp b/src/world/entity/player/Inventory.cpp index 480627b..19ff6ad 100755 --- a/src/world/entity/player/Inventory.cpp +++ b/src/world/entity/player/Inventory.cpp @@ -1,11 +1,12 @@ #include "Inventory.h" #include "../../level/material/Material.h" -#include "../../level/tile/QuartzBlockTile.h" -#include "../../level/tile/TreeTile.h" -#include "../../level/tile/StoneSlabTile.h" -#include "../../item/DyePowderItem.h" -#include "../../item/crafting/Recipe.h" -#include "../../item/CoalItem.h" +#include "../../level/tile/QuartzBlockTile.h" +#include "../../level/tile/TreeTile.h" +#include "../../level/tile/StoneSlabTile.h" +#include "../../level/tile/TallGrass.h" +#include "../../item/DyePowderItem.h" +#include "../../item/crafting/Recipe.h" +#include "../../item/CoalItem.h" #include "../../level/tile/SandStoneTile.h" Inventory::Inventory( Player* player, bool creativeMode ) @@ -80,10 +81,10 @@ void Inventory::setupDefault() { addItem(new ItemInstance(Tile::chest)); addItem(new ItemInstance(Tile::furnace)); - addItem(new ItemInstance(((Tile*)Tile::flower))); - addItem(new ItemInstance(Tile::cactus)); - - // + addItem(new ItemInstance(((Tile*)Tile::flower))); + addItem(new ItemInstance(Tile::cactus)); + + // // Those below are inactive due to demo // addItem(new ItemInstance(Item::sword_stone)); @@ -227,9 +228,10 @@ void Inventory::setupDefault() { addItem(new ItemInstance(Tile::furnace)); addItem(new ItemInstance(Tile::tnt)); - addItem(new ItemInstance(((Tile*)Tile::flower))); - addItem(new ItemInstance(((Tile*)Tile::rose))); - addItem(new ItemInstance(((Tile*)Tile::mushroom1))); + addItem(new ItemInstance(((Tile*)Tile::flower))); + addItem(new ItemInstance(((Tile*)Tile::rose))); + addItem(new ItemInstance(Tile::tallgrass, 1, TallGrass::TALL_GRASS)); + addItem(new ItemInstance(((Tile*)Tile::mushroom1))); addItem(new ItemInstance(((Tile*)Tile::mushroom2))); addItem(new ItemInstance(Tile::cactus)); addItem(new ItemInstance(Tile::melon)); diff --git a/src/world/level/tile/Tile.cpp b/src/world/level/tile/Tile.cpp index a5acf7a..ea6f6ea 100755 --- a/src/world/level/tile/Tile.cpp +++ b/src/world/level/tile/Tile.cpp @@ -281,13 +281,14 @@ void Tile::initTiles() { Item::items[stoneBrickSmooth->id] = (new AuxDataTileItem(stoneBrickSmooth->id - 256, stoneBrickSmooth))->setCategory(ItemCategory::Structures)->setDescriptionId("stonebricksmooth"); Item::items[stoneSlabHalf->id] = (new StoneSlabTileItem(stoneSlabHalf->id - 256))->setCategory(ItemCategory::Structures)->setDescriptionId("stoneSlab"); Item::items[sapling->id] = (new SaplingTileItem(sapling->id - 256))->setCategory(ItemCategory::Structures)->setDescriptionId("sapling"); - Item::items[leaves->id] = (new LeafTileItem(leaves->id - 256))->setCategory(ItemCategory::Decorations)->setDescriptionId("leaves"); - Item::items[sandStone->id] = (new AuxDataTileItem(sandStone->id - 256, sandStone))->setCategory(ItemCategory::Structures)->setDescriptionId("sandStone"); - - Item::items[quartzBlock->id] = (new AuxDataTileItem(quartzBlock->id - 256, quartzBlock))->setCategory(ItemCategory::Structures)->setDescriptionId("quartzBlock"); - - for (int i = 0; i < 256; i++) { - if (Tile::tiles[i] != NULL) { + Item::items[leaves->id] = (new LeafTileItem(leaves->id - 256))->setCategory(ItemCategory::Decorations)->setDescriptionId("leaves"); + Item::items[sandStone->id] = (new AuxDataTileItem(sandStone->id - 256, sandStone))->setCategory(ItemCategory::Structures)->setDescriptionId("sandStone"); + + Item::items[quartzBlock->id] = (new AuxDataTileItem(quartzBlock->id - 256, quartzBlock))->setCategory(ItemCategory::Structures)->setDescriptionId("quartzBlock"); + Item::items[tallgrass->id] = (new AuxDataTileItem(tallgrass->id - 256, tallgrass))->setCategory(ItemCategory::Decorations); + + for (int i = 0; i < 256; i++) { + if (Tile::tiles[i] != NULL) { if (Item::items[i] == NULL) { Item::items[i] = new TileItem(i - 256); Item::items[i]->category = Tile::tiles[i]->category;