diff --git a/src/Graphics.cpp b/src/Graphics.cpp index fad82dfc2..3b88adb91 100644 --- a/src/Graphics.cpp +++ b/src/Graphics.cpp @@ -452,6 +452,7 @@ int Graphics::textnwidth(char *s, int n) } return x-1; } + void Graphics::textnpos(char *s, int n, int w, int *cx, int *cy) { int x = 0; @@ -508,6 +509,70 @@ int Graphics::textwidthx(char *s, int w) } return n; } + +int Graphics::PositionAtCharIndex(char *s, int charIndex, int & positionX, int & positionY) +{ + int x = 0, y = 0, lines = 1; + for (; *s; s++) + { + if (!charIndex) + break; + if(*s == '\n') { + lines++; + x = 0; + y += FONT_H+2; + charIndex--; + continue; + } else if(*s =='\b') { + if(!s[1]) break; + s++; + charIndex-=2; + continue; + } else if(*s == '\x0F') { + if(!s[1] || !s[2] || !s[3]) break; + s+=3; + charIndex-=4; + continue; + } + x += font_data[font_ptrs[(int)(*(unsigned char *)s)]]; + charIndex--; + } + positionX = x; + positionY = y; + return lines; +} + +int Graphics::CharIndexAtPosition(char *s, int positionX, int positionY) +{ + int x=0, y=0,charIndex=0,cw; + for (; *s; s++) + { + if(*s == '\n') { + x = 0; + y += FONT_H+2; + charIndex++; + continue; + } else if(*s == '\b') { + if(!s[1]) break; + s++; + charIndex+=2; + continue; + } else if (*s == '\x0F') { + if(!s[1] || !s[2] || !s[3]) break; + s+=3; + charIndex+=4; + continue; + } + cw = font_data[font_ptrs[(int)(*(unsigned char *)s)]]; + if ((x+(cw/2) >= positionX && y+FONT_H >= positionY) || y > positionY) + break; + x += cw; + charIndex++; + } + return charIndex; +} + + int Graphics::textposxy(char *s, int width, int w, int h) { int x=0,y=0,n=0,cw, wordlen, charspace; diff --git a/src/Graphics.h b/src/Graphics.h index ef72bf050..8c019e1e0 100644 --- a/src/Graphics.h +++ b/src/Graphics.h @@ -122,6 +122,8 @@ public: static pixel *render_packed_rgb(void *image, int width, int height, int cmp_size); //Font/text metrics + static int CharIndexAtPosition(char *s, int positionX, int positionY); + static int PositionAtCharIndex(char *s, int charIndex, int & positionX, int & positionY); static int textnwidth(char *s, int n); static void textnpos(char *s, int n, int w, int *cx, int *cy); static int textwidthx(char *s, int w); diff --git a/src/dialogues/ConfirmPrompt.cpp b/src/dialogues/ConfirmPrompt.cpp index d9cf94542..30b94a8f2 100644 --- a/src/dialogues/ConfirmPrompt.cpp +++ b/src/dialogues/ConfirmPrompt.cpp @@ -7,7 +7,7 @@ #include "ConfirmPrompt.h" #include "Style.h" -#include "interface/Textblock.h" +#include "interface/Label.h" #include "interface/Button.h" ConfirmPrompt::ConfirmPrompt(std::string title, std::string message, ConfirmDialogueCallback * callback_): @@ -22,13 +22,12 @@ ConfirmPrompt::ConfirmPrompt(std::string title, std::string message, ConfirmDial AddComponent(titleLabel); - ui::Textblock * messageLabel = new ui::Textblock(ui::Point(4, 25), ui::Point(Size.X-8, 60), message); - Graphics::textsize(messageLabel->GetDisplayText().c_str(), width, height); + ui::Label * messageLabel = new ui::Label(ui::Point(4, 25), ui::Point(Size.X-8, -1), message); messageLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; messageLabel->Appearance.VerticalAlign = ui::Appearance::AlignTop; AddComponent(messageLabel); - Size.Y += height; + Size.Y += messageLabel->Size.Y; Position.Y = (ui::Engine::Ref().GetHeight()-Size.Y)/2; class CloseAction: public ui::ButtonAction diff --git a/src/interface/Component.cpp b/src/interface/Component.cpp index 0094cf5cc..a0c55f40a 100644 --- a/src/interface/Component.cpp +++ b/src/interface/Component.cpp @@ -16,6 +16,7 @@ Component::Component(Window* parent_state): Locked(false), Visible(true), textPosition(0, 0), + textSize(0, 0), iconPosition(0, 0), drawn(false) { @@ -30,6 +31,7 @@ Component::Component(Point position, Point size): Locked(false), Visible(true), textPosition(0, 0), + textSize(0, 0), iconPosition(0, 0), drawn(false) { @@ -44,6 +46,7 @@ Component::Component(): Locked(false), Visible(true), textPosition(0, 0), + textSize(0, 0), iconPosition(0, 0), drawn(false) { @@ -62,6 +65,7 @@ void Component::TextPosition(std::string displayText) int textWidth, textHeight = 10; Graphics::textsize((char*)displayText.c_str(), textWidth, textHeight); + textSize.X = textWidth; textSize.Y = textHeight; textHeight-=3; textWidth-=1; if(Appearance.icon) diff --git a/src/interface/Component.h b/src/interface/Component.h index a4fde39db..555be8436 100644 --- a/src/interface/Component.h +++ b/src/interface/Component.h @@ -23,6 +23,7 @@ namespace ui protected: bool drawn; ui::Point textPosition; + ui::Point textSize; ui::Point iconPosition; public: Component(Window* parent_state); diff --git a/src/interface/Label.cpp b/src/interface/Label.cpp index ceb5a4e88..755e3ceb1 100644 --- a/src/interface/Label.cpp +++ b/src/interface/Label.cpp @@ -5,57 +5,199 @@ using namespace ui; -/*Label::Label(Window* parent_state, std::string labelText): - Component(parent_state), - text(labelText), - textPosition(ui::Point(0, 0)), - textVAlign(AlignMiddle), - textHAlign(AlignCentre) -{ - TextPosition(); -}*/ - Label::Label(Point position, Point size, std::string labelText): Component(position, size), text(labelText), - textColour(255, 255, 255) + textColour(255, 255, 255), + selectionIndex0(-1), + selectionIndex1(-1), + selectionXL(-1), + selectionXH(-1), + multiline(false), + selecting(false), + autoHeight(size.Y==-1?true:false), + caret(-1) { } -/*Label::Label(std::string labelText): - Component(), - text(labelText), - textPosition(ui::Point(0, 0)), - textVAlign(AlignMiddle), - textHAlign(AlignCentre) -{ - TextPosition(); -}*/ - Label::~Label() { } +void Label::SetMultiline(bool status) +{ + multiline = status; + if(status) + { + updateMultiline(); + updateSelection(); + } +} + void Label::SetText(std::string text) { this->text = text; + if(multiline) + { + updateMultiline(); + updateSelection(); + } TextPosition(text); } +void Label::updateMultiline() +{ + char * rawText = new char[text.length()+1]; + std::copy(text.begin(), text.end(), rawText); + rawText[text.length()] = 0; + + int lines = 1; + int currentWidth = 0; + char * lastSpace = NULL; + char * currentWord = rawText; + char * nextSpace; + while(true) + { + nextSpace = strchr(currentWord+1, ' '); + if(nextSpace) + nextSpace[0] = 0; + int width = Graphics::textwidth(currentWord); + if(width+currentWidth > Size.X-6) + { + currentWidth = width; + currentWord[0] = '\n'; + lines++; + } + else + currentWidth += width; + if(nextSpace) + nextSpace[0] = ' '; + if(!(currentWord = strchr(currentWord+1, ' '))) + break; + } + if(autoHeight) + { + Size.Y = lines*12; + } + textLines = std::string(rawText); + delete[] rawText; +} + std::string Label::GetText() { return this->text; } +void Label::OnMouseClick(int x, int y, unsigned button) +{ + if(x > textPosition.X && x < textPosition.X + textSize.X && y > textPosition.Y && y < textPosition.Y + textSize.Y) + { + selecting = true; + if(multiline) + selectionIndex0 = Graphics::CharIndexAtPosition((char*)textLines.c_str(), x-textPosition.X, y-textPosition.Y); + else + selectionIndex0 = Graphics::CharIndexAtPosition((char*)text.c_str(), x-textPosition.X, y-textPosition.Y); + selectionIndex1 = selectionIndex0; + + updateSelection(); + } +} + +void Label::OnMouseUp(int x, int y, unsigned button) +{ + selecting = false; +} + +void Label::OnMouseMoved(int localx, int localy, int dx, int dy) +{ + if(selecting) + { + if(multiline) + selectionIndex1 = Graphics::CharIndexAtPosition((char*)textLines.c_str(), localx-textPosition.X, localy-textPosition.Y); + else + selectionIndex1 = Graphics::CharIndexAtPosition((char*)text.c_str(), localx-textPosition.X, localy-textPosition.Y); + updateSelection(); + } +} + +void Label::updateSelection() +{ + std::string currentText; + 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); + + textFragments = std::string(currentText); + textFragments.insert(selectionIndex1, "\x0E"); + textFragments.insert(selectionIndex0, "\x0F\x01\x01\x01"); + } else if(selectionIndex0 > selectionIndex1) { + selectionLineH = Graphics::PositionAtCharIndex((char*)currentText.c_str(), selectionIndex0, selectionXH, selectionYH); + selectionLineL = Graphics::PositionAtCharIndex((char*)currentText.c_str(), selectionIndex1, selectionXL, selectionYL); + + textFragments = std::string(currentText); + textFragments.insert(selectionIndex0, "\x0E"); + textFragments.insert(selectionIndex1, "\x0F\x01\x01\x01"); + } else { + selectionXH = -1; + selectionXL = -1; + + textFragments = std::string(currentText); + } +} + void Label::Draw(const Point& screenPos) { if(!drawn) { - TextPosition(text); + if(multiline) + { + TextPosition(textLines); + updateMultiline(); + updateSelection(); + } + else + TextPosition(text); drawn = true; } Graphics * g = Engine::Ref().g; - g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, text, textColour.Red, textColour.Green, textColour.Blue, 255); + + if(multiline) + { + if(selectionXL != -1 && selectionXH != -1) + { + if(selectionLineH - selectionLineL > 0) + { + g->fillrect(screenPos.X+textPosition.X+selectionXL, (screenPos.Y+textPosition.Y-1)+selectionYL, textSize.X-(selectionXL), 10, 255, 255, 255, 255); + for(int i = 1; i < selectionLineH-selectionLineL; i++) + { + g->fillrect(screenPos.X+textPosition.X, (screenPos.Y+textPosition.Y-1)+selectionYL+(i*12), textSize.X, 10, 255, 255, 255, 255); + } + g->fillrect(screenPos.X+textPosition.X, (screenPos.Y+textPosition.Y-1)+selectionYH, selectionXH, 10, 255, 255, 255, 255); + + } else { + g->fillrect(screenPos.X+textPosition.X+selectionXL, screenPos.Y+selectionYL+textPosition.Y-1, selectionXH-(selectionXL), 10, 255, 255, 255, 255); + } + g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, textFragments, textColour.Red, textColour.Green, textColour.Blue, 255); + } + else + { + g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, textLines, textColour.Red, textColour.Green, textColour.Blue, 255); + } + } else { + if(selectionXL != -1 && selectionXH != -1) + { + g->fillrect(screenPos.X+textPosition.X+selectionXL, screenPos.Y+textPosition.Y-1, selectionXH-(selectionXL), 10, 255, 255, 255, 255); + g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, textFragments, textColour.Red, textColour.Green, textColour.Blue, 255); + } + else + { + g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, text, textColour.Red, textColour.Green, textColour.Blue, 255); + } + } } diff --git a/src/interface/Label.h b/src/interface/Label.h index 08c5fad6f..e154c0e51 100644 --- a/src/interface/Label.h +++ b/src/interface/Label.h @@ -12,20 +12,44 @@ namespace ui class Label : public Component { protected: + std::string textFragments; + std::string textLines; + std::string text; Colour textColour; + int caret; + int selectionIndex0; + int selectionIndex1; + + int selectionXL; + int selectionXH; + int selectionYL; + int selectionYH; + int selectionLineL; + int selectionLineH; + + bool multiline; + bool selecting; + bool autoHeight; + + void updateMultiline(); + void updateSelection(); public: //Label(Window* parent_state, std::string labelText); Label(Point position, Point size, std::string labelText); //Label(std::string labelText); 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 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 Draw(const Point& screenPos); }; } diff --git a/src/interface/Textblock.cpp b/src/interface/Textblock.cpp deleted file mode 100644 index f003a6aee..000000000 --- a/src/interface/Textblock.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Textblock.cpp - * - * Created on: Jan 29, 2012 - * Author: Simon - */ - -#include -#include "Textblock.h" - -using namespace ui; - -Textblock::Textblock(Point position, Point size, std::string textboxText): - Label(position, size, textboxText) -{ - if(size.Y==-1) - autoHeight = true; - else - autoHeight = false; - updateMultiline(); -} - -void Textblock::SetText(std::string text) -{ - this->text = text; - updateMultiline(); -} - -void Textblock::updateMultiline() -{ - char * rawText = new char[text.length()+1]; - std::copy(text.begin(), text.end(), rawText); - rawText[text.length()] = 0; - - int lines = 1; - int currentWidth = 0; - char * lastSpace = NULL; - char * currentWord = rawText; - char * nextSpace; - while(true) - { - nextSpace = strchr(currentWord+1, ' '); - if(nextSpace) - nextSpace[0] = 0; - int width = Graphics::textwidth(currentWord); - if(width+currentWidth > Size.X-6) - { - currentWidth = width; - currentWord[0] = '\n'; - lines++; - } - else - currentWidth += width; - if(nextSpace) - nextSpace[0] = ' '; - if(!(currentWord = strchr(currentWord+1, ' '))) - break; - } - if(autoHeight) - { - Size.Y = lines*12; - } - textLines = std::string(rawText); - delete[] rawText; -} - -void Textblock::Draw(const Point &screenPos) -{ - Graphics * g = ui::Engine::Ref().g; - //g->drawrect(screenPos.X, screenPos.Y, Size.X, Size.Y, textColour.Red, textColour.Green, textColour.Blue, 255); - g->drawtext(screenPos.X+3, screenPos.Y+3, textLines, textColour.Red, textColour.Green, textColour.Blue, 255); -} - -Textblock::~Textblock() { - // TODO Auto-generated destructor stub -} - diff --git a/src/interface/Textblock.h b/src/interface/Textblock.h deleted file mode 100644 index 7a94c7797..000000000 --- a/src/interface/Textblock.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Textblock.h - * - * Created on: Jan 29, 2012 - * Author: Simon - */ - -#ifndef TEXTBLOCK_H_ -#define TEXTBLOCK_H_ - -#include -#include -#include -#include "Label.h" - -namespace ui -{ - -class Textblock: public ui::Label -{ - bool autoHeight; - void updateMultiline(); - std::string textLines; -public: - Textblock(Point position, Point size, std::string textboxText); - virtual void TextPosition() {} - virtual void SetText(std::string text); - virtual std::string GetDisplayText() { return textLines; } - virtual void Draw(const Point& screenPos); - virtual ~Textblock(); -}; -} - -#endif /* TEXTBLOCK_H_ */ diff --git a/src/preview/PreviewView.cpp b/src/preview/PreviewView.cpp index 69229f000..b6b2e02b1 100644 --- a/src/preview/PreviewView.cpp +++ b/src/preview/PreviewView.cpp @@ -5,6 +5,7 @@ * Author: Simon */ +#include #include #include #include "PreviewView.h" @@ -106,10 +107,12 @@ PreviewView::PreviewView(): saveNameLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; saveNameLabel->Appearance.VerticalAlign = ui::Appearance::AlignBottom; AddComponent(saveNameLabel); - saveDescriptionTextblock = new ui::Textblock(ui::Point(5, (YRES/2)+15+14+17), ui::Point((XRES/2)-10, Size.Y-((YRES/2)+15+14+17)-21), ""); - saveDescriptionTextblock->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; saveDescriptionTextblock->Appearance.VerticalAlign = ui::Appearance::AlignTop; - saveDescriptionTextblock->SetTextColour(ui::Colour(180, 180, 180)); - AddComponent(saveDescriptionTextblock); + saveDescriptionLabel = new ui::Label(ui::Point(5, (YRES/2)+15+14+17), ui::Point((XRES/2)-10, Size.Y-((YRES/2)+15+14+17)-21), ""); + saveDescriptionLabel->SetMultiline(true); + saveDescriptionLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; + saveDescriptionLabel->Appearance.VerticalAlign = ui::Appearance::AlignTop; + saveDescriptionLabel->SetTextColour(ui::Colour(180, 180, 180)); + AddComponent(saveDescriptionLabel); authorDateLabel = new ui::Label(ui::Point(5, (YRES/2)+15+14), ui::Point(100, 16), ""); authorDateLabel->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; authorDateLabel->Appearance.VerticalAlign = ui::Appearance::AlignBottom; @@ -231,7 +234,7 @@ void PreviewView::NotifySaveChanged(PreviewModel * sender) votesDown = save->votesDown; saveNameLabel->SetText(save->name); authorDateLabel->SetText("\bgAuthor:\bw " + save->userName + " \bgDate:\bw "); - saveDescriptionTextblock->SetText(save->Description); + saveDescriptionLabel->SetText(save->Description); if(save->Favourite) favButton->Enabled = false; else @@ -261,7 +264,7 @@ void PreviewView::NotifySaveChanged(PreviewModel * sender) votesDown = 0; saveNameLabel->SetText(""); authorDateLabel->SetText(""); - saveDescriptionTextblock->SetText(""); + saveDescriptionLabel->SetText(""); favButton->Enabled = false; } } @@ -278,7 +281,7 @@ void PreviewView::displayComments(int yOffset) int currentY = -yOffset; ui::Label * tempUsername; - ui::Textblock * tempComment; + ui::Label * tempComment; for(int i = 0; i < comments.size(); i++) { int usernameY = currentY+5, commentY; @@ -299,7 +302,8 @@ void PreviewView::displayComments(int yOffset) } commentY = currentY+5; - tempComment = new ui::Textblock(ui::Point((XRES/2) + 5, currentY+5), ui::Point(Size.X-((XRES/2) + 10), -1), comments[i].comment); + tempComment = new ui::Label(ui::Point((XRES/2) + 5, currentY+5), ui::Point(Size.X-((XRES/2) + 10), -1), comments[i].comment); + tempComment->SetMultiline(true); tempComment->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; tempComment->Appearance.VerticalAlign = ui::Appearance::AlignTop; tempComment->SetTextColour(ui::Colour(180, 180, 180)); currentY += tempComment->Size.Y+4; @@ -338,7 +342,7 @@ void PreviewView::NotifyCommentsChanged(PreviewModel * sender) } ui::Label * tempUsername; - ui::Textblock * tempComment; + ui::Label * tempComment; int maxY = 0; for(int i = 0; i < comments.size(); i++) { @@ -346,7 +350,7 @@ void PreviewView::NotifyCommentsChanged(PreviewModel * sender) tempUsername->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; tempUsername->Appearance.VerticalAlign = ui::Appearance::AlignBottom; maxY += 16; - tempComment = new ui::Textblock(ui::Point(0, 0), ui::Point(Size.X-((XRES/2) + 10), -1), comments[i].comment); + tempComment = new ui::Label(ui::Point(0, 0), ui::Point(Size.X-((XRES/2) + 10), -1), comments[i].comment); tempComment->Appearance.HorizontalAlign = ui::Appearance::AlignLeft; tempComment->Appearance.VerticalAlign = ui::Appearance::AlignTop; tempComment->SetTextColour(ui::Colour(180, 180, 180)); diff --git a/src/preview/PreviewView.h b/src/preview/PreviewView.h index 58232bbb0..fbc2adce3 100644 --- a/src/preview/PreviewView.h +++ b/src/preview/PreviewView.h @@ -16,7 +16,6 @@ #include "interface/Button.h" #include "search/Thumbnail.h" #include "interface/Label.h" -#include "interface/Textblock.h" class PreviewModel; class PreviewController; @@ -30,7 +29,7 @@ class PreviewView: public ui::Window { ui::Label * saveNameLabel; ui::Label * authorDateLabel; ui::Label * pageInfo; - ui::Textblock * saveDescriptionTextblock; + ui::Label * saveDescriptionLabel; std::vector comments; std::vector commentComponents; std::vector commentTextComponents;