From 5a71068ba07f42cffbd50324176510d992ebbc5e Mon Sep 17 00:00:00 2001 From: Simon Robertshaw Date: Tue, 26 Jun 2012 22:55:52 +0100 Subject: [PATCH] Textbox now inherits from Label - gets all the fancy text selection features --- src/interface/Label.cpp | 46 +++++++- src/interface/Label.h | 8 +- src/interface/Textbox.cpp | 230 +++++++++++++++++++++++++++++++++++++- src/interface/Textbox.h | 36 +++++- 4 files changed, 312 insertions(+), 8 deletions(-) diff --git a/src/interface/Label.cpp b/src/interface/Label.cpp index a51387848..35b20007e 100644 --- a/src/interface/Label.cpp +++ b/src/interface/Label.cpp @@ -125,20 +125,58 @@ void Label::Tick(float dt) { if(!this->IsFocused() && (selecting || (selectionIndex0 != -1 && selectionIndex1 != -1))) { - selecting = false; - selectionIndex0 = -1; - selectionIndex1 = -1; - updateSelection(); + ClearSelection(); } } +int Label::getLowerSelectionBound() +{ + return (selectionIndex0 > selectionIndex1) ? selectionIndex1 : selectionIndex0; +} + +int Label::getHigherSelectionBound() +{ + return (selectionIndex0 > selectionIndex1) ? selectionIndex0 : selectionIndex1; +} + +bool Label::HasSelection() +{ + if(selectionIndex0 != -1 && selectionIndex1 != -1 && selectionIndex0 != selectionIndex1) + return true; + return false; +} + +void Label::ClearSelection() +{ + selecting = false; + selectionIndex0 = -1; + selectionIndex1 = -1; + updateSelection(); +} + void Label::updateSelection() { std::string currentText; + + if(selectionIndex0 < 0) selectionIndex0 = 0; + if(selectionIndex0 > text.length()) selectionIndex0 = text.length(); + if(selectionIndex1 < 0) selectionIndex1 = 0; + if(selectionIndex1 > text.length()) selectionIndex1 = text.length(); + + if(selectionIndex0 == -1 || selectionIndex1 == -1) + { + selectionXH = -1; + selectionXL = -1; + + textFragments = std::string(currentText); + return; + } + if(multiline) currentText = textLines; else currentText = text; + if(selectionIndex1 > selectionIndex0) { selectionLineH = Graphics::PositionAtCharIndex((char*)currentText.c_str(), selectionIndex1, selectionXH, selectionYH); selectionLineL = Graphics::PositionAtCharIndex((char*)currentText.c_str(), selectionIndex0, selectionXL, selectionYL); diff --git a/src/interface/Label.h b/src/interface/Label.h index 34822bb42..c8c63d48c 100644 --- a/src/interface/Label.h +++ b/src/interface/Label.h @@ -34,6 +34,9 @@ namespace ui void updateMultiline(); void updateSelection(); + + int getLowerSelectionBound(); + int getHigherSelectionBound(); public: //Label(Window* parent_state, std::string labelText); Label(Point position, Point size, std::string labelText); @@ -41,11 +44,14 @@ namespace ui virtual ~Label(); virtual void SetMultiline(bool status); + virtual void SetText(std::string text); virtual std::string GetText(); - void SetTextColour(Colour textColour) { this->textColour = textColour; } + virtual bool HasSelection(); + virtual void ClearSelection(); + void SetTextColour(Colour textColour) { this->textColour = textColour; } virtual void OnMouseClick(int x, int y, unsigned button); virtual void OnMouseUp(int x, int y, unsigned button); diff --git a/src/interface/Textbox.cpp b/src/interface/Textbox.cpp index 4ea5bd013..12a469839 100644 --- a/src/interface/Textbox.cpp +++ b/src/interface/Textbox.cpp @@ -8,6 +8,234 @@ using namespace ui; +Textbox::Textbox(Point position, Point size, std::string textboxText): + Label(position, size, ""), + actionCallback(NULL), + masked(false), + border(true), + mouseDown(false) +{ + SetText(textboxText); + cursor = text.length(); +} + +Textbox::~Textbox() +{ + if(actionCallback) + delete actionCallback; +} + +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); + + if(cursor) + { + cursorPosition = Graphics::textnwidth((char *)text.c_str(), cursor); + } + else + { + cursorPosition = 0; + } +} + +void Textbox::SetDisplayText(std::string newText) +{ + Label::SetText(text); +} + +std::string Textbox::GetText() +{ + return backingText; +} + +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 = backingText.length(); + break; + case KEY_LEFT: + if(cursor > 0) + cursor--; + break; + case KEY_RIGHT: + if(cursor < backingText.length()) + cursor++; + break; + case KEY_DELETE: + 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; + } + break; + case KEY_BACKSPACE: + 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; + } + break; + } + if(character >= ' ' && character < 127) + { + if(HasSelection()) + { + if(getLowerSelectionBound() < 0 || getHigherSelectionBound() > backingText.length()) + return; + backingText.erase(backingText.begin()+getLowerSelectionBound(), backingText.begin()+getHigherSelectionBound()); + cursor = getLowerSelectionBound(); + } + + 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(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(); + TextPosition(text); + + if(cursor) + { + cursorPosition = Graphics::textnwidth((char *)text.c_str(), cursor); + } + else + { + cursorPosition = 0; + } +} + +void Textbox::OnMouseClick(int x, int y, unsigned button) +{ + mouseDown = true; + cursor = Graphics::CharIndexAtPosition((char*)text.c_str(), x-textPosition.X, y-textPosition.Y); + if(cursor) + { + cursorPosition = Graphics::textnwidth((char *)text.c_str(), cursor); + } + else + { + cursorPosition = 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((char*)text.c_str(), localx-textPosition.X, localy-textPosition.Y); + if(cursor) + { + cursorPosition = Graphics::textnwidth((char *)text.c_str(), cursor); + } + else + { + cursorPosition = 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+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); + } +} + +/* Textbox::Textbox(Point position, Point size, std::string textboxText): Component(position, size), text(textboxText), @@ -165,4 +393,4 @@ void Textbox::Draw(const Point& screenPos) 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); -} +}*/ diff --git a/src/interface/Textbox.h b/src/interface/Textbox.h index 551ff5437..120194e81 100644 --- a/src/interface/Textbox.h +++ b/src/interface/Textbox.h @@ -3,7 +3,7 @@ #include -#include "Component.h" +#include "Label.h" #include "Misc.h" namespace ui @@ -15,7 +15,37 @@ public: virtual void TextChangedCallback(ui::Textbox * sender) {} virtual ~TextboxAction() {} }; -class Textbox : public Component + +class Textbox : public Label +{ + friend class TextboxAction; +protected: + bool mouseDown; + bool masked, border; + int cursor, cursorPosition; + TextboxAction *actionCallback; + std::string backingText; +public: + Textbox(Point position, Point size, std::string textboxText); + virtual ~Textbox(); + + virtual void SetDisplayText(std::string text); + virtual void SetText(std::string text); + virtual std::string GetText(); + + void SetBorder(bool border) { this->border = border; }; + void SetHidden(bool hidden) { masked = hidden; } + bool GetHidden() { return masked; } + void SetActionCallback(TextboxAction * action) { actionCallback = action; } + + virtual void OnMouseClick(int x, int y, unsigned button); + virtual void OnMouseUp(int x, int y, unsigned button); + virtual void OnMouseMoved(int localx, int localy, int dx, int dy); + virtual void OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt); + virtual void Draw(const Point& screenPos); +}; + +/*class Textbox : public Component { friend class TextboxAction; protected: @@ -44,6 +74,8 @@ public: virtual void Draw(const Point& screenPos); }; +}*/ } + #endif // TEXTBOX_H