mirror of
				https://github.com/RetroDECK/ES-DE.git
				synced 2025-04-10 19:15:13 +00:00 
			
		
		
		
	Move scrolling out of TextComponent and into a generic
ScrollableContainer.
This commit is contained in:
		
							parent
							
								
									df78b5352d
								
							
						
					
					
						commit
						ed384e057b
					
				|  | @ -135,6 +135,7 @@ set(ES_HEADERS | |||
|     ${CMAKE_CURRENT_SOURCE_DIR}/src/components/AnimationComponent.h | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ComponentListComponent.h | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.h | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ScrollableContainer.h | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/src/components/SliderComponent.h | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.h | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.h | ||||
|  | @ -175,6 +176,7 @@ set(ES_SOURCES | |||
|     ${CMAKE_CURRENT_SOURCE_DIR}/src/components/AnimationComponent.cpp | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ComponentListComponent.cpp | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ImageComponent.cpp | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/src/components/ScrollableContainer.cpp | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/src/components/SliderComponent.cpp | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/src/components/SwitchComponent.cpp | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.cpp | ||||
|  |  | |||
|  | @ -254,7 +254,8 @@ namespace Renderer { | |||
| 
 | ||||
| 	void sizeWrappedText(std::string text, int xLen, Font* font, int* xOut, int* yOut) | ||||
| 	{ | ||||
| 		*xOut = xLen; | ||||
| 		if(xOut != NULL) | ||||
| 			*xOut = xLen; | ||||
| 
 | ||||
| 		int y = 0; | ||||
| 
 | ||||
|  | @ -306,7 +307,8 @@ namespace Renderer { | |||
| 
 | ||||
| 		} | ||||
| 
 | ||||
| 		*yOut = y; | ||||
| 		if(yOut != NULL) | ||||
| 			*yOut = y; | ||||
| 	} | ||||
| 
 | ||||
| }; | ||||
|  |  | |||
|  | @ -25,13 +25,15 @@ GuiGameList::GuiGameList(Window* window) : GuiComponent(window), | |||
| 	mList(window, 0, 0, Renderer::getDefaultFont(Renderer::MEDIUM)), | ||||
| 	mScreenshot(window), | ||||
| 	mDescription(window),  | ||||
| 	mDescContainer(window),  | ||||
| 	mTransitionImage(window, 0, 0, "", Renderer::getScreenWidth(), Renderer::getScreenHeight(), true) | ||||
| { | ||||
| 	mImageAnimation.addChild(&mScreenshot); | ||||
| 	mDescContainer.addChild(&mDescription); | ||||
| 
 | ||||
| 	//scale delay with screen width (higher width = more text per line)
 | ||||
| 	//the scroll speed is automatically scaled by component size
 | ||||
| 	mDescription.setAutoScroll((int)(1500 + (Renderer::getScreenWidth() * 0.5)), 0.025f); | ||||
| 	mDescContainer.setAutoScroll((int)(1500 + (Renderer::getScreenWidth() * 0.5)), 0.025f); | ||||
| 
 | ||||
| 	mTransitionImage.setOffset(Renderer::getScreenWidth(), 0); | ||||
| 	mTransitionImage.setOrigin(0, 0); | ||||
|  | @ -104,7 +106,7 @@ void GuiGameList::render() | |||
| 			Renderer::drawRect((int)(Renderer::getScreenWidth() * mTheme->getFloat("listOffsetX")) - 4, Renderer::getDefaultFont(Renderer::LARGE)->getHeight() + 2, 8, Renderer::getScreenHeight(), 0x0000FFFF); | ||||
| 		 | ||||
| 		mScreenshot.render(); | ||||
| 		mDescription.render(); | ||||
| 		mDescContainer.render(); | ||||
| 	} | ||||
| 
 | ||||
| 	mList.render(); | ||||
|  | @ -290,8 +292,13 @@ void GuiGameList::updateDetailData() | |||
| 			mImageAnimation.fadeIn(35); | ||||
| 			mImageAnimation.move(imgOffset.x, imgOffset.y, 20); | ||||
| 
 | ||||
| 			mDescription.setOffset(Vector2i((int)(Renderer::getScreenWidth() * 0.03), getImagePos().y + mScreenshot.getSize().y + 12)); | ||||
| 			mDescription.setExtent(Vector2u((int)(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03)), Renderer::getScreenHeight() - mDescription.getOffset().y)); | ||||
| 			mDescContainer.setOffset(Vector2i((int)(Renderer::getScreenWidth() * 0.03), getImagePos().y + mScreenshot.getSize().y + 12)); | ||||
| 			mDescContainer.setSize(Vector2u((int)(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03)), Renderer::getScreenHeight() - mDescContainer.getOffset().y)); | ||||
| 			mDescContainer.setScrollPos(Vector2d(0, 0)); | ||||
| 			mDescContainer.resetAutoScrollTimer(); | ||||
| 
 | ||||
| 			mDescription.setOffset(0, 0); | ||||
| 			mDescription.setExtent(Vector2u((int)(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03)), 0)); | ||||
| 			mDescription.setText(((GameData*)mList.getSelectedObject())->getDescription()); | ||||
| 		}else{ | ||||
| 			mScreenshot.setImage(""); | ||||
|  | @ -340,7 +347,7 @@ void GuiGameList::update(int deltaTime) | |||
| 
 | ||||
| 	mList.update(deltaTime); | ||||
| 
 | ||||
| 	mDescription.update(deltaTime); | ||||
| 	mDescContainer.update(deltaTime); | ||||
| } | ||||
| 
 | ||||
| void GuiGameList::doTransition(int dir) | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ | |||
| #include "../SystemData.h" | ||||
| #include "../GameData.h" | ||||
| #include "../FolderData.h" | ||||
| #include "ScrollableContainer.h" | ||||
| 
 | ||||
| //This is where the magic happens - GuiGameList is the parent of almost every graphical element in ES at the moment.
 | ||||
| //It has a TextListComponent child that handles the game list, a ThemeComponent that handles the theming system, and an ImageComponent for game images.
 | ||||
|  | @ -53,6 +54,7 @@ private: | |||
| 	TextListComponent<FileData*> mList; | ||||
| 	ImageComponent mScreenshot; | ||||
| 	TextComponent mDescription; | ||||
| 	ScrollableContainer mDescContainer; | ||||
| 	AnimationComponent mImageAnimation; | ||||
| 	ThemeComponent* mTheme; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										111
									
								
								src/components/ScrollableContainer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								src/components/ScrollableContainer.cpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,111 @@ | |||
| #include "ScrollableContainer.h" | ||||
| #include "../Renderer.h" | ||||
| #include "../Log.h" | ||||
| 
 | ||||
| ScrollableContainer::ScrollableContainer(Window* window) : GuiComponent(window),  | ||||
| 	mAutoScrollDelay(0), mAutoScrollSpeed(0), mAutoScrollTimer(0) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void ScrollableContainer::render() | ||||
| { | ||||
| 	Renderer::pushClipRect(getGlobalOffset(), getSize()); | ||||
| 
 | ||||
| 	Vector2f translate = (Vector2f)mOffset - (Vector2f)mScrollPos; | ||||
| 
 | ||||
| 	Renderer::translatef(translate.x, translate.y); | ||||
| 	 | ||||
| 	Renderer::drawRect(0, 0, 800, 800, 0xFF0000FF); | ||||
| 
 | ||||
| 	GuiComponent::onRender(); | ||||
| 
 | ||||
| 	Renderer::translatef(-translate.x, -translate.y); | ||||
| 
 | ||||
| 	Renderer::popClipRect(); | ||||
| } | ||||
| 
 | ||||
| void ScrollableContainer::setAutoScroll(int delay, double speed) | ||||
| { | ||||
| 	mAutoScrollDelay = delay; | ||||
| 	mAutoScrollSpeed = speed; | ||||
| 	mAutoScrollTimer = 0; | ||||
| } | ||||
| 
 | ||||
| Vector2d ScrollableContainer::getScrollPos() const | ||||
| { | ||||
| 	return mScrollPos; | ||||
| } | ||||
| 
 | ||||
| void ScrollableContainer::setScrollPos(const Vector2d& pos) | ||||
| { | ||||
| 	mScrollPos = pos; | ||||
| } | ||||
| 
 | ||||
| void ScrollableContainer::update(int deltaTime) | ||||
| { | ||||
| 	double scrollAmt = (double)deltaTime; | ||||
| 
 | ||||
| 	if(mAutoScrollSpeed != 0) | ||||
| 	{ | ||||
| 		mAutoScrollTimer += deltaTime; | ||||
| 
 | ||||
| 		scrollAmt = (float)(mAutoScrollTimer - mAutoScrollDelay); | ||||
| 
 | ||||
| 		if(scrollAmt > 0) | ||||
| 		{ | ||||
| 			//scroll the amount of time left over from the delay
 | ||||
| 			mAutoScrollTimer = mAutoScrollDelay; | ||||
| 
 | ||||
| 			//scale speed by our width! more text per line = slower scrolling
 | ||||
| 			const double widthMod = (680.0 / getSize().x); | ||||
| 			mScrollDir = Vector2d(0, mAutoScrollSpeed * widthMod); | ||||
| 		}else{ | ||||
| 			//not enough to pass the delay, do nothing
 | ||||
| 			scrollAmt = 0; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	Vector2d scroll = mScrollDir * scrollAmt; | ||||
| 	mScrollPos += scroll; | ||||
| 
 | ||||
| 	//clip scrolling within bounds
 | ||||
| 	if(mScrollPos.x < 0) | ||||
| 		mScrollPos.x = 0; | ||||
| 	if(mScrollPos.y < 0) | ||||
| 		mScrollPos.y = 0; | ||||
| 
 | ||||
| 	 | ||||
| 	Vector2i contentSize = getContentSize(); | ||||
| 	if(mScrollPos.x + getSize().x > contentSize.x) | ||||
| 		mScrollPos.x = (double)contentSize.x - getSize().x; | ||||
| 	if(mScrollPos.y + getSize().y > contentSize.y) | ||||
| 		mScrollPos.y = (double)contentSize.y - getSize().y; | ||||
| 
 | ||||
| 	GuiComponent::update(deltaTime); | ||||
| } | ||||
| 
 | ||||
| //this should probably return a box to allow for when controls don't start at 0,0
 | ||||
| Vector2i ScrollableContainer::getContentSize() | ||||
| { | ||||
| 	Vector2i max; | ||||
| 	for(unsigned int i = 0; i < mChildren.size(); i++) | ||||
| 	{ | ||||
| 		Vector2i bottomRight = (Vector2i)mChildren.at(i)->getSize() + mChildren.at(i)->getOffset(); | ||||
| 		if(bottomRight.x > max.x) | ||||
| 			max.x = bottomRight.x; | ||||
| 		if(bottomRight.y > max.y) | ||||
| 			max.y = bottomRight.y; | ||||
| 	} | ||||
| 
 | ||||
| 	return max; | ||||
| } | ||||
| 
 | ||||
| void ScrollableContainer::setSize(Vector2u size) | ||||
| { | ||||
| 	mSize = size; | ||||
| } | ||||
| 
 | ||||
| void ScrollableContainer::resetAutoScrollTimer() | ||||
| { | ||||
| 	mAutoScrollTimer = 0; | ||||
| } | ||||
							
								
								
									
										29
									
								
								src/components/ScrollableContainer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/components/ScrollableContainer.h
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include "../GuiComponent.h" | ||||
| 
 | ||||
| class ScrollableContainer : public GuiComponent | ||||
| { | ||||
| public: | ||||
| 	ScrollableContainer(Window* window); | ||||
| 
 | ||||
| 	void setSize(Vector2u size); | ||||
| 
 | ||||
| 	Vector2d getScrollPos() const; | ||||
| 	void setScrollPos(const Vector2d& pos); | ||||
| 	void setAutoScroll(int delay, double speed); //Use 0 for speed to disable.
 | ||||
| 	void resetAutoScrollTimer(); | ||||
| 
 | ||||
| 	void update(int deltaTime) override; | ||||
| 	void render() override; | ||||
| 
 | ||||
| 	//Vector2i getGlobalOffset() override;
 | ||||
| private: | ||||
| 	Vector2i getContentSize(); | ||||
| 
 | ||||
| 	Vector2d mScrollPos; | ||||
| 	Vector2d mScrollDir; | ||||
| 	int mAutoScrollDelay; | ||||
| 	double mAutoScrollSpeed; | ||||
| 	int mAutoScrollTimer; | ||||
| }; | ||||
|  | @ -3,12 +3,12 @@ | |||
| #include "../Log.h" | ||||
| 
 | ||||
| TextComponent::TextComponent(Window* window) : GuiComponent(window),  | ||||
| 	mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true), mAutoScrollDelay(0), mAutoScrollSpeed(0), mAutoScrollTimer(0) | ||||
| 	mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true, true) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| TextComponent::TextComponent(Window* window, const std::string& text, Font* font, Vector2i pos, Vector2u size) : GuiComponent(window),  | ||||
| 	mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true), mAutoScrollDelay(0), mAutoScrollSpeed(0), mAutoScrollTimer(0) | ||||
| 	mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true, true) | ||||
| { | ||||
| 	setText(text); | ||||
| 	setFont(font); | ||||
|  | @ -23,22 +23,16 @@ void TextComponent::setBox(Vector2i pos, Vector2u size) | |||
| 
 | ||||
| void TextComponent::setExtent(Vector2u size) | ||||
| { | ||||
| 	if(size == Vector2u(0, 0)) | ||||
| 	{ | ||||
| 		mAutoCalcExtent = true; | ||||
| 		calculateExtent(); | ||||
| 	}else{ | ||||
| 		mAutoCalcExtent = false; | ||||
| 		mSize = size; | ||||
| 	} | ||||
| 	mSize = size; | ||||
| 	mAutoCalcExtent = Vector2<bool>(size.x == 0, size.y == 0); | ||||
| 	calculateExtent(); | ||||
| } | ||||
| 
 | ||||
| void TextComponent::setFont(Font* font) | ||||
| { | ||||
| 	mFont = font; | ||||
| 
 | ||||
| 	if(mAutoCalcExtent) | ||||
| 		calculateExtent(); | ||||
| 	calculateExtent(); | ||||
| } | ||||
| 
 | ||||
| void TextComponent::setColor(unsigned int color) | ||||
|  | @ -50,12 +44,7 @@ void TextComponent::setText(const std::string& text) | |||
| { | ||||
| 	mText = text; | ||||
| 
 | ||||
| 	if(mAutoCalcExtent) | ||||
| 		calculateExtent(); | ||||
| 
 | ||||
| 	mScrollPos = Vector2d(0, 0); | ||||
| 	mScrollDir = Vector2d(0, 0); | ||||
| 	resetAutoScrollTimer(); | ||||
| 	calculateExtent(); | ||||
| } | ||||
| 
 | ||||
| Font* TextComponent::getFont() const | ||||
|  | @ -72,11 +61,11 @@ void TextComponent::onRender() | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	Renderer::pushClipRect(getGlobalOffset(), getSize()); | ||||
| 	//Renderer::pushClipRect(getGlobalOffset(), getSize());
 | ||||
| 
 | ||||
| 	Renderer::drawWrappedText(mText, (int)-mScrollPos.x, (int)-mScrollPos.y, mSize.x, mColor >> 8 << 8  | getOpacity(), font); | ||||
| 	Renderer::drawWrappedText(mText, 0, 0, mSize.x, mColor >> 8 << 8  | getOpacity(), font); | ||||
| 
 | ||||
| 	Renderer::popClipRect(); | ||||
| 	//Renderer::popClipRect();
 | ||||
| 
 | ||||
| 	GuiComponent::onRender(); | ||||
| } | ||||
|  | @ -90,75 +79,9 @@ void TextComponent::calculateExtent() | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	font->sizeText(mText, (int*)&mSize.x, (int*)&mSize.y); | ||||
| } | ||||
| 
 | ||||
| void TextComponent::setAutoScroll(int delay, double speed) | ||||
| { | ||||
| 	mAutoScrollDelay = delay; | ||||
| 	mAutoScrollSpeed = speed; | ||||
| 	resetAutoScrollTimer(); | ||||
| } | ||||
| 
 | ||||
| void TextComponent::resetAutoScrollTimer() | ||||
| { | ||||
| 	mAutoScrollTimer = 0; | ||||
| } | ||||
| 
 | ||||
| Vector2d TextComponent::getScrollPos() const | ||||
| { | ||||
| 	return mScrollPos; | ||||
| } | ||||
| 
 | ||||
| void TextComponent::setScrollPos(const Vector2d& pos) | ||||
| { | ||||
| 	mScrollPos = pos; | ||||
| } | ||||
| 
 | ||||
| void TextComponent::update(int deltaTime) | ||||
| { | ||||
| 	double scrollAmt = (double)deltaTime; | ||||
| 
 | ||||
| 	if(mAutoScrollSpeed != 0) | ||||
| 	{ | ||||
| 		mAutoScrollTimer += deltaTime; | ||||
| 
 | ||||
| 		scrollAmt = (float)(mAutoScrollTimer - mAutoScrollDelay); | ||||
| 
 | ||||
| 		if(scrollAmt > 0) | ||||
| 		{ | ||||
| 			//scroll the amount of time left over from the delay
 | ||||
| 			mAutoScrollTimer = mAutoScrollDelay; | ||||
| 
 | ||||
| 			//scale speed by our width! more text per line = slower scrolling
 | ||||
| 			const double widthMod = (680.0 / getSize().x); | ||||
| 			mScrollDir = Vector2d(0, mAutoScrollSpeed * widthMod); | ||||
| 		}else{ | ||||
| 			//not enough to pass the delay, do nothing
 | ||||
| 			scrollAmt = 0; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	Vector2d scroll = mScrollDir * scrollAmt; | ||||
| 	mScrollPos += scroll; | ||||
| 
 | ||||
| 	//clip scrolling within bounds
 | ||||
| 	if(mScrollPos.x < 0) | ||||
| 		mScrollPos.x = 0; | ||||
| 	if(mScrollPos.y < 0) | ||||
| 		mScrollPos.y = 0; | ||||
| 
 | ||||
| 	Font* font = getFont(); | ||||
| 	if(font != NULL) | ||||
| 	{ | ||||
| 		Vector2i textSize; | ||||
| 		Renderer::sizeWrappedText(mText, getSize().x, getFont(), &textSize.x, &textSize.y); | ||||
| 		 | ||||
| 		if(mScrollPos.x + getSize().x > textSize.x) | ||||
| 			mScrollPos.x = (double)textSize.x - getSize().x; | ||||
| 		if(mScrollPos.y + getSize().y > textSize.y) | ||||
| 			mScrollPos.y = (double)textSize.y - getSize().y; | ||||
| 	} | ||||
| 
 | ||||
| 	GuiComponent::update(deltaTime); | ||||
| 	if(mAutoCalcExtent.x) | ||||
| 		font->sizeText(mText, (int*)&mSize.x, (int*)&mSize.y); | ||||
| 	else | ||||
| 		if(mAutoCalcExtent.y) | ||||
| 			Renderer::sizeWrappedText(mText, getSize().x, mFont, NULL, (int*)&mSize.y); | ||||
| } | ||||
|  |  | |||
|  | @ -12,33 +12,21 @@ public: | |||
| 
 | ||||
| 	void setFont(Font* font); | ||||
| 	void setBox(Vector2i pos, Vector2u size); | ||||
| 	void setExtent(Vector2u size); //Use Vector2u(0, 0) to automatically generate extent.
 | ||||
| 	void setExtent(Vector2u size); //Use Vector2u(0, 0) to automatically generate extent on a single line.  Use Vector2(value, 0) to automatically generate extent for wrapped text.
 | ||||
| 	void setText(const std::string& text); | ||||
| 	void setColor(unsigned int color); | ||||
| 
 | ||||
| 	Vector2d getScrollPos() const; | ||||
| 	void setScrollPos(const Vector2d& pos); | ||||
| 	void setAutoScroll(int delay, double speed); //Use 0 for speed to disable.
 | ||||
| 	void resetAutoScrollTimer(); | ||||
| 
 | ||||
| 	void update(int deltaTime) override; | ||||
| 	void onRender() override; | ||||
| 
 | ||||
| private: | ||||
| 	Font* getFont() const; | ||||
| 	 | ||||
| 	void calculateExtent(); | ||||
| 
 | ||||
| 	unsigned int mColor; | ||||
| 	Font* mFont; | ||||
| 	bool mAutoCalcExtent; | ||||
| 	Vector2<bool> mAutoCalcExtent; | ||||
| 	std::string mText; | ||||
| 
 | ||||
| 	//scrolling
 | ||||
| 	Vector2d mScrollPos; | ||||
| 	Vector2d mScrollDir; | ||||
| 	int mAutoScrollDelay; | ||||
| 	double mAutoScrollSpeed; | ||||
| 	int mAutoScrollTimer; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Aloshi
						Aloshi