summaryrefslogtreecommitdiff
path: root/src/gui/interface/Textbox.cpp
diff options
context:
space:
mode:
authorSimon Robertshaw <simon@hardwired.org.uk>2013-03-24 12:24:17 (GMT)
committer Simon Robertshaw <simon@hardwired.org.uk>2013-03-24 12:24:17 (GMT)
commit9b5b85f9b01cbda7ef9a7ec2a15b2a35630a5b9d (patch)
treeac7d040253b459ce102e476cb19ab59e3cfa90d7 /src/gui/interface/Textbox.cpp
parent6bf98ccdca39936a3c51367862eed7c49f8786ec (diff)
parentbdc69f31c0be94191015838886bdcc2bc67f1acb (diff)
downloadpowder-9b5b85f9b01cbda7ef9a7ec2a15b2a35630a5b9d.zip
powder-9b5b85f9b01cbda7ef9a7ec2a15b2a35630a5b9d.tar.gz
Merge branch 'reorganisation' of github.com:FacialTurd/The-Powder-Toy
Diffstat (limited to 'src/gui/interface/Textbox.cpp')
-rw-r--r--src/gui/interface/Textbox.cpp707
1 files changed, 707 insertions, 0 deletions
diff --git a/src/gui/interface/Textbox.cpp b/src/gui/interface/Textbox.cpp
new file mode 100644
index 0000000..c23bcb4
--- /dev/null
+++ b/src/gui/interface/Textbox.cpp
@@ -0,0 +1,707 @@
+#include <string>
+#include <iostream>
+#include <stdexcept>
+#include <time.h>
+#include "Config.h"
+#include "gui/interface/Point.h"
+#include "gui/interface/Textbox.h"
+#include "gui/interface/Keys.h"
+#include "ContextMenu.h"
+
+using namespace ui;
+
+Textbox::Textbox(Point position, Point size, std::string textboxText, std::string textboxPlaceholder):
+ Label(position, size, ""),
+ actionCallback(NULL),
+ masked(false),
+ border(true),
+ mouseDown(false),
+ limit(std::string::npos),
+ inputType(All),
+ keyDown(0),
+ characterDown(0),
+ ReadOnly(false)
+{
+ placeHolder = textboxPlaceholder;
+
+ SetText(textboxText);
+ cursor = text.length();
+
+ menu->RemoveItem(0);
+ menu->AddItem(ContextMenuItem("Cut", 1, true));
+ menu->AddItem(ContextMenuItem("Copy", 0, true));
+ menu->AddItem(ContextMenuItem("Paste", 2, true));
+}
+
+Textbox::~Textbox()
+{
+ if(actionCallback)
+ delete actionCallback;
+}
+
+void Textbox::SetHidden(bool hidden)
+{
+ menu->RemoveItem(0);
+ menu->RemoveItem(1);
+ menu->RemoveItem(2);
+ menu->AddItem(ContextMenuItem("Cut", 1, !hidden));
+ menu->AddItem(ContextMenuItem("Copy", 0, !hidden));
+ menu->AddItem(ContextMenuItem("Paste", 2, true));
+
+ masked = hidden;
+}
+
+void Textbox::SetPlaceholder(std::string text)
+{
+ placeHolder = text;
+}
+
+void Textbox::SetText(std::string newText)
+{
+ backingText = newText;
+
+ if(masked)
+ {
+ std::string maskedText = std::string(newText);
+ std::fill(maskedText.begin(), maskedText.end(), '\x8D');
+ Label::SetText(maskedText);
+ }
+ else
+ Label::SetText(newText);
+
+ cursor = newText.length();
+
+ if(cursor)
+ {
+ Graphics::PositionAtCharIndex(multiline?((char*)textLines.c_str()):((char*)text.c_str()), cursor, cursorPositionX, cursorPositionY);
+ }
+ else
+ {
+ cursorPositionY = cursorPositionX = 0;
+ }
+}
+
+Textbox::ValidInput Textbox::GetInputType()
+{
+ return inputType;
+}
+
+void Textbox::SetInputType(ValidInput input)
+{
+ inputType = input;
+}
+
+void Textbox::SetLimit(size_t limit)
+{
+ this->limit = limit;
+}
+
+size_t Textbox::GetLimit()
+{
+ return limit;
+}
+
+std::string Textbox::GetText()
+{
+ return backingText;
+}
+
+void Textbox::OnContextMenuAction(int item)
+{
+ switch(item)
+ {
+ case 0:
+ copySelection();
+ break;
+ case 1:
+ cutSelection();
+ break;
+ case 2:
+ pasteIntoSelection();
+ break;
+ }
+}
+
+void Textbox::cutSelection()
+{
+ char * clipboardText;
+ clipboardText = ClipboardPull();
+ std::string newText = std::string(clipboardText);
+ free(clipboardText);
+ if(HasSelection())
+ {
+ if(getLowerSelectionBound() < 0 || getHigherSelectionBound() > backingText.length())
+ return;
+ ClipboardPush((char*)backingText.substr(getLowerSelectionBound(), getHigherSelectionBound()-getLowerSelectionBound()).c_str());
+ backingText.erase(backingText.begin()+getLowerSelectionBound(), backingText.begin()+getHigherSelectionBound());
+ cursor = getLowerSelectionBound();
+ }
+ else
+ {
+ ClipboardPush((char*)backingText.c_str());
+ backingText.clear();
+ }
+ ClearSelection();
+
+ if(masked)
+ {
+ std::string maskedText = std::string(backingText);
+ std::fill(maskedText.begin(), maskedText.end(), '\x8D');
+ Label::SetText(maskedText);
+ }
+ else
+ {
+ text = backingText;
+ }
+ if(actionCallback)
+ actionCallback->TextChangedCallback(this);
+
+ if(multiline)
+ updateMultiline();
+ updateSelection();
+ TextPosition(text);
+
+ if(cursor)
+ {
+ Graphics::PositionAtCharIndex(multiline?((char*)textLines.c_str()):((char*)text.c_str()), cursor, cursorPositionX, cursorPositionY);
+ }
+ else
+ {
+ cursorPositionY = cursorPositionX = 0;
+ }
+}
+
+void Textbox::selectAll()
+{
+ selectionIndex0 = 0;
+ selectionIndex1 = text.length();
+ updateSelection();
+}
+
+void Textbox::pasteIntoSelection()
+{
+ char * clipboardText;
+ clipboardText = ClipboardPull();
+ std::string newText = std::string(clipboardText);
+ free(clipboardText);
+ if(HasSelection())
+ {
+ if(getLowerSelectionBound() < 0 || getHigherSelectionBound() > backingText.length())
+ return;
+ backingText.erase(backingText.begin()+getLowerSelectionBound(), backingText.begin()+getHigherSelectionBound());
+ cursor = getLowerSelectionBound();
+ }
+ for(std::string::iterator iter = newText.begin(), end = newText.end(); iter != end; ++iter)
+ {
+ if(!CharacterValid(*iter))
+ {
+ if(inputType == All)
+ {
+ if(*iter == '\n' || *iter == '\r')
+ *iter = ' ';
+ else
+ *iter = '?';
+ }
+ else
+ *iter = '0';
+ }
+ }
+
+ int regionWidth = Size.X;
+ if(Appearance.icon)
+ regionWidth -= 13;
+ regionWidth -= Appearance.Margin.Left;
+ regionWidth -= Appearance.Margin.Right;
+
+ if(limit!=std::string::npos)
+ {
+ if(limit-backingText.length() >= 0)
+ newText = newText.substr(0, limit-backingText.length());
+ else
+ newText = "";
+ }
+ else if(!multiline && Graphics::textwidth((char*)std::string(backingText+newText).c_str()) > regionWidth)
+ {
+ int pLimit = regionWidth - Graphics::textwidth((char*)backingText.c_str());
+ int cIndex = Graphics::CharIndexAtPosition((char *)newText.c_str(), pLimit, 0);
+
+ if(cIndex > 0)
+ newText = newText.substr(0, cIndex);
+ else
+ newText = "";
+ }
+
+ backingText.insert(cursor, newText);
+ cursor = cursor+newText.length();
+ ClearSelection();
+
+ if(masked)
+ {
+ std::string maskedText = std::string(backingText);
+ std::fill(maskedText.begin(), maskedText.end(), '\x8D');
+ Label::SetText(maskedText);
+ }
+ else
+ {
+ text = backingText;
+ }
+ if(actionCallback)
+ actionCallback->TextChangedCallback(this);
+
+ if(multiline)
+ updateMultiline();
+ updateSelection();
+ if(multiline)
+ TextPosition(textLines);
+ else
+ TextPosition(text);
+
+ if(cursor)
+ {
+ Graphics::PositionAtCharIndex(multiline?((char*)textLines.c_str()):((char*)text.c_str()), cursor, cursorPositionX, cursorPositionY);
+ }
+ else
+ {
+ cursorPositionY = cursorPositionX = 0;
+ }
+}
+
+bool Textbox::CharacterValid(Uint16 character)
+{
+ switch(inputType)
+ {
+ case Number:
+ case Numeric:
+ return (character >= '0' && character <= '9');
+ case All:
+ default:
+ return (character >= ' ' && character < 127);
+ }
+ return false;
+}
+
+void Textbox::Tick(float dt)
+{
+ Label::Tick(dt);
+ if(!IsFocused())
+ {
+ keyDown = 0;
+ characterDown = 0;
+ }
+ if((keyDown || characterDown) && repeatTime <= clock())
+ {
+ OnVKeyPress(keyDown, characterDown, false, false, false);
+ repeatTime = clock()+(0.03 * CLOCKS_PER_SEC);
+ }
+}
+
+void Textbox::OnKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+ keyDown = 0;
+ characterDown = 0;
+}
+
+void Textbox::OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+ characterDown = character;
+ keyDown = key;
+ repeatTime = clock()+(0.3 * CLOCKS_PER_SEC);
+ OnVKeyPress(key, character, shift, ctrl, alt);
+}
+
+void Textbox::OnVKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+ bool changed = false;
+ if(ctrl && key == 'c' && !masked)
+ {
+ copySelection();
+ return;
+ }
+ if(ctrl && key == 'v' && !ReadOnly)
+ {
+ pasteIntoSelection();
+ return;
+ }
+ if(ctrl && key == 'x' && !masked && !ReadOnly)
+ {
+ cutSelection();
+ return;
+ }
+ if(ctrl && key == 'a')
+ {
+ selectAll();
+ return;
+ }
+
+ try
+ {
+ switch(key)
+ {
+ case KEY_HOME:
+ cursor = 0;
+ ClearSelection();
+ break;
+ case KEY_END:
+ cursor = backingText.length();
+ ClearSelection();
+ break;
+ case KEY_LEFT:
+ if(cursor > 0)
+ cursor--;
+ ClearSelection();
+ break;
+ case KEY_RIGHT:
+ if(cursor < backingText.length())
+ cursor++;
+ ClearSelection();
+ break;
+ case KEY_DELETE:
+ if(ReadOnly)
+ break;
+ if(HasSelection())
+ {
+ if(getLowerSelectionBound() < 0 || getHigherSelectionBound() > backingText.length())
+ return;
+ backingText.erase(backingText.begin()+getLowerSelectionBound(), backingText.begin()+getHigherSelectionBound());
+ cursor = getLowerSelectionBound();
+ changed = true;
+ }
+ else if(backingText.length() && cursor < backingText.length())
+ {
+ if(ctrl)
+ backingText.erase(cursor, backingText.length()-cursor);
+ else
+ backingText.erase(cursor, 1);
+ changed = true;
+ }
+ ClearSelection();
+ break;
+ case KEY_BACKSPACE:
+ if(ReadOnly)
+ break;
+ if(HasSelection())
+ {
+ if(getLowerSelectionBound() < 0 || getHigherSelectionBound() > backingText.length())
+ return;
+ backingText.erase(backingText.begin()+getLowerSelectionBound(), backingText.begin()+getHigherSelectionBound());
+ cursor = getLowerSelectionBound();
+ changed = true;
+ }
+ else if(backingText.length() && cursor > 0)
+ {
+ if(ctrl)
+ {
+ backingText.erase(0, cursor);
+ cursor = 0;
+ }
+ else
+ {
+ backingText.erase(cursor-1, 1);
+ cursor--;
+ }
+ changed = true;
+ }
+ ClearSelection();
+ break;
+ }
+ if(CharacterValid(character) && !ReadOnly)
+ {
+ if(HasSelection())
+ {
+ if(getLowerSelectionBound() < 0 || getHigherSelectionBound() > backingText.length())
+ return;
+ backingText.erase(backingText.begin()+getLowerSelectionBound(), backingText.begin()+getHigherSelectionBound());
+ cursor = getLowerSelectionBound();
+ }
+
+ int regionWidth = Size.X;
+ if(Appearance.icon)
+ regionWidth -= 13;
+ regionWidth -= Appearance.Margin.Left;
+ regionWidth -= Appearance.Margin.Right;
+ if((limit==std::string::npos || backingText.length() < limit) && (Graphics::textwidth((char*)std::string(backingText+char(character)).c_str()) <= regionWidth || multiline || limit!=std::string::npos))
+ {
+ if(cursor == backingText.length())
+ {
+ backingText += character;
+ }
+ else
+ {
+ backingText.insert(cursor, 1, (char)character);
+ }
+ cursor++;
+ }
+ changed = true;
+ ClearSelection();
+ }
+ }
+ catch(std::out_of_range &e)
+ {
+ cursor = 0;
+ backingText = "";
+ }
+ if(inputType == Number)
+ {
+ //Remove extra preceding 0's
+ while(backingText[0] == '0' && backingText.length()>1)
+ backingText.erase(backingText.begin());
+ }
+ if(cursor > backingText.length())
+ cursor = backingText.length();
+ if(changed)
+ {
+ if(masked)
+ {
+ std::string maskedText = std::string(backingText);
+ std::fill(maskedText.begin(), maskedText.end(), '\x8D');
+ Label::SetText(maskedText);
+ }
+ else
+ {
+ text = backingText;
+ }
+ if(actionCallback)
+ actionCallback->TextChangedCallback(this);
+ }
+
+ if(multiline)
+ updateMultiline();
+ updateSelection();
+ if(multiline)
+ TextPosition(textLines);
+ else
+ TextPosition(text);
+
+ if(cursor)
+ {
+ Graphics::PositionAtCharIndex(multiline?((char*)textLines.c_str()):((char*)text.c_str()), cursor, cursorPositionX, cursorPositionY);
+ }
+ else
+ {
+ cursorPositionY = cursorPositionX = 0;
+ }
+}
+
+void Textbox::OnMouseClick(int x, int y, unsigned button)
+{
+
+ if(button != BUTTON_RIGHT)
+ {
+ mouseDown = true;
+ cursor = Graphics::CharIndexAtPosition(multiline?((char*)textLines.c_str()):((char*)text.c_str()), x-textPosition.X, y-textPosition.Y);
+ if(cursor)
+ {
+ Graphics::PositionAtCharIndex(multiline?((char*)textLines.c_str()):((char*)text.c_str()), cursor, cursorPositionX, cursorPositionY);
+ }
+ else
+ {
+ cursorPositionY = cursorPositionX = 0;
+ }
+ }
+ Label::OnMouseClick(x, y, button);
+}
+
+void Textbox::OnMouseUp(int x, int y, unsigned button)
+{
+ mouseDown = false;
+ Label::OnMouseUp(x, y, button);
+}
+
+void Textbox::OnMouseMoved(int localx, int localy, int dx, int dy)
+{
+ if(mouseDown)
+ {
+ cursor = Graphics::CharIndexAtPosition(multiline?((char*)textLines.c_str()):((char*)text.c_str()), localx-textPosition.X, localy-textPosition.Y);
+ if(cursor)
+ {
+ Graphics::PositionAtCharIndex(multiline?((char*)textLines.c_str()):((char*)text.c_str()), cursor, cursorPositionX, cursorPositionY);
+ }
+ else
+ {
+ cursorPositionY = cursorPositionX = 0;
+ }
+ }
+ Label::OnMouseMoved(localx, localy, dx, dy);
+}
+
+void Textbox::Draw(const Point& screenPos)
+{
+ Label::Draw(screenPos);
+
+ Graphics * g = Engine::Ref().g;
+ if(IsFocused())
+ {
+ if(border) g->drawrect(screenPos.X, screenPos.Y, Size.X, Size.Y, 255, 255, 255, 255);
+ g->draw_line(screenPos.X+textPosition.X+cursorPositionX, screenPos.Y-2+textPosition.Y+cursorPositionY, screenPos.X+textPosition.X+cursorPositionX, screenPos.Y+9+textPosition.Y+cursorPositionY, 255, 255, 255, 255);
+ }
+ else
+ {
+ if(!text.length())
+ {
+ g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, placeHolder, textColour.Red, textColour.Green, textColour.Blue, 170);
+ }
+ if(border) g->drawrect(screenPos.X, screenPos.Y, Size.X, Size.Y, 160, 160, 160, 255);
+ }
+ if(Appearance.icon)
+ g->draw_icon(screenPos.X+iconPosition.X, screenPos.Y+iconPosition.Y, Appearance.icon);
+}
+
+/*
+Textbox::Textbox(Point position, Point size, std::string textboxText):
+ Component(position, size),
+ text(textboxText),
+ actionCallback(NULL),
+ masked(false),
+ border(true)
+{
+ SetText(textboxText);
+ cursor = text.length();
+}
+
+Textbox::~Textbox()
+{
+ if(actionCallback)
+ delete actionCallback;
+}
+
+void Textbox::TextPosition()
+{
+ if(cursor)
+ {
+ cursorPosition = Graphics::textnwidth((char *)displayText.c_str(), cursor);
+ }
+ else
+ {
+ cursorPosition = 0;
+ }
+ Component::TextPosition(displayText);
+}
+
+void Textbox::SetText(std::string text)
+{
+ cursor = text.length();
+ this->text = text;
+ this->displayText = text;
+ TextPosition();
+}
+
+
+void Textbox::SetDisplayText(std::string text)
+{
+ displayText = text;
+ TextPosition();
+}
+
+std::string Textbox::GetText()
+{
+ return text;
+}
+
+void Textbox::OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
+{
+ bool changed = false;
+ try
+ {
+ switch(key)
+ {
+ case KEY_HOME:
+ cursor = 0;
+ break;
+ case KEY_END:
+ cursor = text.length();
+ break;
+ case KEY_LEFT:
+ if(cursor > 0)
+ cursor--;
+ break;
+ case KEY_RIGHT:
+ if(cursor < text.length())
+ cursor++;
+ break;
+ case KEY_DELETE:
+ if(text.length() && cursor < text.length())
+ {
+ if(ctrl)
+ text.erase(cursor, text.length()-cursor);
+ else
+ text.erase(cursor, 1);
+ changed = true;
+ }
+ break;
+ case KEY_BACKSPACE:
+ if(text.length() && cursor > 0)
+ {
+ if(ctrl)
+ {
+ text.erase(0, cursor);
+ cursor = 0;
+ }
+ else
+ {
+ text.erase(cursor-1, 1);
+ cursor--;
+ }
+ changed = true;
+ }
+ break;
+ }
+ if(character >= ' ' && character < 127)
+ {
+ if(cursor == text.length())
+ {
+ text += character;
+ }
+ else
+ {
+ text.insert(cursor, 1, (char)character);
+ }
+ cursor++;
+ changed = true;
+ }
+ }
+ catch(std::out_of_range &e)
+ {
+ cursor = 0;
+ text = "";
+ }
+ if(changed)
+ {
+ if(masked)
+ {
+ char * tempText = new char[text.length()+1];
+ std::fill(tempText, tempText+text.length(), 0x8d);
+ tempText[text.length()] = 0;
+ displayText = std::string(tempText);
+ delete tempText;
+ }
+ else
+ {
+ displayText = text;
+ }
+ if(actionCallback)
+ actionCallback->TextChangedCallback(this);
+ }
+ TextPosition();
+}
+
+void Textbox::Draw(const Point& screenPos)
+{
+ if(!drawn)
+ {
+ TextPosition();
+ drawn = true;
+ }
+ Graphics * g = Engine::Ref().g;
+ if(IsFocused())
+ {
+ if(border) g->drawrect(screenPos.X, screenPos.Y, Size.X, Size.Y, 255, 255, 255, 255);
+ g->draw_line(screenPos.X+textPosition.X+cursorPosition, screenPos.Y+3, screenPos.X+textPosition.X+cursorPosition, screenPos.Y+12, 255, 255, 255, XRES+BARSIZE);
+ }
+ else
+ {
+ if(border) g->drawrect(screenPos.X, screenPos.Y, Size.X, Size.Y, 160, 160, 160, 255);
+ }
+ g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, displayText, 255, 255, 255, 255);
+ if(Appearance.icon)
+ g->draw_icon(screenPos.X+iconPosition.X, screenPos.Y+iconPosition.Y, Appearance.icon);
+}*/