Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
40 KB
Referenced Files
None
Subscribers
None
diff --git a/src/GUIObject.h b/src/GUIObject.h
index a87bee9..4619086 100644
--- a/src/GUIObject.h
+++ b/src/GUIObject.h
@@ -1,389 +1,389 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GUIOBJECT_H
#define GUIOBJECT_H
#include "FileManager.h"
#include "ImageManager.h"
#include "Render.h"
#include <string>
#include <vector>
#include <list>
//Widget gravity properties
const int GUIGravityLeft=0;
const int GUIGravityCenter=1;
const int GUIGravityRight=2;
//The event id's.
//A click event used for e.g. buttons.
const int GUIEventClick=0;
//A change event used for e.g. textboxes.
const int GUIEventChange=1;
struct SDL_Renderer;
class GUIObject;
//Class that is used as event callback.
class GUIEventCallback{
public:
//This method is called when an event is fired.
//name: The name of the event.
//obj: Pointer to the GUIObject which caused this event.
//eventType: The type of event as defined above.
virtual void GUIEventCallback_OnEvent(ImageManager& imageManager, SDL_Renderer& renderer, std::string name,GUIObject* obj,int eventType)=0;
};
//Class containing the
class GUIObject{
public:
//The relative x location of the GUIObject.
int left;
//The relative y location of the GUIObject.
int top;
//The width of the GUIObject.
int width;
//The height of the GUIObject.
int height;
//The type of the GUIObject.
int type;
//The value of the GUIObject.
//It depends on the type of GUIObject what it means.
int value;
//The name of the GUIObject.
std::string name;
//The caption of the GUIObject.
//It depends on the type of GUIObject what it is.
std::string caption;
//Boolean if the GUIObject is enabled.
bool enabled;
//Boolean if the GUIObject is visible.
bool visible;
//Vector containing the children of the GUIObject.
std::vector<GUIObject*> childControls;
//Event callback used to invoke events.
GUIEventCallback* eventCallback;
//Widget's gravity to centering
int gravity;
int gravityX;
bool autoWidth;
//Is the parent widget a dialog?
bool inDialog;
protected:
//The state of the GUIObject.
//It depends on the type of GUIObject where it's used for.
int state;
//Texture containing different gui images.
SharedTexture bmGuiTex;
//Surface that can be used to cache rendered text.
TexturePtr cacheTex;
//String containing the old caption to detect if it changed.
std::string cachedCaption;
//Boolean containing the previous enabled state.
bool cachedEnabled;
public:
//Constructor.
//left: The relative x location of the GUIObject.
//top: The relative y location of the GUIObject.
//witdh: The width of the GUIObject.
//height: The height of the GUIObject.
//caption: The text on the GUIObject.
//value: The value of the GUIObject.
//enabled: Boolean if the GUIObject is enabled or not.
//visible: Boolean if the GUIObject is visisble or not.
//gravity: The way the GUIObject needs to be aligned.
GUIObject(ImageManager& imageManager, SDL_Renderer& renderer,int left=0,int top=0,int width=0,int height=0,
const char* caption=NULL,int value=0,
bool enabled=true,bool visible=true,int gravity=0):
left(left),top(top),width(width),height(height),
gravity(gravity),value(value),
enabled(enabled),visible(visible),
eventCallback(NULL),state(0),
cachedEnabled(enabled),gravityX(0)
{
//Make sure that caption isn't NULL before setting it.
if(caption){
GUIObject::caption=caption;
//And set the cached caption.
cachedCaption=caption;
}
if(width<=0)
autoWidth=true;
else
autoWidth=false;
inDialog=false;
//Load the gui images.
bmGuiTex=imageManager.loadTexture(getDataPath()+"gfx/gui.png", renderer);
}
//Destructor.
virtual ~GUIObject();
//Method used to handle mouse and/or key events.
//x: The x mouse location.
//y: The y mouse location.
//enabled: Boolean if the parent is enabled or not.
//visible: Boolean if the parent is visible or not.
//processed: Boolean if the event has been processed (by the parent) or not.
//Returns: Boolean if the event is processed by the child.
virtual bool handleEvents(SDL_Renderer&renderer, int x=0, int y=0, bool enabled=true, bool visible=true, bool processed=false);
//Method that will render the GUIObject.
//x: The x location to draw the GUIObject. (x+left)
//y: The y location to draw the GUIObject. (y+top)
//draw: Draw widget or just update it without drawing
virtual void render(SDL_Renderer& renderer, int x=0,int y=0,bool draw=true);
void addChild(GUIObject* obj){
//Add widget add a child
childControls.push_back(obj);
//Copy inDialog boolean from parent.
obj->inDialog=inDialog;
}
//Method for getting a child from a GUIObject.
//NOTE: This method doesn't search recursively.
//name: The name of the child to return.
//Returns: Pointer to the requested child, NULL otherwise.
GUIObject* getChild(std::string name){
//Look for a child with the name.
for(unsigned int i=0;i<childControls.size();i++)
if(childControls[i]->name==name)
return childControls[i];
//Not found so return NULL.
return NULL;
}
//Check if the caption or status has changed, or if the width is <0 and
//recreate the cached texture if so.
void refreshCache(bool enabled);
};
//Method used to handle the GUIEvents from the GUIEventQueue.
//kill: Boolean if an SDL_QUIT event may kill the GUIObjectRoot.
void GUIObjectHandleEvents(ImageManager &imageManager, SDL_Renderer &renderer, bool kill=false);
//A structure containing the needed variables to call an event.
struct GUIEvent{
//Event callback used to invoke the event.
GUIEventCallback* eventCallback;
//The name of the event.
std::string name;
//Pointer to the object which invoked the event.
GUIObject* obj;
//The type of event.
int eventType;
};
//List used to queue the gui events.
extern std::list<GUIEvent> GUIEventQueue;
class GUIButton:public GUIObject{
public:
GUIButton(ImageManager& imageManager, SDL_Renderer& renderer,int left=0,int top=0,int width=0,int height=0,
const char* caption=NULL,int value=0,
bool enabled=true,bool visible=true,int gravity=0):
GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity),
smallFont(false){ }
//Method used to handle mouse and/or key events.
//x: The x mouse location.
//y: The y mouse location.
//enabled: Boolean if the parent is enabled or not.
//visible: Boolean if the parent is visible or not.
//processed: Boolean if the event has been processed (by the parent) or not.
//Returns: Boolean if the event is processed by the child.
virtual bool handleEvents(SDL_Renderer&renderer, int x=0, int y=0, bool enabled=true, bool visible=true, bool processed=false);
//Method that will render the GUIScrollBar.
//x: The x location to draw the GUIObject. (x+left)
//y: The y location to draw the GUIObject. (y+top)
//draw: Whether displey the widget or not.
virtual void render(SDL_Renderer& renderer, int x=0,int y=0,bool draw=true);
//Boolean if small font is used.
bool smallFont;
};
class GUICheckBox:public GUIObject{
public:
GUICheckBox(ImageManager& imageManager, SDL_Renderer& renderer,int left=0,int top=0,int width=0,int height=0,
const char* caption=NULL,int value=0,
bool enabled=true,bool visible=true,int gravity=0):
GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity){}
//Method used to handle mouse and/or key events.
//x: The x mouse location.
//y: The y mouse location.
//enabled: Boolean if the parent is enabled or not.
//visible: Boolean if the parent is visible or not.
//processed: Boolean if the event has been processed (by the parent) or not.
//Returns: Boolean if the event is processed by the child.
virtual bool handleEvents(SDL_Renderer&,int x=0,int y=0,bool enabled=true,bool visible=true,bool processed=false);
//Method that will render the GUIScrollBar.
//x: The x location to draw the GUIObject. (x+left)
//y: The y location to draw the GUIObject. (y+top)
//draw: Whether displey the widget or not.
virtual void render(SDL_Renderer &renderer, int x=0, int y=0, bool draw=true);
};
class GUILabel:public GUIObject{
public:
GUILabel(ImageManager& imageManager, SDL_Renderer& renderer,int left=0,int top=0,int width=0,int height=0,
const char* caption=NULL,int value=0,
bool enabled=true,bool visible=true,int gravity=0):
GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity){}
//Method used to handle mouse and/or key events.
//x: The x mouse location.
//y: The y mouse location.
//enabled: Boolean if the parent is enabled or not.
//visible: Boolean if the parent is visible or not.
//processed: Boolean if the event has been processed (by the parent) or not.
//Returns: Boolean if the event is processed by the child.
virtual bool handleEvents(SDL_Renderer&,int =0, int =0, bool =true, bool =true, bool processed=false);
//Method that will render the GUIScrollBar.
//x: The x location to draw the GUIObject. (x+left)
//y: The y location to draw the GUIObject. (y+top)
//draw: Whether displey the widget or not.
virtual void render(SDL_Renderer &renderer, int x=0, int y=0, bool draw=true);
};
class GUITextBox:public GUIObject{
public:
GUITextBox(ImageManager& imageManager, SDL_Renderer& renderer,int left=0,int top=0,int width=0,int height=0,
const char* caption=NULL,int value=0,
bool enabled=true,bool visible=true,int gravity=0):
GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity),
- highlightStart(0),highlightEnd(0),tick(15){}
+ highlightStart(0),highlightEnd(0),highlightStartX(0),highlightEndX(0),tick(15){}
//Method used to handle mouse and/or key events.
//x: The x mouse location.
//y: The y mouse location.
//enabled: Boolean if the parent is enabled or not.
//visible: Boolean if the parent is visible or not.
//processed: Boolean if the event has been processed (by the parent) or not.
//Returns: Boolean if the event is processed by the child.
virtual bool handleEvents(SDL_Renderer&,int x=0,int y=0,bool enabled=true,bool visible=true,bool processed=false);
//Method that will render the GUIScrollBar.
//x: The x location to draw the GUIObject. (x+left)
//y: The y location to draw the GUIObject. (y+top)
//draw: Whether displey the widget or not.
virtual void render(SDL_Renderer& renderer, int x=0,int y=0,bool draw=true);
private:
//Text highlights.
int highlightStart;
int highlightEnd;
int highlightStartX;
int highlightEndX;
//Carrot ticking.
int tick;
//Functions for modifying the text.
void backspaceChar();
void deleteChar();
//Functions for moving the carrot.
void moveCarrotLeft();
void moveCarrotRight();
};
class GUIFrame:public GUIObject{
public:
GUIFrame(ImageManager& imageManager, SDL_Renderer& renderer,int left=0,int top=0,int width=0,int height=0,
const char* caption=NULL,int value=0,
bool enabled=true,bool visible=true,int gravity=0):
GUIObject(imageManager,renderer,left,top,width,height,caption,value,enabled,visible,gravity){
inDialog=true;
}
//Method used to handle mouse and/or key events.
//x: The x mouse location.
//y: The y mouse location.
//enabled: Boolean if the parent is enabled or not.
//visible: Boolean if the parent is visible or not.
//processed: Boolean if the event has been processed (by the parent) or not.
//Returns: Boolean if the event is processed by the child.
virtual bool handleEvents(SDL_Renderer&renderer, int x=0, int y=0, bool enabled=true, bool visible=true, bool processed=false);
//Method that will render the GUIScrollBar.
//x: The x location to draw the GUIObject. (x+left)
//y: The y location to draw the GUIObject. (y+top)
//draw: Whether displey the widget or not.
virtual void render(SDL_Renderer &renderer, int x=0, int y=0, bool draw=true);
};
//A GUIObject that holds an shared_ptr to a Texture for rendering.
class GUIImage:public GUIObject{
public:
GUIImage(ImageManager& imageManager, SDL_Renderer& renderer,int left=0,int top=0,int width=0,int height=0,
SharedTexture image=nullptr,SDL_Rect clip=SDL_Rect(),
bool enabled=true,bool visible=true):
GUIObject(imageManager,renderer,left,top,width,height,NULL,0,enabled,visible,0),
image(image),clip(clip){ }
//Destructor.
~GUIImage();
//Method used to handle mouse and/or key events.
//x: The x mouse location.
//y: The y mouse location.
//enabled: Boolean if the parent is enabled or not.
//visible: Boolean if the parent is visible or not.
//processed: Boolean if the event has been processed (by the parent) or not.
//Returns: Boolean if the event is processed by the child.
virtual bool handleEvents(SDL_Renderer&,int =0, int =0, bool =true, bool =true, bool processed=false);
//Method that will render the GUIScrollBar.
//x: The x location to draw the GUIObject. (x+left)
//y: The y location to draw the GUIObject. (y+top)
//draw: Whether display the widget or not.
virtual void render(SDL_Renderer &renderer, int x=0, int y=0, bool draw=true);
//Method that will change the dimensions of the GUIImage so that the full image is shown.
//OR in case of a clip rect that the selected section of the image is shown.
void fitToImage();
//Method for setting the image of the widget.
//image: SharedTexture containing the image.
void setImage(SharedTexture texture){
image=texture;
}
//Method for setting the clip rectangle for the GUIImager.
//rect: The new clip rectangle.
void setClipRect(SDL_Rect rect){
clip=rect;
}
private:
//Pointer to the SDL_Texture to draw.
//MAY BE NULL!!
SharedTexture image;
//Optional rectangle for defining the section of the texture that should be drawn.
//NOTE: This doesn't have to correspond with the dimensions of the GUIObject.
SDL_Rect clip;
};
#endif
diff --git a/src/GUITextArea.cpp b/src/GUITextArea.cpp
index b3bd9f9..11a9de9 100644
--- a/src/GUITextArea.cpp
+++ b/src/GUITextArea.cpp
@@ -1,840 +1,848 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow 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 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow 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 Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Functions.h"
#include "GUITextArea.h"
#include <cmath>
#include <algorithm>
#include <ctype.h>
#include <SDL_ttf.h>
using namespace std;
GUITextArea::GUITextArea(ImageManager& imageManager, SDL_Renderer& renderer,int left,int top,int width,int height,bool enabled,bool visible):
GUIObject(imageManager,renderer,left,top,width,height,NULL,-1,enabled,visible),editable(true){
//Set some default values.
state=0;
setFont(fontText);
highlightLineStart=highlightLineEnd=0;
highlightStartX=highlightEndX=0;
highlightStart=highlightEnd=0;
//Add empty text.
lines.push_back("");
linesCache.push_back(nullptr);
//Create scrollbar widget.
scrollBar=new GUIScrollBar(imageManager,renderer,width-16,0,16,height,1,0,0,0);
childControls.push_back(scrollBar);
scrollBarH=new GUIScrollBar(imageManager,renderer,0,height-16,width-16,16,0,0,0,0,100,500,true,false);
childControls.push_back(scrollBarH);
}
void GUITextArea::setFont(TTF_Font* font){
//NOTE: This fuction shouldn't be called after adding items, so no need to update the whole cache.
widgetFont=font;
fontHeight=TTF_FontHeight(font)+1;
}
bool GUITextArea::handleEvents(SDL_Renderer& renderer,int x,int y,bool enabled,bool visible,bool processed){
//Boolean if the event is processed.
bool b=processed;
//The GUIObject is only enabled when he and his parent are enabled.
enabled=enabled && this->enabled;
//The GUIObject is only enabled when he and his parent are enabled.
visible=visible && this->visible;
//Get the absolute position.
x+=left;
y+=top;
//Update the vertical scrollbar.
b=b||scrollBar->handleEvents(renderer,x,y,enabled,visible,b);
//NOTE: We don't reset the state to have a "focus" effect.
//Only check for events when the object is both enabled and visible.
if(enabled&&visible){
//Check if there's a key press and the event hasn't been already processed.
if(state==2 && event.type==SDL_KEYDOWN && !b && editable){
//Get the keycode.
SDL_Keycode key=event.key.keysym.sym;
//Check if the key is supported.
if(event.key.keysym.sym==SDLK_BACKSPACE){
//Delete one character direct to prevent a lag.
backspaceChar(renderer);
}else if(event.key.keysym.sym==SDLK_DELETE){
//Delete one character direct to prevent a lag.
deleteChar(renderer);
}else if(event.key.keysym.sym==SDLK_RETURN){
removeHighlight(renderer);
//Split the current line and update.
string str2=lines.at(highlightLineEnd).substr(highlightStart);
lines.at(highlightLineStart)=lines.at(highlightLineStart).substr(0,highlightStart);
linesCache.at(highlightLineStart) =
textureFromText(renderer,*widgetFont,lines.at(highlightLineStart).c_str(),BLACK);
//Calculate indentation.
int indent=0;
for (int i=0; i<lines.at(highlightLineStart).length(); i++){
if (isspace(lines.at(highlightLineStart)[i]))
indent++;
else
break;
}
str2.insert(0,indent,' ');
//Add the rest in a new line.
highlightLineStart++;
highlightStart=indent;
highlightEnd=highlightStart;
highlightLineEnd++;
highlightStartX=0;
for(int i=0; i<indent; i++){
int advance;
TTF_GlyphMetrics(widgetFont,str2.at(i),NULL,NULL,NULL,NULL,&advance);
highlightStartX+=advance;
}
highlightEndX=highlightStartX;
lines.insert(lines.begin()+highlightLineStart,str2);
auto tex = textureFromText(renderer,*widgetFont,str2.c_str(),BLACK);
linesCache.insert(linesCache.begin()+highlightLineStart,std::move(tex));
adjustView();
//If there is an event callback then call it.
if(eventCallback){
GUIEvent e={eventCallback,name,this,GUIEventChange};
GUIEventQueue.push_back(e);
}
}else if(event.key.keysym.sym==SDLK_TAB){
removeHighlight(renderer);
//Add a tabulator or here just 2 spaces to the string.
std::string& str=lines.at(highlightLineStart);
str.insert((size_t)highlightStart,2,char(' '));
int advance;
TTF_GlyphMetrics(widgetFont,' ',NULL,NULL,NULL,NULL,&advance);
highlightStart+=2;
highlightStartX=advance*2;
highlightEnd=highlightStart;
highlightEndX=highlightStartX;
//Update cache.
linesCache.at(highlightLineStart) = textureFromText(renderer,*widgetFont,str.c_str(),BLACK);
adjustView();
}else if(event.key.keysym.sym==SDLK_RIGHT){
//Move the carrot once to prevent a lag.
moveCarrotRight();
}else if(event.key.keysym.sym==SDLK_LEFT){
//Move the carrot once to prevent a lag.
moveCarrotLeft();
}else if(event.key.keysym.sym==SDLK_DOWN){
//Move the carrot once to prevent a lag.
moveCarrotDown();
}else if(event.key.keysym.sym==SDLK_UP){
//Move the carrot once to prevent a lag.
moveCarrotUp();
}
//The event has been processed.
b=true;
}else if(state == 2 && event.type == SDL_TEXTINPUT && !b && editable){
int m = strlen(event.text.text);
if (m > 0){
removeHighlight(renderer);
string* str = &lines.at(highlightLineStart);
str->insert((size_t)highlightEnd, event.text.text);
highlightEnd += m;
highlightStart = highlightEnd;
int advance = 0;
for (int i = 0;;) {
int a = 0;
int ch = utf8ReadForward(event.text.text, i);
if (ch <= 0) break;
TTF_GlyphMetrics(widgetFont, ch, NULL, NULL, NULL, NULL, &a);
advance += a;
}
highlightStartX = highlightEndX = highlightStartX + advance;
//Update cache.
linesCache.at(highlightLineStart) =
textureFromText(renderer, *widgetFont, str->c_str(), BLACK);
//Update view if needed.
adjustView();
//If there is an event callback then call it.
if (eventCallback){
GUIEvent e = { eventCallback, name, this, GUIEventChange };
GUIEventQueue.push_back(e);
}
}
} else if (state == 2 && event.type == SDL_TEXTEDITING && !b && editable){
// TODO: process SDL_TEXTEDITING event
}
//The mouse location (x=i, y=j) and the mouse button (k).
int i,j,k;
k=SDL_GetMouseState(&i,&j);
//Check if the mouse is inside the GUIObject.
if(i>=x&&i<x+width&&j>=y&&j<y+height){
//We can only increase our state. (nothing->hover->focus).
if(state!=2){
state=1;
}
//Check for mouse wheel scrolling.
//Scroll horizontally if mouse is over the horizontal scrollbar.
//Otherwise scroll vertically.
if(event.type==SDL_MOUSEWHEEL) {
if(j>=y+height-16&&scrollBarH->visible){
if(event.wheel.y < 0){
scrollBarH->value+=20;
if(scrollBarH->value>scrollBarH->maxValue)
scrollBarH->value=scrollBarH->maxValue;
}else if(event.wheel.y > 0){
scrollBarH->value-=20;
if(scrollBarH->value<0)
scrollBarH->value=0;
}
}else{
if(event.wheel.y < 0){
scrollBar->value++;
if(scrollBar->value>scrollBar->maxValue)
scrollBar->value=scrollBar->maxValue;
}else if(event.wheel.y > 0){
scrollBar->value--;
if(scrollBar->value<0)
scrollBar->value=0;
}
}
}
//When mouse is not over the scrollbar.
if(i<x+width-16&&j<(scrollBarH->visible?y+height-16:y+height)&&editable){
//Update the cursor type.
currentCursor=CURSOR_CARROT;
if (((event.type == SDL_MOUSEBUTTONUP || event.type == SDL_MOUSEBUTTONDOWN) && event.button.button == 1)
|| (event.type == SDL_MOUSEMOTION && (k & SDL_BUTTON(1))))
{
//Move carrot to the place clicked.
int mouseLine = clamp((int)floor(float(j - y) / float(fontHeight)) + scrollBar->value, 0, lines.size() - 1);
string* str = &lines.at(mouseLine);
value = str->length();
int clickX = i - x + scrollBarH->value;
int finalX = 0;
int finalPos = str->length();
for (int i = 0;;){
int advance = 0;
int i0 = i;
int ch = utf8ReadForward(str->c_str(), i);
if (ch <= 0) break;
TTF_GlyphMetrics(widgetFont, ch, NULL, NULL, NULL, NULL, &advance);
finalX += advance;
if (clickX < finalX - advance / 2){
finalPos = i0;
finalX -= advance;
break;
}
}
if (event.type == SDL_MOUSEBUTTONUP){
state = 2;
highlightEnd = finalPos;
highlightEndX = finalX;
highlightLineEnd = mouseLine;
} else if (event.type == SDL_MOUSEBUTTONDOWN){
state = 2;
highlightStart = highlightEnd = finalPos;
highlightStartX = highlightEndX = finalX;
highlightLineStart = highlightLineEnd = mouseLine;
} else if (event.type == SDL_MOUSEMOTION){
state = 2;
highlightEnd = finalPos;
highlightEndX = finalX;
highlightLineEnd = mouseLine;
}
}
}
}else{
//The mouse is outside the TextBox.
//If we don't have focus but only hover we lose it.
if(state==1){
state=0;
}
//If it's a click event outside the textbox then we blur.
if(event.type==SDL_MOUSEBUTTONUP && event.button.button==SDL_BUTTON_LEFT){
//Set state to 0.
state=0;
}
}
}
if(!editable)
highlightLineStart=scrollBar->value;
//Process child controls event except for the scrollbar.
//That's why i starts at one.
for(unsigned int i=1;i<childControls.size();i++){
bool b1=childControls[i]->handleEvents(renderer,x,y,enabled,visible,b);
//The event is processed when either our or the childs is true (or both).
b=b||b1;
}
return b;
}
void GUITextArea::removeHighlight(SDL_Renderer& renderer){
if (highlightLineStart==highlightLineEnd) {
int start=highlightStart, end=highlightEnd, startx=highlightStartX;
if(highlightStart>highlightEnd){
start=highlightEnd;
end=highlightStart;
startx=highlightEndX;
}
std::string& str=lines.at(highlightLineStart);
str.erase(start,end-start);
highlightStart=highlightEnd=start;
highlightStartX=highlightEndX=startx;
// Update cache.
linesCache.at(highlightLineStart) = textureFromText(renderer,*widgetFont,str.c_str(),BLACK);
}else{
int startLine=highlightLineStart, endLine=highlightLineEnd,
start=highlightStart, end=highlightEnd, startx=highlightStartX;
if(startLine>endLine){
startLine=highlightLineEnd;
endLine=highlightLineStart;
start=highlightEnd;
end=highlightStart;
startx=highlightEndX;
}
string *str=&lines.at(startLine);
str->erase(start,str->length()-start);
if(endLine-startLine>=2){
for(int i=startLine+1; i < endLine; i++){
lines.erase(lines.begin()+i);
linesCache.erase(linesCache.begin()+i);
endLine--;
i--;
}
}
string *str2=&lines.at(endLine);
str2->erase(0, end);
str->append(*str2);
lines.erase(lines.begin()+endLine);
linesCache.erase(linesCache.begin()+endLine);
highlightLineStart=highlightLineEnd=startLine;
highlightStart=highlightEnd=start;
highlightStartX=highlightEndX=startx;
// Update cache.
linesCache.at(startLine) = textureFromText(renderer,*widgetFont,str->c_str(),BLACK);
}
adjustView();
}
void GUITextArea::deleteChar(SDL_Renderer& renderer){
if (highlightLineStart==highlightLineEnd && highlightStart==highlightEnd){
if(highlightEnd>=lines.at(highlightLineEnd).length()){
if(highlightLineEnd<lines.size()-1){
highlightLineEnd++;
highlightEnd=0;
}
} else {
utf8ReadForward(lines.at(highlightLineEnd).c_str(), highlightEnd);
}
}
removeHighlight(renderer);
//If there is an event callback.
if(eventCallback){
GUIEvent e={eventCallback,name,this,GUIEventChange};
GUIEventQueue.push_back(e);
}
}
void GUITextArea::backspaceChar(SDL_Renderer& renderer){
if(highlightLineStart==highlightLineEnd && highlightStart==highlightEnd){
if(highlightStart<=0){
if(highlightLineStart==0){
highlightStart=0;
}else{
highlightLineStart--;
highlightStart=lines.at(highlightLineStart).length();
highlightStartX=0;
- TexturePtr& t = linesCache.at(highlightLineEnd);
- if(t) highlightStartX=textureWidth(*t);
+ if (highlightStart > 0) {
+ TexturePtr& t = linesCache.at(highlightLineEnd);
+ if (t) highlightStartX = textureWidth(*t);
+ }
highlightEndX=highlightStartX;
}
}else{
int advance = 0;
int ch = utf8ReadBackward(lines.at(highlightLineStart).c_str(), highlightStart);
if (ch > 0) TTF_GlyphMetrics(widgetFont, ch, NULL, NULL, NULL, NULL, &advance);
highlightStartX -= advance;
highlightEndX = highlightStartX;
}
}
removeHighlight(renderer);
//If there is an event callback.
if(eventCallback){
GUIEvent e={eventCallback,name,this,GUIEventChange};
GUIEventQueue.push_back(e);
}
}
void GUITextArea::moveCarrotRight(){
if (highlightEnd>=lines.at(highlightLineEnd).length()){
if (highlightLineEnd<lines.size()-1){
highlightEnd=0;
highlightEndX=0;
highlightLineEnd++;
}
}else{
int advance = 0;
int ch = utf8ReadForward(lines.at(highlightLineEnd).c_str(), highlightEnd);
if (ch > 0) TTF_GlyphMetrics(widgetFont, ch, NULL, NULL, NULL, NULL, &advance);
highlightEndX += advance;
}
if((SDL_GetModState()&KMOD_SHIFT)==0){
highlightLineStart=highlightLineEnd;
highlightStart=highlightEnd;
highlightStartX=highlightEndX;
}
adjustView();
}
void GUITextArea::moveCarrotLeft(){
if (highlightEnd<=0){
if (highlightLineEnd==0){
highlightEnd=0;
}else{
highlightLineEnd--;
highlightEnd=lines.at(highlightLineEnd).length();
highlightEndX=0;
- TexturePtr& t = linesCache.at(highlightLineEnd);
- if(t) highlightEndX=textureWidth(*t);
+ if (highlightEnd > 0) {
+ TexturePtr& t = linesCache.at(highlightLineEnd);
+ if (t) highlightEndX = textureWidth(*t);
+ }
}
}else{
int advance = 0;
int ch = utf8ReadBackward(lines.at(highlightLineEnd).c_str(), highlightEnd);
if (ch > 0) TTF_GlyphMetrics(widgetFont, ch, NULL, NULL, NULL, NULL, &advance);
highlightEndX -= advance;
}
if((SDL_GetModState()&KMOD_SHIFT)==0){
highlightLineStart=highlightLineEnd;
highlightStart=highlightEnd;
highlightStartX=highlightEndX;
}
adjustView();
}
void GUITextArea::moveCarrotUp(){
if(highlightLineEnd==0){
highlightEnd=0;
highlightEndX=0;
}else{
highlightLineEnd--;
const std::string& str=lines.at(highlightLineEnd);
//Find out closest match.
int xPos=0;
int i=0;
for (;;){
int advance = 0;
int i0 = i;
int ch = utf8ReadForward(str.c_str(), i);
if (ch <= 0) break;
TTF_GlyphMetrics(widgetFont, ch, NULL, NULL, NULL, NULL, &advance);
xPos += advance;
if(highlightEndX<xPos-advance/2){
highlightEnd=i=i0;
highlightEndX=xPos-advance;
break;
}
}
if (i == 0) {
highlightEnd = highlightEndX = 0;
} else if (i == str.length()){
highlightEnd=str.length();
highlightEndX=0;
- TexturePtr& t = linesCache.at(highlightLineEnd);
- if(t) highlightEndX=textureWidth(*t);
+ if (highlightEnd > 0) {
+ TexturePtr& t = linesCache.at(highlightLineEnd);
+ if (t) highlightEndX = textureWidth(*t);
+ }
}
}
if((SDL_GetModState()&KMOD_SHIFT)==0){
highlightStart=highlightEnd;
highlightStartX=highlightEndX;
highlightLineStart=highlightLineEnd;
}
adjustView();
}
void GUITextArea::moveCarrotDown(){
if(highlightLineEnd==lines.size()-1){
highlightEnd=lines.at(highlightLineEnd).length();
highlightEndX=0;
- TexturePtr& t = linesCache.at(highlightLineEnd);
- if(t) highlightEndX=textureWidth(*t);
+ if (highlightEnd > 0) {
+ TexturePtr& t = linesCache.at(highlightLineEnd);
+ if (t) highlightEndX = textureWidth(*t);
+ }
}else{
highlightLineEnd++;
string* str=&lines.at(highlightLineEnd);
//Find out closest match.
int xPos=0;
int i = 0;
for (;;){
int advance = 0;
int i0 = i;
int ch = utf8ReadForward(str->c_str(), i);
if (ch <= 0) break;
TTF_GlyphMetrics(widgetFont, ch, NULL, NULL, NULL, NULL, &advance);
xPos += advance;
if (highlightEndX<xPos - advance / 2){
highlightEnd = i = i0;
highlightEndX = xPos - advance;
break;
}
}
if (i == 0) {
highlightEnd = highlightEndX = 0;
} else if (i == str->length()){
highlightEnd=str->length();
highlightEndX=0;
TexturePtr& t = linesCache.at(highlightLineEnd);
if(t) highlightEndX=textureWidth(*t);
}
}
if((SDL_GetModState()&KMOD_SHIFT)==0){
highlightStart=highlightEnd;
highlightStartX=highlightEndX;
highlightLineStart=highlightLineEnd;
}
adjustView();
}
void GUITextArea::adjustView(){
//Adjust view to current line.
if(fontHeight*(highlightLineEnd-scrollBar->value)+4>height-4)
scrollBar->value=highlightLineEnd-3;
else if(highlightLineEnd-scrollBar->value<0)
scrollBar->value=highlightLineEnd;
//Find out the lenght of the longest line.
int maxWidth=0;
for(const TexturePtr& tex: linesCache){
if(tex) {
const int texWidth = textureWidth(*tex.get());
if(texWidth>width-16&&texWidth>maxWidth)
maxWidth=texWidth;
}
}
//We need the horizontal scrollbar if any line is too long.
if(maxWidth>0){
scrollBar->height=height-16;
scrollBarH->visible=true;
scrollBarH->maxValue=maxWidth-width+24;
}else{
scrollBar->height=height;
scrollBarH->visible=false;
scrollBarH->value=0;
scrollBarH->maxValue=0;
}
//Adjust the horizontal view.
int carrotX=0;
for(int n=0;n<highlightEnd;){
int advance = 0;
int ch = utf8ReadForward(lines.at(highlightLineEnd).c_str(), n);
if (ch <= 0) break;
TTF_GlyphMetrics(widgetFont, ch, NULL, NULL, NULL, NULL, &advance);
carrotX += advance;
}
if(carrotX>width-24)
scrollBarH->value=scrollBarH->maxValue;
else
scrollBarH->value=0;
//Update vertical scrollbar.
int rh=height-(scrollBarH->visible?16:0);
int m=lines.size(),n=(int)floor((float)rh/(float)fontHeight);
if(m>n){
scrollBar->maxValue=m-n;
scrollBar->smallChange=1;
scrollBar->largeChange=n;
}else{
scrollBar->value=0;
scrollBar->maxValue=0;
}
}
void GUITextArea::drawHighlight(SDL_Renderer& renderer, int x,int y,SDL_Rect r,SDL_Color color){
if(r.x<x) {
int tmp_w = r.w - x + r.x;
if(tmp_w<0) return;
r.w = tmp_w;
r.x = left;
}
if(r.x+r.w > x+width){
int tmp_w=width-r.x+x;
if(tmp_w<=0) return;
r.w=tmp_w;
}
if(r.y<y){
int tmp_h=r.h - y + r.y;
if(tmp_h<=0) return;
r.h=tmp_h;
}
if(r.y+r.h > y+height){
int tmp_h=height-r.y+y;
if(tmp_h<=0) return;
r.h=tmp_h;
}
SDL_SetRenderDrawColor(&renderer, color.r, color.g, color.b, color.a);
SDL_RenderFillRect(&renderer, &r);
}
void GUITextArea::render(SDL_Renderer& renderer, int x,int y,bool draw){
//There's no need drawing the GUIObject when it's invisible.
if(!visible||!draw)
return;
//Get the absolute x and y location.
x+=left;
y+=top;
{
//Draw the box.
const Uint32 color=0xFFFFFFFF;
drawGUIBox(x,y,width,height,renderer,color);
}
//Place the highlighted area.
SDL_Rect r;
const SDL_Color color{128,128,128,255};
if (editable) {
if (highlightLineStart == highlightLineEnd){
r.x = x - scrollBarH->value;
r.y = y + ((highlightLineStart - scrollBar->value)*fontHeight);
r.h = fontHeight;
if (highlightStart < highlightEnd){
r.x += highlightStartX;
r.w = highlightEndX - highlightStartX;
} else{
r.x += highlightEndX;
r.w = highlightStartX - highlightEndX;
}
drawHighlight(renderer, x, y, r, color);
} else if (highlightLineStart < highlightLineEnd){
int lnc = highlightLineEnd - highlightLineStart;
for (int i = 0; i <= lnc; i++){
r.x = x - scrollBarH->value;
r.y = y + ((i + highlightLineStart - scrollBar->value)*fontHeight);
r.w = width + scrollBarH->maxValue;
r.h = fontHeight;
if (i == 0){
r.x += highlightStartX;
r.w -= highlightStartX;
} else if (i == lnc){
r.w = highlightEndX;
}
if (lines.at(i + highlightLineStart).empty()){
r.w = fontHeight / 4;
}
drawHighlight(renderer, x, y, r, color);
}
} else{
int lnc = highlightLineStart - highlightLineEnd;
for (int i = 0; i <= lnc; i++){
r.x = x - scrollBarH->value;
r.y = y + ((i + highlightLineEnd - scrollBar->value)*fontHeight);
r.w = width + scrollBarH->maxValue;
r.h = fontHeight;
if (i == 0){
r.x += highlightEndX;
r.w -= highlightEndX;
} else if (i == lnc){
r.w = highlightStartX;
}
if (lines.at(i + highlightLineEnd).empty()){
r.w = fontHeight / 4;
}
drawHighlight(renderer, x, y, r, color);
}
}
}
//Draw text.
int lineY=0;
for(auto it = linesCache.begin()+scrollBar->value;it!=linesCache.end();++it){
if(*it){
if(lineY<height){
SDL_Rect r = { scrollBarH->value, 0, std::min(width - 17, textureWidth(*it->get()) - scrollBarH->value), textureHeight(*it->get()) };
int over=-height+lineY+fontHeight;
if(over>0) r.h-=over;
const SDL_Rect dstRect={x+1,y+1+lineY,r.w,r.h};
if(r.w>0 && r.h>0) SDL_RenderCopy(&renderer,it->get(),&r,&dstRect);
}else{
break;
}
}
lineY+=fontHeight;
}
//Only draw the carrot when focus.
if(state==2&&editable){
r.x=x-scrollBarH->value+highlightEndX;
r.y=y+4+fontHeight*(highlightLineEnd-scrollBar->value);
r.w=2;
r.h=fontHeight-4;
//Make sure that the carrot is inside the textbox.
if((r.y<y+height-4)&&(r.y>y)&&(r.x>x-1)&&(r.x<x+width-16)){
drawHighlight(renderer,x,y,r,SDL_Color{0,0,0,127});
}
}
//We now need to draw all the children of the GUIObject.
for(unsigned int i=0;i<childControls.size();i++){
childControls[i]->render(renderer,x,y,draw);
}
}
void GUITextArea::setString(SDL_Renderer& renderer, std::string input){
//Clear previous content if any.
//Delete every line.
lines.clear();
linesCache.clear();
size_t linePos=0,lineLen=0;
//Loop through the input string.
for(size_t i=0;i<input.length();++i){
//Check when we come in end of a line.
if(input.at(i)=='\n'){
//Check if the line is empty.
if(lineLen==0){
lines.push_back("");
linesCache.push_back(nullptr);
}else{
//Read the whole line.
string line=input.substr(linePos,lineLen);
lines.push_back(line);
//Render and cache text.
linesCache.push_back(
textureFromText(renderer,*widgetFont,line.c_str(),BLACK));
}
//Skip '\n' in end of the line.
linePos=i+1;
lineLen=0;
}else{
lineLen++;
}
}
//The string might not end with a newline.
//That's why we're going to add end rest of the string as one line.
string line=input.substr(linePos);
lines.push_back(line);
//bm=TTF_RenderUTF8_Blended(widgetFont,line.c_str(),black);
TexturePtr tex = textureFromText(renderer,*widgetFont,line.c_str(),BLACK);
linesCache.push_back(std::move(tex));
adjustView();
}
void GUITextArea::setStringArray(SDL_Renderer& renderer, std::vector<std::string> input){
//Free cached images.
linesCache.clear();
//Copy values.
lines=input;
for(const std::string& s: lines) {
linesCache.push_back(textureFromText(renderer,*widgetFont,s.c_str(),BLACK));
}
adjustView();
}
string GUITextArea::getString(){
string tmp;
for(vector<string>::iterator it=lines.begin();it!=lines.end();++it){
//Append a newline only if not the first line.
if(it!=lines.begin())
tmp.append(1,'\n');
//Append the line.
tmp.append(*it);
}
return tmp;
}
void GUITextArea::resize(){
scrollBar->left=width-16;
scrollBar->height=height;
if(scrollBarH->visible)
scrollBar->height-=16;
scrollBarH->top=height-16;
scrollBarH->width=width-16;
adjustView();
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 16, 1:24 AM (2 w, 21 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
69822
Default Alt Text
(40 KB)

Event Timeline