/* * pawstextbox.cpp - Author: Andrew Craig * * Copyright (C) 2003 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) * * * This program 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 (version 2 of the License) * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ // pawstextbox.cpp: implementation of the pawsTextBox class. // ////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include "pawstextbox.h" #include "pawsmanager.h" #include "pawsprefmanager.h" #include "pawscrollbar.h" #include "util/log.h" #include "util/strutil.h" #include "util/psstring.h" #define BORDER_SIZE 2 // For pawsFadingTextBox ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// pawsTextBox::pawsTextBox() : textX(0), textY(0) { horizAdjust = horizLEFT; vertAdjust = vertTOP; vertical = false; grayed = false; letterSizes = NULL; } pawsTextBox::~pawsTextBox() { if (letterSizes != NULL) delete [] letterSizes; } bool pawsTextBox::Setup( iDocumentNode* node ) { csRef vertAttribute = node->GetAttribute("vertical"); if ( vertAttribute ) SetVertical(strcmp(vertAttribute->GetValue(), "yes") == 0); csRef textNode = node->GetNode( "text" ); if ( textNode ) { csRef fontAdjustAttribute; fontAdjustAttribute = textNode->GetAttribute("horizAdjust"); if ( fontAdjustAttribute ) { csString fontAdjust = fontAdjustAttribute->GetValue(); if (fontAdjust == "CENTRE") HorizAdjust(horizCENTRE); else if (fontAdjust == "RIGHT") HorizAdjust(horizRIGHT); else HorizAdjust(horizLEFT); } fontAdjustAttribute = textNode->GetAttribute("vertAdjust"); if ( fontAdjustAttribute ) { csString fontAdjust = fontAdjustAttribute->GetValue(); if (fontAdjust == "CENTRE") VertAdjust(vertCENTRE); else if (fontAdjust == "BOTTOM") VertAdjust(vertBOTTOM); else VertAdjust(vertTOP); } csRef textAttribute = textNode->GetAttribute("string"); if ( textAttribute ) { SetText(PawsManager::GetSingleton().Translate(textAttribute->GetValue())); } } return true; } void pawsTextBox::CalcTextPos() { int width, height; if (horizAdjust==horizRIGHT || horizAdjust==horizCENTRE || vertAdjust==vertBOTTOM || vertAdjust==vertCENTRE) CalcTextSize(width, height); switch (horizAdjust) { case horizLEFT: textX = 0; break; case horizRIGHT: textX = screenFrame.Width() - width; break; case horizCENTRE: textX = (screenFrame.Width() - width) / 2; break; } switch (vertAdjust) { case vertTOP: textY = 0; break; case vertBOTTOM: textY = screenFrame.Height() - height; break; case vertCENTRE: textY = (screenFrame.Height() - height) / 2; break; } } void pawsTextBox::CalcLetterSizes() { char letterStr[2]; unsigned int i; assert(vertical); if (letterSizes != NULL) delete [] letterSizes; letterSizes = new psPoint [text.Length()]; textWidth = 0; letterStr[1] = '\0'; // Make sure the string is terminated // pos 0 will be filled in later. for (i=0; i < text.Length(); i++) { letterStr[0] = text.GetAt(i); GetFont()->GetDimensions(letterStr, letterSizes[i].x, letterSizes[i].y); textWidth = MAX(textWidth, letterSizes[i].x); } } void pawsTextBox::SetVertical(bool vertical) { this->vertical = vertical; if (vertical) CalcLetterSizes(); else if (letterSizes != NULL) { delete [] letterSizes; letterSizes = NULL; } CalcTextPos(); } void pawsTextBox::Adjust(pawsHorizAdjust horiz, pawsVertAdjust vert) { horizAdjust = horiz; vertAdjust = vert; CalcTextPos(); } void pawsTextBox::HorizAdjust(pawsHorizAdjust horiz) { horizAdjust = horiz; CalcTextPos(); } void pawsTextBox::VertAdjust(pawsVertAdjust vert) { vertAdjust = vert; CalcTextPos(); } void pawsTextBox::CalcTextSize(int & width, int & height) { if (vertical) { unsigned int i; width = 0; height = 0; for (i=0; i < text.Length(); i++) { width = MAX(width, letterSizes[i].x); height += letterSizes[i].y; } } else if (text.GetData() != NULL) { GetFont()->GetDimensions( (const char*)text, width, height ); width+=5; } else { width = 0; height = 0; } } bool pawsTextBox::SelfPopulate( iDocumentNode *node) { if (node->GetAttributeValue("text")) { SetText (node->GetAttributeValue("text")); return true; } else return false; } void pawsTextBox::FormatText( const char *fmt, ... ) { char text[1024]; va_list args; va_start(args, fmt); cs_vsnprintf(text,sizeof(text),fmt,args); va_end(args); SetText( (const char*)text ); } void pawsTextBox::SetText( const char* newText ) { // Make sure any \r characters are replaced by printable \n ones. psString str(newText); str.ReplaceAllSubString("\r", "\n"); text.Replace(str.GetData()); if (vertical) CalcLetterSizes(); CalcTextPos(); } void pawsTextBox::SetSizeByText() { int width, height; CalcTextSize(width, height); SetRelativeFrameSize(width, height); textX = 0; textY = 0; } int pawsTextBox::GetFontColour() { if (grayed) return graphics2D->FindRGB( 150,150,100 ); return pawsWidget::GetFontColour(); } void pawsTextBox::Draw() { pawsWidget::Draw(); if (vertical) { char letterStr[2]; int letterY; letterStr[1] = 0; letterY = textY; for (unsigned int i = 0; i < text.Length(); i++) { letterStr[0] = text.GetAt(i); DrawWidgetText( letterStr , screenFrame.xmin + textX + (textWidth-letterSizes[i].x)/2, screenFrame.ymin + letterY ); letterY += letterSizes[i].y; } } else { DrawWidgetText( (const char*)text, screenFrame.xmin + textX, screenFrame.ymin + textY ); } } void pawsTextBox::OnUpdateData(const char *dataname,PAWSData& value) { // This is called automatically whenever subscribed data is published. if (subscription_format == "percent") { float f = value.GetFloat(); char buff[10]; sprintf(buff,"%.01f%%",f*100); SetText(buff); } else SetText( value.GetStr()); } //---------------------------------------------------------------------------------------- pawsMessageTextBox::pawsMessageTextBox() { topLine = 0; maxLines = 0; CalcLineHeight(); scrollBar = NULL; } pawsMessageTextBox::~pawsMessageTextBox() { Clear(); } void pawsMessageTextBox::Clear() { messages.Empty(); adjusted.Empty(); topLine = 0; if (scrollBar) scrollBar->Hide(); } void pawsMessageTextBox::CalcLineHeight() { int dummy; GetFont()->GetMaxSize( dummy, lineHeight ); lineHeight -=2; } bool pawsMessageTextBox::Setup( iDocumentNode* node ) { CalcLineHeight(); // Create the optional scroll bar here as well but hidden. scrollBar = (pawsScrollBar*) PawsManager::GetSingleton().CreateWidget ( "pawsScrollBar" ); scrollBar->SetParent( this ); scrollBar->SetRelativeFrame( defaultFrame.Width() - 24, 6, 24, defaultFrame.Height() - 12 ); int attach = ATTACH_TOP | ATTACH_BOTTOM | ATTACH_RIGHT; scrollBar->SetAttachFlags( attach ); scrollBar->PostSetup(); scrollBar->SetTickValue( 1.0 ); AddChild( scrollBar ); OnResize(); return true; } bool pawsMessageTextBox::Setup( void ) { CalcLineHeight(); // Create the optional scroll bar here as well but hidden. scrollBar = (pawsScrollBar*) PawsManager::GetSingleton().CreateWidget ( "pawsScrollBar" ); scrollBar->SetParent( this ); scrollBar->SetRelativeFrame( defaultFrame.Width() - 24, 6, 24, defaultFrame.Height() - 12 ); int attach = ATTACH_TOP | ATTACH_BOTTOM | ATTACH_RIGHT; scrollBar->SetAttachFlags( attach ); scrollBar->PostSetup(); scrollBar->SetTickValue( 1.0 ); scrollBar->SetMaxValue(0.0); AddChild( scrollBar ); OnResize(); return true; } void pawsMessageTextBox::Resize() { pawsWidget::Resize(); CalcLineHeight(); adjusted.Empty(); for ( size_t x = 0; x < messages.Length(); x++ ) { SplitMessage( messages[x]->text, messages[x]->colour ); } } void pawsMessageTextBox::OnResize() { int borderOffSize = 4; if ( border ) borderOffSize = 8; int rest = (screenFrame.Height()-borderOffSize) % lineHeight; if (screenFrame.Height() >= borderOffSize+rest) maxLines = (screenFrame.Height()-borderOffSize-rest) / lineHeight; else maxLines = 0; // Re adjust the top line value topLine = (int)adjusted.Length() - (int)maxLines; if ( topLine < 0 ) topLine = 0; if (scrollBar) { scrollBar->SetMaxValue( (float)(adjusted.Length()-maxLines) ); scrollBar->SetCurrentValue( (float)topLine ); if ( maxLines < adjusted.Length() ) { scrollBar->Show(); scrollBar->RecalcScreenPositions(); } else scrollBar->Hide(); } } void pawsMessageTextBox::Draw() { pawsWidget::Draw(); ClipToParent(); int yPos = 0; if ( topLine < 0 ) topLine = 0; for ( size_t x = topLine; x < (topLine+maxLines); x++ ) { if ( x < adjusted.Length() ) { graphics2D->Write( GetFont(), screenFrame.xmin, screenFrame.ymin + yPos*lineHeight, adjusted[x]->colour, -1, (const char*)adjusted[x]->text ); yPos++; } } } bool pawsMessageTextBox::SelfPopulate( iDocumentNode *node) { if (node->GetAttributeValue("text")) { Clear(); AddMessage(node->GetAttributeValue("text")); return true; } return false; } void pawsMessageTextBox::AddMessage( const char* data, int msgColour ) { bool onBottom = false; int oldTopLine = topLine; if ( topLine == (int)scrollBar->GetMaxValue() ) onBottom = true; if ( (size_t)scrollBar->GetMaxValue() < maxLines ) onBottom = true; if ( topLine < 0 ) topLine = 0; // Add it to the main message buffer. MessageLine * msg = new MessageLine; int colour; msg->text = data; if ( msgColour != -1 ) colour = msgColour; else colour = GetFontColour(); msg->colour = colour; messages.Push(msg); SplitMessage( data, colour ); if (scrollBar) { if ( adjusted.Length() > maxLines ) scrollBar->ShowBehind(); else scrollBar->Hide(); } scrollBar->SetMaxValue( (float)(adjusted.Length()-maxLines) ); topLine = (int)adjusted.Length() - (int)maxLines; if ( topLine < 0 ) topLine = 0; if ( !onBottom ) { topLine = oldTopLine; scrollBar->SetCurrentValue( (float)topLine ); } else { scrollBar->SetCurrentValue( float(topLine) ); } } void pawsMessageTextBox::OnUpdateData(const char *dataname,PAWSData& value) { // This is called automatically whenever subscribed data is published. if (overwrite_subscription) Clear(); AddMessage( value.GetStr() ); } void pawsMessageTextBox::ResetScroll() { if (scrollBar) scrollBar->SetCurrentValue(0); } void pawsMessageTextBox::FullScroll() { if(scrollBar) scrollBar->SetCurrentValue(scrollBar->GetMaxValue()); } void pawsMessageTextBox::SplitMessage( const char* newText, int colour ) { int maxWidth; int maxHeight; GetFont()->GetMaxSize( maxWidth, maxHeight ); char* dummy = new char[strlen( newText ) + 1]; char* head = dummy; strcpy( dummy, newText ); int offSet = 40; while ( dummy ) { /// See how many characters can be drawn on a single line. int canDrawLength = GetFont()->GetLength( dummy, screenFrame.Width()-offSet ); /// If it can fit the entire string then return. if ( canDrawLength == (int)strlen( dummy ) ) { csString temp( dummy ); MessageLine* msgLine = new MessageLine; msgLine->text = temp; msgLine->colour = colour; adjusted.Push( msgLine ); break; } // We have to push in a new line to the lines bit. else { // Find out the nearest white space to break the line. int index = canDrawLength; while ( index > 0 && dummy[index] != ' ' ) { index--; } if (index == 0) index = canDrawLength; // Index now points to the whitespace line so we can break it here. csString test; test.Append( dummy, index ); dummy+=index; MessageLine* msgLine = new MessageLine; msgLine->text = test; msgLine->colour = colour; adjusted.Push( msgLine ); } } delete [] head; } bool pawsMessageTextBox::OnScroll( int direction, pawsScrollBar* widget ) { topLine = (int)widget->GetCurrentValue(); return true; } bool pawsMessageTextBox::OnMouseDown( int button, int modifiers, int x, int y ) { if (button == csmbWheelUp) { if (scrollBar) scrollBar->SetCurrentValue(scrollBar->GetCurrentValue() - MESSAGE_TEXTBOX_MOUSE_SCROLL_AMOUNT); return true; } else if (button == csmbWheelDown) { if (scrollBar) scrollBar->SetCurrentValue(scrollBar->GetCurrentValue() + MESSAGE_TEXTBOX_MOUSE_SCROLL_AMOUNT); return true; } return pawsWidget::OnMouseDown( button, modifiers, x ,y); } //--------------------------------------------------------------------------------- pawsEditTextBox::pawsEditTextBox() { start = 0; blink = true; cursorPosition = 0; cursorLine = 0; topLine=0; usedLines=0; multiLine = false; vScrollBar = NULL; topLine = 0; password = 0; clock = CS_QUERY_REGISTRY( PawsManager::GetSingleton().GetObjectRegistry(), iVirtualClock ); blinkTicks = clock->GetCurrentTicks(); // Find the line height; int dummy; GetFont()->GetMaxSize( dummy, lineHeight ); lineHeight -=2; } pawsEditTextBox::~pawsEditTextBox() { } void pawsEditTextBox::SetSizeByText() { int width, height; if (GetFont()!=NULL && text.GetData()!=NULL ) { GetFont()->GetDimensions( text.GetData(), width, height ); SetSize(width, height); } } void pawsEditTextBox::SetPassword( bool pass ) { password = pass; } bool pawsEditTextBox::Setup( iDocumentNode* node ) { csRef multi = node->GetAttribute( "multiline" ); if ( multi ) { csString choice = csString( multi->GetValue() ); if ( choice == "yes" ) SetMultiline(true); } csRef textNode = node->GetNode( "text" ); if (textNode) { csRef stringAttribute = textNode->GetAttribute("string"); if ( stringAttribute ) { SetText( PawsManager::GetSingleton().Translate(stringAttribute->GetValue()) ); } } // Find the line height int dummy; GetFont()->GetMaxSize( dummy, lineHeight ); lineHeight -=2; return true; } bool pawsEditTextBox::SelfPopulate( iDocumentNode *node) { if (node->GetAttributeValue("text")) { SetText(node->GetAttributeValue("text")); return true; } else return false; } void pawsEditTextBox::SetText( const char* newText, bool publish ) { if (publish && subscribedVar) PawsManager::GetSingleton().Publish(subscribedVar, newText); text.Replace( newText ); if (multiLine) { start = 0; cursorPosition = 0; cursorLine = 0; usedLines = 0; topLine = 0; } else { if (newText) cursorPosition = strlen( newText ); else cursorPosition = 0; } } void pawsEditTextBox::OnUpdateData(const char *dataname,PAWSData& value) { // This is called automatically whenever subscribed data is published. SetText( value.GetStr(), false ); } void pawsEditTextBox::Draw() { if ( clock->GetCurrentTicks() - blinkTicks > BLINK_TICKS ) { blink = !blink; blinkTicks = clock->GetCurrentTicks(); } pawsWidget::Draw(); ClipToParent(); if (!multiLine) { if (cursorPosition>text.Length()) cursorPosition=text.Length(); if(start>(int)text.Length()) start=0; if ( text.Length() > 0 ) { // Get the number of characters to draw int maxChars; maxChars = GetFont()->GetLength( text.GetData() + start, screenFrame.Width()); if ( (int)cursorPosition > start + maxChars ) start = (int)cursorPosition - maxChars; if ( start < 0 ) start = 0; /// Make the text the correct length csString tmp ( text.GetData() + start ); tmp.Truncate( maxChars ); if (password) //show astrices instead of text for (unsigned int i=0;iGetDimensions( tmp.GetData(), textWidth, textHeight ); // Get the center int textCenterX = 4; int textCenterY = screenFrame.Height() / 2 - textHeight / 2; DrawWidgetText( tmp.GetData(), screenFrame.xmin + textCenterX, screenFrame.ymin + textCenterY ); if ( blink && hasFocus ) { int cursor = (int)cursorPosition - start; tmp.Truncate( cursor ); //Figure out where to put the cursor. int width, height; GetFont()->GetDimensions( tmp, width, height ); graphics2D->DrawLine( (float)(screenFrame.xmin + textCenterX + width + 1), (float)(screenFrame.ymin + textCenterY), (float)(screenFrame.xmin + textCenterX + width + 1), (float)(screenFrame.ymin + textCenterY+height), GetFontColour() ); } } // End if stored.Length() > 0 else if ( blink && hasFocus ) { graphics2D->DrawLine( (float)screenFrame.xmin + 5, (float)screenFrame.ymin + 4, (float)screenFrame.xmin + 5, (float)screenFrame.ymax - 4, GetFontColour() ); } } else if ( text.Length() > 0 ) { int max = 0; if ( border ) max = 8; if ( vScrollBar->IsVisible() ) max += 24; int maxChars; unsigned int line=0; const char* nextLine=text.GetData(); const char* pos=nextLine; csString thisLine; for (line=0;pos && *nextLine!='\0';line++) { pos =strchr(nextLine,'\n'); thisLine = nextLine; if (pos) { thisLine.Truncate(pos-nextLine); nextLine=pos+1; } if (line thisLine.Length()) continue; // No need to break here because we need to find the maximum number of lines too if (line>maxLines+topLine) continue; // Get the number of characters to draw maxChars = GetFont()->GetLength( thisLine.GetData() + start, screenFrame.Width() - max); // This is the line of text that contains the cursor if (line==cursorLine) { // Calculate number of starting characters that should NOT be drawn if (cursorPosition<=thisLine.Length()) { if ((int)cursorPosition > start + maxChars) start = (int)cursorPosition - maxChars; } else if ((int)thisLine.Length() > start + maxChars) start = (int)thisLine.Length() - maxChars; } if ( start < 0 ) start = 0; csString tmp(thisLine.GetData()+start); tmp.Truncate(maxChars); DrawWidgetText( tmp , screenFrame.xmin + 4, screenFrame.ymin + (line-topLine)*lineHeight ); if (blink && hasFocus && line==cursorLine) // Draw the cursor { if ((int)cursorPosition-start<(int)tmp.Length()) tmp.Truncate(cursorPosition-start); //Figure out where to put the cursor. int width, height; GetFont()->GetDimensions( tmp.GetData(), width, height ); height=lineHeight*(cursorLine-topLine); graphics2D->DrawLine( (float)(screenFrame.xmin + 4 + width + 1), (float)(screenFrame.ymin + height), (float)(screenFrame.xmin + 4 + width + 1), (float)(screenFrame.ymin + height + lineHeight), GetFontColour() ); } } if (*nextLine=='\0') // Single line on its own if (blink && hasFocus && line==cursorLine) // Draw the cursor { //Figure out where to put the cursor. int height=lineHeight*(cursorLine-topLine); graphics2D->DrawLine( (float)(screenFrame.xmin + 4 + 1), (float)(screenFrame.ymin + height), (float)(screenFrame.xmin + 4 + 1), (float)(screenFrame.ymin + height + lineHeight), GetFontColour() ); } // If line doesn't exist, the maximum line counter needs to be decremented if (!pos) line--; vScrollBar->SetCurrentValue( topLine ); if (usedLines != line) { usedLines = line; if ( usedLines > maxLines ) { vScrollBar->Show(); vScrollBar->SetMaxValue( usedLines ); } else vScrollBar->Hide(); } } else if ( blink && hasFocus ) // Multiline, no text and blinking { graphics2D->DrawLine( (float)screenFrame.xmin + 5, (float)screenFrame.ymin, (float)screenFrame.xmin + 5, (float)screenFrame.ymin + lineHeight, GetFontColour() ); } } bool pawsEditTextBox::OnKeyDown( int code, int key, int modifiers ) { bool changed = false; blink = true; csString curLine; int startLoc=0; size_t oldLength=text.Length(); // Find the line the cursor is on if (multiLine && text.Length()>0) { const char* next=NULL; const char* pos=text.GetData(); for (unsigned int line=0;line=curLine.Length()) break; if ( cursorPosition != (size_t)-1 ) { if ( cursorPosition - start < 5 ) start = (int)cursorPosition - 5; if ( start < 0 ) start = 0; if ( curLine.Length() > 1 ) { if ( cursorPosition == curLine.Length() ) { curLine.Truncate( curLine.Length() - 1 ); } else { csString tmp( curLine.GetData() ); tmp.Truncate( cursorPosition ); tmp.Append( curLine.GetData() + cursorPosition + 1 ); curLine.Replace( tmp ); } } else { curLine.Clear(); } } //endif cursor position > 0 else if (cursorLine != 0) { startLoc--; text.DeleteAt(startLoc); // Delete newline character cursorLine--; if (cursorLinecurLine.Length()) cursorPosition=curLine.Length(); if ( cursorPosition > 0 ) { cursorPosition--; if ( cursorPosition - start < 5 ) start = (int)cursorPosition - 5; if ( start < 0 ) start = 0; if ( curLine.Length() > 1 ) { if ( cursorPosition == curLine.Length() ) { curLine.Truncate( curLine.Length() - 1 ); } else { csString tmp( curLine.GetData() ); tmp.Truncate( cursorPosition ); tmp.Append( curLine.GetData() + cursorPosition + 1 ); curLine.Replace( tmp ); } } else { curLine.Clear(); } } //endif cursor position > 0 else if (cursorLine != 0) { startLoc--; text.DeleteAt(startLoc); // Delete newline character cursorLine--; if (cursorLinecurLine.Length()) cursorPosition=curLine.Length(); if ( cursorPosition > 0 ) cursorPosition--; else if (cursorLine != 0) { cursorLine--; if (cursorLinecurLine.Length()) cursorPosition=curLine.Length(); if ( cursorPosition < curLine.Length() ) { cursorPosition++; } else if (cursorLinetopLine+maxLines) topLine++; } break; case CSKEY_UP: if (multiLine && cursorLine>0) cursorLine--; if (cursorLinetopLine+maxLines) topLine++; break; case CSKEY_END: cursorPosition=1024; break; case CSKEY_HOME: cursorPosition=0; start=0; break; default: if ( !isprint((unsigned char)key) && !(multiLine && key==CSKEY_ENTER)) { break; } if ( key == CSKEY_ALT || key == CSKEY_CTRL ) { break; } if ( cursorPosition >= curLine.Length() ) { curLine.Append( (char)key ); } else { curLine.Insert( cursorPosition, (char)key ); } if (key == CSKEY_ENTER) { cursorLine++; cursorPosition=0; start=0; if (cursorLine>topLine+maxLines) topLine++; } else cursorPosition++; changed = true; } if (oldLength) text.DeleteAt(startLoc,oldLength); text.Insert(startLoc,curLine); if (changed) { if (subscribedVar) PawsManager::GetSingleton().Publish(subscribedVar, text); parent->OnChange(this); } if ( isprint((unsigned char)key) ) return true; if (!(multiLine && code== CSKEY_ENTER)) { pawsWidget::OnKeyDown( code, key, modifiers ); } return true; } void pawsEditTextBox::Clear() { start = 0; cursorPosition = 0; cursorLine = 0; usedLines = 0; topLine = 0; text.Clear(); } bool pawsEditTextBox::OnMouseDown( int button, int modifiers, int x, int y ) { if (button == csmbWheelUp) { if (vScrollBar) vScrollBar->SetCurrentValue(vScrollBar->GetCurrentValue() - EDIT_TEXTBOX_MOUSE_SCROLL_AMOUNT); return true; } else if (button == csmbWheelDown) { if (vScrollBar) vScrollBar->SetCurrentValue(vScrollBar->GetCurrentValue() + EDIT_TEXTBOX_MOUSE_SCROLL_AMOUNT); return true; } x -= (screenFrame.xmin+4); // Adjust x to be relative to the text box int textWidth; int dummy; //Force the cursor to blink blink = true; // Find the line the mouse is on and move the cursor there if (multiLine) cursorLine=(y-screenFrame.ymin)/lineHeight+topLine; if (cursorLine>usedLines) cursorLine=(unsigned int)usedLines; // Basic comparisons to see if it was clicked after all the text or before all the text or neither if (x<=0) { start=0; cursorPosition=0; return true; } csString curLine; // Find the line the cursor is on if (multiLine && text.Length()>0) { const char* next=NULL; const char* pos=text.GetData(); for (unsigned int line=0;line 0 ) { GetFont()->GetDimensions(curLine.GetData(),textWidth,dummy); if (x>=textWidth) { cursorPosition=text.Length(); return true; } } //Find exact letter mouse was clicked on int xlast; int xlast2=0; const char *c; char temp[2]; temp[1]='\0'; c=temp; for (unsigned int i=0;iGetDimensions(c, textWidth, dummy); xlast2+=textWidth; if (x >= xlast && x < xlast2) { cursorPosition=i; break; } } return pawsWidget::OnMouseDown( button, modifiers, x ,y); } bool pawsEditTextBox::OnScroll( int direction, pawsScrollBar* widget ) { topLine = (int)widget->GetCurrentValue(); return true; } void pawsEditTextBox::SetMultiline(bool multi) { if (multiLine && multi == false) { multiLine=multi; DeleteChild(vScrollBar); cursorLine=0; return; } else if ((multiLine && multi == true) || (!multiLine && multi == false)) return; multiLine=true; // Define the total number of total allowable drawing lines. int borderOffSize = 0; if ( border ) borderOffSize = 8; cursorLine=0; maxLines = (screenFrame.Height()-borderOffSize) / (lineHeight) - 1; // Create the optional scroll bar here as well but hidden. vScrollBar = (pawsScrollBar*) PawsManager::GetSingleton().CreateWidget ( "pawsScrollBar" ); AddChild( vScrollBar ); vScrollBar->SetRelativeFrame( screenFrame.Width() - 24, 0, 24, screenFrame.Height()); int attach = ATTACH_TOP | ATTACH_BOTTOM | ATTACH_RIGHT; vScrollBar->SetAttachFlags( attach ); vScrollBar->UseBorder(); vScrollBar->PostSetup(); vScrollBar->SetTickValue( 1.0 ); vScrollBar->Hide(); } ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// pawsMultiLineTextBox::pawsMultiLineTextBox() { scrollBar = 0; startLine = 0; canDrawLines = 0; maxHeight = 0; maxWidth = 0; } pawsMultiLineTextBox::~pawsMultiLineTextBox() { } bool pawsMultiLineTextBox::Setup( iDocumentNode* node ) { csRef textNode = node->GetNode( "text" ); if ( textNode ) { csRef textAttribute = textNode->GetAttribute("string"); if ( textAttribute ) { SetText( textAttribute->GetValue() ); } } return true; } void pawsMultiLineTextBox::OrganizeText( const char* newText ) { csString text(newText); // Check if we end with \n // Chomp if we do if (text.Length() > 0) { if (text.GetAt(text.Length()-1) == '\n') { text = text.Slice(0,text.Length()-1); } } startLine = 0; GetFont()->GetMaxSize( maxWidth, maxHeight ); canDrawLines = screenFrame.Height() / maxHeight; char* dummy = new char[text.Length() + 1]; char* head = dummy; if (text.Length () > 0) strcpy( dummy, text ); else dummy[0] = 0; int offSet = 0; if ( usingScrollBar ) offSet = 36; while ( dummy ) { /// See how many characters can be drawn on a single line. int canDrawLength = GetFont()->GetLength( dummy, screenFrame.Width()-offSet ); // Check for linebreaks const char* pos=strchr(dummy,'\n'); csString loopStr(dummy); if (pos) { while(pos) { csString temp(loopStr.GetData()); csString temp2(loopStr.GetData()); size_t pos1=temp.FindFirst('\n'); temp= temp.Slice(0,pos1); temp2= temp2.Slice(pos1+1,(temp2.Length() - pos1-1)); OrganizeText(temp.GetData()); if (temp2.Length()) { loopStr = temp2; pos=strchr(loopStr.GetData(),'\n'); if (!pos) { OrganizeText(temp2.GetData()); } } else break; } break; } /// If it can fit the entire string then return. if ( canDrawLength == (int)strlen( dummy ) ) { csString temp( dummy ); lines.Push( temp ); break; } // We have to push in a new line to the lines bit. else { // Find out the nearest white space to break the line. int index = canDrawLength; while ( index > 0 && dummy[index] != ' ' ) { index--; } if (index == 0) index = canDrawLength; // Index now points to the whitespace line so we can break it here. csString test; test.Append( dummy, index+1 ); dummy+=index+1; lines.Push( test ); } } delete [] head; } void pawsMultiLineTextBox::SetText( const char* newText ) { lines.Empty(); psString str(newText); size_t pos = str.FindSubString("\r"); while(pos != (size_t)-1) { str = str.Slice(0,pos) + "\n" + str.Slice(pos+2,str.Length()-pos-2); pos = str.FindSubString("\r"); } usingScrollBar = false; if ( scrollBar ) scrollBar->Hide(); OrganizeText( str.GetData() ); if ( canDrawLines > lines.Length() ) canDrawLines = lines.Length(); else { usingScrollBar = true; lines.Empty(); OrganizeText( str.GetData() ); if ( !scrollBar ) { // Create the optional scroll bar here as well but hidden. scrollBar = (pawsScrollBar*) PawsManager::GetSingleton().CreateWidget ( "pawsScrollBar" ); scrollBar->SetParent( this ); scrollBar->SetRelativeFrame( defaultFrame.Width() - 40, 6, 24, defaultFrame.Height() - 12 ); scrollBar->PostSetup(); scrollBar->SetTickValue( 1.0 ); AddChild( scrollBar ); } scrollBar->Show(); scrollBar->SetMaxValue(lines.Length() - canDrawLines ); scrollBar->SetCurrentValue(0); } startLine = 0; text.Replace( str.GetData() ); } void pawsMultiLineTextBox::OnUpdateData(const char *dataname,PAWSData& value) { // This is called automatically whenever subscribed data is published. SetText( value.GetStr() ); } void pawsMultiLineTextBox::Draw() { pawsWidget::Draw(); pawsWidget::ClipToParent(); int drawX = screenFrame.xmin; int drawY = screenFrame.ymin; if (!maxHeight && GetFont()) GetFont()->GetMaxSize( maxWidth, maxHeight ); if (!canDrawLines && maxHeight) canDrawLines = screenFrame.Height() / maxHeight; for (size_t x = startLine; x < (startLine+canDrawLines); x++ ) { if ( x >= lines.Length() ) return; DrawWidgetText( (const char*)lines[x], drawX, drawY); drawY+=maxHeight; } } bool pawsMultiLineTextBox::OnScroll( int direction, pawsScrollBar* widget ) { startLine = (int)widget->GetCurrentValue(); return true; } bool pawsMultiLineTextBox::OnMouseDown( int button, int modifiers, int x, int y ) { if (button == csmbWheelUp) { if (scrollBar) scrollBar->SetCurrentValue(scrollBar->GetCurrentValue() - MULTILINE_TEXTBOX_MOUSE_SCROLL_AMOUNT); return true; } else if (button == csmbWheelDown) { if (scrollBar) scrollBar->SetCurrentValue(scrollBar->GetCurrentValue() + MULTILINE_TEXTBOX_MOUSE_SCROLL_AMOUNT); return true; } return pawsWidget::OnMouseDown( button, modifiers, x ,y); } pawsFadingTextBox::pawsFadingTextBox() { start = 0; color = scolor = 0; ymod = 0; firstFont = NULL; font = NULL; } void pawsFadingTextBox::SetText(const char* newtext, iFont* font1,iFont* font2, int color,int time,int fadetime) { // Seperate the first and the rest text = newtext; first = "XXX"; first.SetAt(0,text.GetAt(0)); first.SetAt(1,0); text = text.Slice(1,text.Length() -1); // Add the other stuff firstFont = font1; font = font2; start = csGetTicks(); //Start the effect this->org_color = color; this->time = time; this->fadetime = fadetime; } void pawsFadingTextBox::GetSize(int &w, int &h) { int iw=0,ih=0; int dummy=0; // Get the sizes firstFont->GetDimensions(first,iw,ih,dummy); font->GetDimensions(text,w,h,dummy); if(iw > w) // Stretch the size to have space for the first letter w = iw; if(ih > h) h = ih; w += BORDER_SIZE*2; // Add the border pixels h += BORDER_SIZE*2; // Add the border pixels } void pawsFadingTextBox::Draw() { if(!text || text.Length() == 0) return; // Calculate fading int alpha = 0; if(csGetTicks() > start + time) { int elapsed = csGetTicks() - (start + time); float multi = float(elapsed) / float(fadetime); alpha = int(multi * float(255)); } int r=0,g=0,b=0,a=0; graphics2D->GetRGB(org_color,r,g,b,a); a -= alpha; // Apply alpha if(a < 1) { // Destroy the widget DeleteYourself(); return; } int newymod = alpha / 2; MoveDelta(0,newymod - ymod); // Move downwards ymod = newymod; // Prepare to paint the text color = graphics2D->FindRGB(r,g,b,a); // Color on text scolor = graphics2D->FindRGB(0,0,0,a); // Color on "shadow" int iw=0; // Width on the first letter int dummy=-1; // Used as return value for 'desc' and the height firstFont->GetDimensions(first,iw,dummy,dummy); // Draw //ClipToParent(); DrawBorderText(first,firstFont,0); DrawBorderText(text,font,iw); } void pawsFadingTextBox::Fade() { if(start < csGetTicks() - time) // Already fading? return; start = csGetTicks() - time; } void pawsFadingTextBox::DrawBorderText(const char* text, iFont* font,int x) { int y = 0; x += screenFrame.xmin; y += screenFrame.ymin; graphics2D->Write(font,x+BORDER_SIZE,y+BORDER_SIZE,scolor,-1,text); // Right down graphics2D->Write(font,x-BORDER_SIZE,y+BORDER_SIZE,scolor,-1,text); // Left down graphics2D->Write(font,x+BORDER_SIZE,y-BORDER_SIZE,scolor,-1,text); // Right up graphics2D->Write(font,x-BORDER_SIZE,y-BORDER_SIZE,scolor,-1,text); // Left up graphics2D->Write(font,x,y+BORDER_SIZE,scolor,-1,text); // Down graphics2D->Write(font,x,y-BORDER_SIZE,scolor,-1,text); // Up graphics2D->Write(font,x+BORDER_SIZE,y,scolor,-1,text); // Right graphics2D->Write(font,x-BORDER_SIZE,y,scolor,-1,text); // Left // Draw the letter graphics2D->Write(font,x,y,color,-1,text); }