This repository has been archived on 2025-03-20. You can view files and clone it, but cannot push or open issues or pull requests.
The-Powder-Toy/src/gui/interface/Label.cpp

424 lines
10 KiB
C++

#include <string>
#include "Config.h"
#include "Format.h"
#include "Point.h"
#include "Label.h"
#include "Keys.h"
#include "ContextMenu.h"
using namespace ui;
Label::Label(Point position, Point size, std::string labelText):
Component(position, size),
text(labelText),
textColour(255, 255, 255),
selectionIndex0(-1),
selectionIndex1(-1),
selectionXL(-1),
selectionXH(-1),
multiline(false),
selecting(false),
autoHeight(size.Y==-1?true:false)
{
menu = new ContextMenu(this);
menu->AddItem(ContextMenuItem("Copy", 0, true));
}
Label::~Label()
{
}
void Label::SetMultiline(bool status)
{
multiline = status;
if(status)
{
updateMultiline();
updateSelection();
TextPosition(textLines);
}
else
{
TextPosition(text);
}
}
void Label::SetText(std::string text)
{
this->text = text;
if(multiline)
{
updateMultiline();
updateSelection();
TextPosition(textLines);
}
else
{
TextPosition(text);
}
}
void Label::AutoHeight()
{
bool oldAH = autoHeight;
autoHeight = true;
updateMultiline();
autoHeight = oldAH;
}
void Label::updateMultiline()
{
int lines = 1;
if (text.length()>0)
{
char * rawText = new char[text.length()+1];
std::copy(text.begin(), text.end(), rawText);
rawText[text.length()] = 0;
char c, pc = 0;
int charIndex = 0;
int wordWidth = 0;
int lineWidth = 0;
char * wordStart = NULL;
while ((c = rawText[charIndex++]))
{
switch(c)
{
case ' ':
lineWidth += Graphics::CharWidth(c);
lineWidth += wordWidth;
wordWidth = 0;
break;
case '\n':
lineWidth = wordWidth = 0;
lines++;
break;
default:
wordWidth += Graphics::CharWidth(c);
break;
}
if (pc == ' ')
{
wordStart = &rawText[charIndex-2];
}
if ((c != ' ' || pc == ' ') && lineWidth + wordWidth >= Size.X-(Appearance.Margin.Left+Appearance.Margin.Right))
{
if (wordStart && *wordStart)
{
*wordStart = '\n';
if (lineWidth != 0)
lineWidth = wordWidth;
}
else if (!wordStart)
{
rawText[charIndex-1] = '\n';
lineWidth = 0;
}
wordWidth = 0;
wordStart = 0;
lines++;
}
pc = c;
}
if (autoHeight)
{
Size.Y = lines*12+3;
}
textLines = std::string(rawText);
delete[] rawText;
/*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-(Appearance.Margin.Left+Appearance.Margin.Right))
{
currentWidth = width;
if(currentWord!=rawText)
{
currentWord[0] = '\n';
lines++;
}
}
else
currentWidth += width;
if(nextSpace)
nextSpace[0] = ' ';
if(!currentWord[0] || !currentWord[1] || !(currentWord = strchr(currentWord+1, ' ')))
break;
}
if(autoHeight)
{
Size.Y = lines*12;
}
textLines = std::string(rawText);
delete[] rawText;*/
}
else
{
if (autoHeight)
{
Size.Y = 15;
}
textLines = std::string("");
}
}
std::string Label::GetText()
{
return this->text;
}
void Label::OnContextMenuAction(int item)
{
switch(item)
{
case 0:
copySelection();
break;
}
}
void Label::OnMouseClick(int x, int y, unsigned button)
{
if(button == BUTTON_RIGHT)
{
if(menu)
menu->Show(GetScreenPos() + ui::Point(x, y));
}
else
{
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::copySelection()
{
std::string currentText = text;
std::string copyText;
if (selectionIndex1 > selectionIndex0)
copyText = currentText.substr(selectionIndex0, selectionIndex1-selectionIndex0).c_str();
else if(selectionIndex0 > selectionIndex1)
copyText = currentText.substr(selectionIndex1, selectionIndex0-selectionIndex1).c_str();
else if (!currentText.length())
return;
else
copyText = currentText.c_str();
ClipboardPush(format::CleanString(copyText, false, true, false));
}
void Label::OnMouseUp(int x, int y, unsigned button)
{
selecting = false;
}
void Label::OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
{
if(ctrl && key == 'c')
{
copySelection();
}
}
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::Tick(float dt)
{
if(!this->IsFocused() && (selecting || (selectionIndex0 != -1 && selectionIndex1 != -1)))
{
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 > (int)text.length()) selectionIndex0 = text.length();
if (selectionIndex1 < 0) selectionIndex1 = 0;
if (selectionIndex1 > (int)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);
textFragments = std::string(currentText);
//textFragments.insert(selectionIndex1, "\x0E");
//textFragments.insert(selectionIndex0, "\x0F\x01\x01\x01");
textFragments.insert(selectionIndex1, "\x01");
textFragments.insert(selectionIndex0, "\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");
textFragments.insert(selectionIndex0, "\x01");
textFragments.insert(selectionIndex1, "\x01");
} else {
selectionXH = -1;
selectionXL = -1;
textFragments = std::string(currentText);
}
if(displayText.length())
{
displayText = tDisplayText;
if(selectionIndex1 > selectionIndex0) {
int tSelectionIndex1 = Graphics::CharIndexAtPosition((char*)displayText.c_str(), selectionXH, selectionYH);
int tSelectionIndex0 = Graphics::CharIndexAtPosition((char*)displayText.c_str(), selectionXL, selectionYL);
displayText.insert(tSelectionIndex1, "\x01");
displayText.insert(tSelectionIndex0, "\x01");
} else if(selectionIndex0 > selectionIndex1) {
int tSelectionIndex0 = Graphics::CharIndexAtPosition((char*)displayText.c_str(), selectionXH, selectionYH);
int tSelectionIndex1 = Graphics::CharIndexAtPosition((char*)displayText.c_str(), selectionXL, selectionYL);
displayText.insert(tSelectionIndex0, "\x01");
displayText.insert(tSelectionIndex1, "\x01");
}
}
}
void Label::SetDisplayText(std::string newText)
{
ClearSelection();
displayText = tDisplayText = newText;
}
void Label::Draw(const Point& screenPos)
{
if(!drawn)
{
if(multiline)
{
TextPosition(textLines);
updateMultiline();
updateSelection();
}
else
TextPosition(text);
drawn = true;
}
Graphics * g = Engine::Ref().g;
std::string cDisplayText = displayText;
if(!cDisplayText.length())
{
if(selectionXL != -1 && selectionXH != -1)
{
cDisplayText = textFragments;
}
else
{
if(multiline)
cDisplayText = textLines;
else
cDisplayText = text;
}
}
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, cDisplayText, textColour.Red, textColour.Green, textColour.Blue, 255);
}
else
{
g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, cDisplayText, 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, cDisplayText, textColour.Red, textColour.Green, textColour.Blue, 255);
}
else
{
g->drawtext(screenPos.X+textPosition.X, screenPos.Y+textPosition.Y, cDisplayText, textColour.Red, textColour.Green, textColour.Blue, 255);
}
}
}