2016-12-14 19:20:26 +01:00
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers , whose names
* are too numerous to list here . Please refer to the COPYRIGHT
* file distributed with this source distribution .
*
* 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 ; either version 2
* of the License , or ( at your option ) any later version .
*
* 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 . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*/
2017-01-30 10:10:22 +01:00
# include "graphics/macgui/macfontmanager.h"
2016-12-14 19:20:26 +01:00
# include "graphics/macgui/mactext.h"
2017-01-30 10:10:22 +01:00
# include "graphics/macgui/macwindowmanager.h"
2016-12-14 19:37:45 +01:00
# include "graphics/font.h"
2016-12-14 19:20:26 +01:00
namespace Graphics {
2017-01-30 10:10:22 +01:00
const Font * MacFontRun : : getFont ( ) {
if ( font )
return font ;
MacFont macFont = MacFont ( fontId , fontSize , textSlant ) ;
font = wm - > _fontMan - > getFont ( macFont ) ;
return font ;
}
2017-08-01 09:55:20 +02:00
const Common : : String MacFontRun : : toString ( ) {
2019-12-11 18:11:55 +01:00
return Common : : String : : format ( " \001 \016 %04x%02x%04x%04x%04x%04x " , fontId , textSlant , fontSize , palinfo1 , palinfo2 , palinfo3 ) ;
2017-08-01 09:55:20 +02:00
}
2017-04-30 00:18:23 +02:00
2018-08-05 23:07:55 +03:00
MacText : : ~ MacText ( ) {
delete _surface ;
2017-04-30 00:18:23 +02:00
}
2019-10-18 17:20:02 +02:00
MacText : : MacText ( Common : : U32String s , MacWindowManager * wm , const MacFont * macFont , int fgcolor , int bgcolor , int maxWidth , TextAlign textAlignment , int interlinear ) {
2016-12-14 19:20:26 +01:00
_str = s ;
2017-01-29 14:19:28 +01:00
_wm = wm ;
2017-04-30 00:14:23 +02:00
_macFont = macFont ;
2016-12-14 20:09:08 +01:00
_fgcolor = fgcolor ;
_bgcolor = bgcolor ;
2017-02-04 16:29:24 +01:00
_maxWidth = maxWidth ;
2017-01-17 22:15:43 +11:00
_textMaxWidth = 0 ;
2017-01-31 23:14:03 +01:00
_textMaxHeight = 0 ;
2016-12-20 21:18:15 +01:00
_surface = nullptr ;
2017-01-17 22:15:43 +11:00
_textAlignment = textAlignment ;
2017-04-30 23:02:39 +02:00
_interLinear = interlinear ;
2016-12-14 19:37:45 +01:00
2017-04-30 00:14:23 +02:00
if ( macFont ) {
2019-10-19 17:43:47 +02:00
_defaultFormatting = MacFontRun ( _wm , macFont - > getId ( ) , macFont - > getSlant ( ) , macFont - > getSize ( ) , 0 , 0 , 0 ) ;
2017-04-30 00:14:23 +02:00
_defaultFormatting . font = wm - > _fontMan - > getFont ( * macFont ) ;
} else {
_defaultFormatting . font = NULL ;
}
2017-01-30 10:10:22 +01:00
_defaultFormatting . wm = wm ;
2017-01-30 22:58:02 +01:00
_currentFormatting = _defaultFormatting ;
2017-01-31 23:14:03 +01:00
2017-08-02 11:20:35 +02:00
if ( ! _str . empty ( ) )
splitString ( _str ) ;
2017-01-31 23:14:03 +01:00
recalcDims ( ) ;
_fullRefresh = true ;
2016-12-14 19:37:45 +01:00
}
2019-10-18 17:20:02 +02:00
MacText : : MacText ( const Common : : String & s , MacWindowManager * wm , const MacFont * macFont , int fgcolor , int bgcolor , int maxWidth , TextAlign textAlignment , int interlinear ) {
_str = Common : : U32String ( s ) ;
_wm = wm ;
_macFont = macFont ;
_fgcolor = fgcolor ;
_bgcolor = bgcolor ;
_maxWidth = maxWidth ;
_textMaxWidth = 0 ;
_textMaxHeight = 0 ;
_surface = nullptr ;
_textAlignment = textAlignment ;
_interLinear = interlinear ;
if ( macFont ) {
2019-10-19 17:43:47 +02:00
_defaultFormatting = MacFontRun ( _wm , macFont - > getId ( ) , macFont - > getSlant ( ) , macFont - > getSize ( ) , 0 , 0 , 0 ) ;
2019-10-18 17:20:02 +02:00
_defaultFormatting . font = wm - > _fontMan - > getFont ( * macFont ) ;
} else {
_defaultFormatting . font = NULL ;
}
_defaultFormatting . wm = wm ;
_currentFormatting = _defaultFormatting ;
if ( ! _str . empty ( ) )
splitString ( _str ) ;
recalcDims ( ) ;
_fullRefresh = true ;
}
2017-08-02 21:08:46 +02:00
void MacText : : setMaxWidth ( int maxWidth ) {
_maxWidth = maxWidth ;
2017-08-02 21:13:14 +02:00
_textLines . clear ( ) ;
if ( ! _str . empty ( ) ) {
splitString ( _str ) ;
recalcDims ( ) ;
_fullRefresh = true ;
}
2017-08-02 21:08:46 +02:00
}
2019-12-11 18:11:55 +01:00
static const Common : : U32String : : value_type * readHex ( uint16 * res , const Common : : U32String : : value_type * s , int len ) {
* res = 0 ;
for ( int i = 0 ; i < len ; i + + ) {
char b = ( char ) * s + + ;
2019-12-14 00:37:45 +01:00
* res < < = 4 ;
2019-12-11 18:11:55 +01:00
if ( tolower ( b ) > ' a ' )
2019-12-15 10:56:26 +01:00
* res | = tolower ( b ) - ' a ' + 10 ;
2019-12-11 18:11:55 +01:00
else
* res | = tolower ( b ) - ' 0 ' ;
}
return s ;
}
2019-10-18 17:20:02 +02:00
void MacText : : splitString ( Common : : U32String & str ) {
const Common : : U32String : : value_type * s = str . c_str ( ) ;
2016-12-14 19:37:45 +01:00
2019-10-18 17:20:02 +02:00
Common : : U32String tmp ;
2016-12-19 09:26:56 +01:00
bool prevCR = false ;
2016-12-14 19:37:45 +01:00
2017-01-31 09:52:51 +01:00
if ( _textLines . empty ( ) ) {
_textLines . resize ( 1 ) ;
2017-01-31 22:35:06 +01:00
_textLines [ 0 ] . chunks . push_back ( _defaultFormatting ) ;
2017-01-31 09:52:51 +01:00
}
int curLine = _textLines . size ( ) - 1 ;
2017-01-31 22:35:06 +01:00
int curChunk = _textLines [ curLine ] . chunks . size ( ) - 1 ;
2017-01-31 09:52:51 +01:00
bool nextChunk = false ;
2017-02-03 18:32:44 +01:00
MacFontRun previousFormatting ;
2017-01-30 22:58:02 +01:00
2016-12-14 19:37:45 +01:00
while ( * s ) {
2017-02-04 00:50:45 +01:00
# if DEBUG
2017-02-01 11:23:58 +01:00
for ( uint i = 0 ; i < _textLines . size ( ) ; i + + ) {
debugN ( 7 , " %2d " , i ) ;
for ( uint j = 0 ; j < _textLines [ i ] . chunks . size ( ) ; j + + )
2019-12-15 10:57:05 +01:00
debugN ( 7 , " [%d] \" %s \" " , _textLines [ i ] . chunks [ j ] . fontId , Common : : toPrintable ( _textLines [ i ] . chunks [ j ] . text . encode ( ) ) . c_str ( ) ) ;
2017-02-01 11:23:58 +01:00
2019-12-15 10:57:05 +01:00
debug ( 7 , " --> %c %d, '%s' " , ( * s > 0x20 ? * s : ' ' ) , ( byte ) * s , Common : : toPrintable ( tmp . encode ( ) ) . c_str ( ) ) ;
2017-02-01 11:23:58 +01:00
}
2017-02-04 00:50:45 +01:00
# endif
2017-02-01 11:23:58 +01:00
2017-01-29 00:53:41 +01:00
if ( * s = = ' \001 ' ) {
s + + ;
if ( * s = = ' \001 ' ) {
// Copy it verbatim
2019-12-11 18:11:55 +01:00
} else if ( * s = = ' \015 ' ) {
s + + ;
2017-01-29 00:53:41 +01:00
uint16 fontId = * s + + ; fontId = ( fontId < < 8 ) | * s + + ;
byte textSlant = * s + + ;
uint16 fontSize = * s + + ; fontSize = ( fontSize < < 8 ) | * s + + ;
uint16 palinfo1 = * s + + ; palinfo1 = ( palinfo1 < < 8 ) | * s + + ;
uint16 palinfo2 = * s + + ; palinfo2 = ( palinfo2 < < 8 ) | * s + + ;
uint16 palinfo3 = * s + + ; palinfo3 = ( palinfo3 < < 8 ) | * s + + ;
2017-08-01 10:36:26 +02:00
debug ( 8 , " ******** splitString: fontId: %d, textSlant: %d, fontSize: %d, p0: %x p1: %x p2: %x " ,
fontId , textSlant , fontSize , palinfo1 , palinfo2 , palinfo3 ) ;
2017-01-29 00:53:41 +01:00
2017-02-03 18:32:44 +01:00
previousFormatting = _currentFormatting ;
2017-08-01 10:36:26 +02:00
_currentFormatting . setValues ( _wm , fontId , textSlant , fontSize , palinfo1 , palinfo2 , palinfo3 ) ;
2017-01-30 22:58:02 +01:00
2017-02-03 18:32:44 +01:00
if ( curLine = = 0 & & curChunk = = 0 & & tmp . empty ( ) )
previousFormatting = _currentFormatting ;
2017-01-31 09:52:51 +01:00
nextChunk = true ;
2019-12-11 18:11:55 +01:00
} else if ( * s = = ' \016 ' ) {
s + + ;
uint16 fontId , textSlant , fontSize , palinfo1 , palinfo2 , palinfo3 ;
s = readHex ( & fontId , s , 4 ) ;
s = readHex ( & textSlant , s , 2 ) ;
s = readHex ( & fontSize , s , 4 ) ;
s = readHex ( & palinfo1 , s , 4 ) ;
s = readHex ( & palinfo2 , s , 4 ) ;
s = readHex ( & palinfo3 , s , 4 ) ;
debug ( 8 , " ******** splitString: fontId: %d, textSlant: %d, fontSize: %d, p0: %x p1: %x p2: %x " ,
fontId , textSlant , fontSize , palinfo1 , palinfo2 , palinfo3 ) ;
previousFormatting = _currentFormatting ;
_currentFormatting . setValues ( _wm , fontId , textSlant , fontSize , palinfo1 , palinfo2 , palinfo3 ) ;
if ( curLine = = 0 & & curChunk = = 0 & & tmp . empty ( ) )
previousFormatting = _currentFormatting ;
nextChunk = true ;
} else {
error ( " MacText: formatting error, got %02x " , * s ) ;
2017-01-29 00:53:41 +01:00
}
2019-12-11 18:11:55 +01:00
} else if ( * s = = ' \n ' & & prevCR ) { // treat \r\n as one
2016-12-14 19:37:45 +01:00
prevCR = false ;
2017-01-15 18:42:50 +11:00
s + + ;
2016-12-14 19:37:45 +01:00
continue ;
2017-01-31 09:52:51 +01:00
} else if ( * s = = ' \r ' ) {
prevCR = true ;
2016-12-14 19:37:45 +01:00
}
2017-01-31 09:52:51 +01:00
if ( * s = = ' \r ' | | * s = = ' \n ' | | nextChunk ) {
2019-10-18 17:20:02 +02:00
Common : : Array < Common : : U32String > text ;
2016-12-14 19:37:45 +01:00
2017-02-03 18:32:44 +01:00
if ( ! nextChunk )
previousFormatting = _currentFormatting ;
2017-02-01 19:06:36 +01:00
int w = getLineWidth ( curLine , true ) ;
2017-02-03 18:32:44 +01:00
previousFormatting . getFont ( ) - > wordWrapText ( tmp , _maxWidth , text , w ) ;
2017-01-31 19:02:15 +01:00
tmp . clear ( ) ;
2017-01-31 09:52:51 +01:00
2017-01-31 18:44:18 +01:00
if ( text . size ( ) ) {
2017-01-31 19:02:15 +01:00
for ( uint i = 0 ; i < text . size ( ) ; i + + ) {
2017-08-02 22:18:38 +02:00
_textLines [ curLine ] . chunks [ curChunk ] . text + = text [ i ] ;
2017-01-31 22:16:50 +01:00
2017-02-03 18:32:44 +01:00
if ( ( text . size ( ) > 1 | | ! nextChunk ) & & ! ( i = = text . size ( ) - 1 & & nextChunk ) ) {
curLine + + ;
_textLines . resize ( curLine + 1 ) ;
_textLines [ curLine ] . chunks . push_back ( previousFormatting ) ;
curChunk = 0 ;
}
}
if ( nextChunk ) {
curChunk + + ;
2017-01-31 22:35:06 +01:00
_textLines [ curLine ] . chunks . push_back ( _currentFormatting ) ;
2017-02-03 18:32:44 +01:00
} else {
_textLines [ curLine ] . chunks [ 0 ] = _currentFormatting ;
2017-01-31 09:52:51 +01:00
}
2017-01-31 19:06:27 +01:00
} else {
2017-02-02 09:18:08 +01:00
if ( nextChunk ) { // No text, replacing formatting
2017-01-31 22:35:06 +01:00
_textLines [ curLine ] . chunks [ curChunk ] = _currentFormatting ;
2017-02-04 15:31:44 +01:00
} else { // Otherwise it is an empty line
curLine + + ;
_textLines . resize ( curLine + 1 ) ;
_textLines [ curLine ] . chunks . push_back ( previousFormatting ) ;
curChunk = 0 ;
2017-01-31 19:06:27 +01:00
}
2017-01-31 09:52:51 +01:00
}
2016-12-14 19:37:45 +01:00
2017-01-31 18:44:18 +01:00
if ( ! nextChunk ) // Don't skip next character
s + + ;
nextChunk = false ;
2016-12-14 19:37:45 +01:00
continue ;
}
tmp + = * s ;
2017-01-15 18:42:50 +11:00
s + + ;
2016-12-14 19:37:45 +01:00
}
2017-01-31 18:44:18 +01:00
if ( tmp . size ( ) ) {
2019-10-18 17:20:02 +02:00
Common : : Array < Common : : U32String > text ;
2017-02-01 19:06:36 +01:00
int w = getLineWidth ( curLine , true ) ;
2017-01-31 18:44:18 +01:00
2017-02-03 18:32:44 +01:00
_currentFormatting . getFont ( ) - > wordWrapText ( tmp , _maxWidth , text , w ) ;
2017-01-31 18:44:18 +01:00
2017-01-31 22:35:06 +01:00
_textLines [ curLine ] . chunks [ curChunk ] . text = text [ 0 ] ;
2017-01-31 18:44:18 +01:00
if ( text . size ( ) > 1 ) {
for ( uint i = 1 ; i < text . size ( ) ; i + + ) {
curLine + + ;
_textLines . resize ( curLine + 1 ) ;
2017-01-31 22:35:06 +01:00
_textLines [ curLine ] . chunks . push_back ( _currentFormatting ) ;
_textLines [ curLine ] . chunks [ 0 ] . text = text [ i ] ;
2017-01-31 18:44:18 +01:00
}
}
}
2016-12-14 19:37:45 +01:00
}
2016-12-16 19:37:33 +01:00
void MacText : : reallocSurface ( ) {
2016-12-20 21:18:15 +01:00
// round to closest 10
2017-01-15 18:42:50 +11:00
//TODO: work out why this rounding doesn't correctly fill the entire width
//int requiredH = (_text.size() + (_text.size() * 10 + 9) / 10) * lineH
2016-12-16 19:37:33 +01:00
2016-12-20 21:18:15 +01:00
if ( ! _surface ) {
2017-01-31 23:14:03 +01:00
_surface = new ManagedSurface ( _textMaxWidth , _textMaxHeight ) ;
2016-12-20 21:18:15 +01:00
return ;
}
2017-02-02 23:53:30 +01:00
if ( _surface - > w < _textMaxWidth | | _surface - > h < _textMaxHeight ) {
2016-12-20 21:18:15 +01:00
// realloc surface and copy old content
2017-01-31 23:14:03 +01:00
ManagedSurface * n = new ManagedSurface ( _textMaxWidth , _textMaxHeight ) ;
2017-08-26 21:33:35 +02:00
n - > clear ( _bgcolor ) ;
2016-12-20 21:18:15 +01:00
n - > blitFrom ( * _surface , Common : : Point ( 0 , 0 ) ) ;
delete _surface ;
_surface = n ;
2016-12-16 19:37:33 +01:00
}
}
2016-12-14 19:37:45 +01:00
void MacText : : render ( ) {
2016-12-14 20:09:08 +01:00
if ( _fullRefresh ) {
2017-01-31 23:14:03 +01:00
render ( 0 , _textLines . size ( ) ) ;
2016-12-14 20:09:08 +01:00
2016-12-20 21:07:54 +01:00
_fullRefresh = false ;
}
}
2016-12-14 20:09:08 +01:00
2016-12-20 21:07:54 +01:00
void MacText : : render ( int from , int to ) {
2019-11-24 15:55:11 +01:00
if ( _textLines . empty ( ) )
return ;
2016-12-20 21:19:13 +01:00
reallocSurface ( ) ;
2016-12-20 21:07:54 +01:00
from = MAX < int > ( 0 , from ) ;
2017-01-31 23:14:03 +01:00
to = MIN < int > ( to , _textLines . size ( ) - 1 ) ;
2016-12-20 21:07:54 +01:00
// Clear the screen
2017-01-31 23:14:03 +01:00
_surface - > fillRect ( Common : : Rect ( 0 , _textLines [ from ] . y , _surface - > w , _textLines [ to ] . y + getLineHeight ( to ) ) , _bgcolor ) ;
2016-12-20 21:07:54 +01:00
2017-01-31 23:14:03 +01:00
for ( int i = from ; i < = to ; i + + ) {
2017-01-17 22:15:43 +11:00
int xOffset = 0 ;
2017-01-28 12:14:49 +01:00
if ( _textAlignment = = kTextAlignRight )
2017-01-31 23:14:03 +01:00
xOffset = _textMaxWidth - getLineWidth ( i ) ;
2017-01-28 12:14:49 +01:00
else if ( _textAlignment = = kTextAlignCenter )
2017-01-31 23:14:03 +01:00
xOffset = ( _textMaxWidth / 2 ) - ( getLineWidth ( i ) / 2 ) ;
2016-12-20 21:07:54 +01:00
2017-01-31 23:14:03 +01:00
// TODO: _textMaxWidth, when -1, was not rendering ANY text.
for ( uint j = 0 ; j < _textLines [ i ] . chunks . size ( ) ; j + + ) {
2019-12-15 00:10:27 +01:00
debug ( 5 , " MacText::render: line %d[%d]/%d at %d,%d (%s) " , i , j , xOffset , _textLines [ i ] . chunks [ j ] . fontId , _textLines [ i ] . y , _textLines [ i ] . chunks [ j ] . text . encode ( ) . c_str ( ) ) ;
2017-08-02 10:21:08 +02:00
2017-02-02 09:18:08 +01:00
if ( _textLines [ i ] . chunks [ j ] . text . empty ( ) )
continue ;
2017-01-31 23:14:03 +01:00
_textLines [ i ] . chunks [ j ] . getFont ( ) - > drawString ( _surface , _textLines [ i ] . chunks [ j ] . text , xOffset , _textLines [ i ] . y , _maxWidth , _fgcolor ) ;
xOffset + = _textLines [ i ] . chunks [ j ] . getFont ( ) - > getStringWidth ( _textLines [ i ] . chunks [ j ] . text ) ;
}
2016-12-14 20:09:08 +01:00
}
2016-12-20 21:07:54 +01:00
2017-01-31 19:02:15 +01:00
for ( uint i = 0 ; i < _textLines . size ( ) ; i + + ) {
2019-12-15 00:10:27 +01:00
debugN ( 4 , " MacText::render: %2d " , i ) ;
2017-01-31 19:02:15 +01:00
2017-01-31 22:35:06 +01:00
for ( uint j = 0 ; j < _textLines [ i ] . chunks . size ( ) ; j + + )
2019-10-19 17:43:47 +02:00
debugN ( 4 , " [%d (%d)] \" %s \" " , _textLines [ i ] . chunks [ j ] . fontId , _textLines [ i ] . chunks [ j ] . textSlant , _textLines [ i ] . chunks [ j ] . text . encode ( ) . c_str ( ) ) ;
2017-01-31 19:02:15 +01:00
2017-02-01 01:17:53 +00:00
debug ( 4 , " %s " , " " ) ;
2017-01-31 19:02:15 +01:00
}
2016-12-14 19:20:26 +01:00
}
2017-02-01 19:06:36 +01:00
int MacText : : getLineWidth ( int line , bool enforce ) {
2017-02-01 01:17:53 +00:00
if ( ( uint ) line > = _textLines . size ( ) )
2017-01-31 23:14:03 +01:00
return 0 ;
2017-02-01 19:06:36 +01:00
if ( _textLines [ line ] . width ! = - 1 & & ! enforce )
2017-01-31 23:14:03 +01:00
return _textLines [ line ] . width ;
int width = 0 ;
int height = 0 ;
2019-12-15 11:35:56 +01:00
bool hastext = false ;
2017-01-31 23:14:03 +01:00
for ( uint i = 0 ; i < _textLines [ line ] . chunks . size ( ) ; i + + ) {
2017-02-04 16:05:01 +01:00
if ( enforce )
_textLines [ line ] . chunks [ i ] . font = nullptr ;
2019-12-15 11:35:56 +01:00
if ( ! _textLines [ line ] . chunks [ i ] . text . empty ( ) ) {
2017-02-02 10:10:17 +01:00
width + = _textLines [ line ] . chunks [ i ] . getFont ( ) - > getStringWidth ( _textLines [ line ] . chunks [ i ] . text ) ;
2019-12-15 11:35:56 +01:00
hastext = true ;
}
2017-02-02 10:10:17 +01:00
2017-01-31 23:14:03 +01:00
height = MAX ( height , _textLines [ line ] . chunks [ i ] . getFont ( ) - > getFontHeight ( ) ) ;
}
2019-12-15 11:35:56 +01:00
if ( ! hastext )
height - = 3 ;
2017-01-31 23:14:03 +01:00
_textLines [ line ] . width = width ;
_textLines [ line ] . height = height ;
return width ;
}
int MacText : : getLineHeight ( int line ) {
2017-02-01 01:17:53 +00:00
if ( ( uint ) line > = _textLines . size ( ) )
2017-01-31 23:14:03 +01:00
return 0 ;
getLineWidth ( line ) ; // This calculates height also
return _textLines [ line ] . height ;
}
2017-03-31 01:02:01 +02:00
void MacText : : setInterLinear ( int interLinear ) {
_interLinear = interLinear ;
2017-02-07 16:26:59 +11:00
recalcDims ( ) ;
}
2017-01-31 23:14:03 +01:00
void MacText : : recalcDims ( ) {
2019-11-24 15:55:11 +01:00
if ( _textLines . empty ( ) )
return ;
2017-01-31 23:14:03 +01:00
int y = 0 ;
_textMaxWidth = 0 ;
for ( uint i = 0 ; i < _textLines . size ( ) ; i + + ) {
_textLines [ i ] . y = y ;
y + = getLineHeight ( i ) + _interLinear ;
2017-02-02 23:41:58 +01:00
_textMaxWidth = MAX ( _textMaxWidth , getLineWidth ( i , true ) ) ;
2017-01-31 23:14:03 +01:00
}
2017-02-07 16:26:59 +11:00
_textMaxHeight = y - _interLinear ;
2017-01-31 23:14:03 +01:00
}
2016-12-15 18:18:12 +01:00
void MacText : : draw ( ManagedSurface * g , int x , int y , int w , int h , int xoff , int yoff ) {
2017-07-30 09:05:14 +02:00
if ( _textLines . empty ( ) )
return ;
2017-04-09 00:05:56 +03:00
2016-12-15 18:18:12 +01:00
render ( ) ;
2016-12-20 21:18:15 +01:00
if ( x + w < _surface - > w | | y + h < _surface - > h ) {
2016-12-15 18:18:12 +01:00
g - > fillRect ( Common : : Rect ( x , y , x + w , y + w ) , _bgcolor ) ;
}
2017-04-02 01:59:32 +03:00
g - > blitFrom ( * _surface , Common : : Rect ( MIN < int > ( _surface - > w , x ) , MIN < int > ( _surface - > h , y ) ,
2017-08-03 09:27:29 +02:00
MIN < int > ( _surface - > w , x + w ) , MIN < int > ( _surface - > h , y + h ) ) ,
2016-12-20 21:19:13 +01:00
Common : : Point ( xoff , yoff ) ) ;
2016-12-15 18:18:12 +01:00
}
2019-10-20 20:08:37 +05:00
void MacText : : drawToPoint ( ManagedSurface * g , Common : : Rect srcRect , Common : : Point dstPoint ) {
if ( _textLines . empty ( ) )
return ;
render ( ) ;
srcRect . clip ( _surface - > getBounds ( ) ) ;
if ( srcRect . isEmpty ( ) )
return ;
g - > blitFrom ( * _surface , srcRect , dstPoint ) ;
}
void MacText : : drawToPoint ( ManagedSurface * g , Common : : Point dstPoint ) {
if ( _textLines . empty ( ) )
return ;
render ( ) ;
g - > blitFrom ( * _surface , dstPoint ) ;
}
2017-04-04 02:07:35 +03:00
// Count newline characters in String
2019-10-18 17:20:02 +02:00
uint getNewlinesInString ( const Common : : U32String & str ) {
Common : : U32String : : const_iterator p = str . begin ( ) ;
2017-04-04 02:07:35 +03:00
uint newLines = 0 ;
2017-03-31 01:02:01 +02:00
while ( * p ) {
if ( * p = = ' \n ' )
newLines + + ;
p + + ;
}
2017-04-04 02:07:35 +03:00
return newLines ;
}
2019-10-18 17:20:02 +02:00
void MacText : : appendText ( Common : : U32String str , int fontId , int fontSize , int fontSlant , bool skipAdd ) {
2017-04-04 02:07:35 +03:00
uint oldLen = _textLines . size ( ) ;
2017-08-01 10:36:26 +02:00
MacFontRun fontRun = MacFontRun ( _wm , fontId , fontSlant , fontSize , 0 , 0 , 0 ) ;
2017-04-04 02:07:35 +03:00
2017-08-02 10:22:29 +02:00
_currentFormatting = fontRun ;
2017-08-02 21:46:25 +02:00
if ( ! skipAdd ) {
_str + = fontRun . toString ( ) ;
_str + = str ;
}
2017-08-01 09:55:20 +02:00
2017-04-04 02:07:35 +03:00
splitString ( str ) ;
recalcDims ( ) ;
2017-08-02 10:22:29 +02:00
render ( oldLen - 1 , _textLines . size ( ) ) ;
2017-04-04 02:07:35 +03:00
}
2019-10-18 17:20:02 +02:00
void MacText : : appendText ( const Common : : String & str , int fontId , int fontSize , int fontSlant , bool skipAdd ) {
appendText ( Common : : U32String ( str ) , fontId , fontSize , fontSlant , skipAdd ) ;
}
void MacText : : appendTextDefault ( Common : : U32String str , bool skipAdd ) {
2017-04-04 02:07:35 +03:00
uint oldLen = _textLines . size ( ) ;
2017-08-02 10:22:29 +02:00
_currentFormatting = _defaultFormatting ;
2017-08-02 21:46:25 +02:00
if ( ! skipAdd ) {
_str + = _defaultFormatting . toString ( ) ;
_str + = str ;
}
2017-08-01 09:55:20 +02:00
2016-12-16 19:37:33 +01:00
splitString ( str ) ;
2017-01-31 23:14:03 +01:00
recalcDims ( ) ;
2016-12-16 19:37:33 +01:00
2017-08-02 10:22:29 +02:00
render ( oldLen - 1 , _textLines . size ( ) ) ;
2016-12-16 19:37:33 +01:00
}
2019-10-18 17:20:02 +02:00
void MacText : : appendTextDefault ( const Common : : String & str , bool skipAdd ) {
appendTextDefault ( Common : : U32String ( str ) , skipAdd ) ;
}
2017-04-09 00:05:56 +03:00
void MacText : : clearText ( ) {
_textLines . clear ( ) ;
_str . clear ( ) ;
2017-08-28 19:17:45 +02:00
if ( _surface )
_surface - > clear ( _bgcolor ) ;
2017-08-05 23:32:05 +02:00
2017-08-05 23:55:44 +02:00
recalcDims ( ) ;
2017-04-09 00:05:56 +03:00
}
2019-10-18 17:20:02 +02:00
void MacText : : replaceLastLine ( Common : : U32String str ) {
2017-02-06 08:41:09 +01:00
int oldLen = MAX < int > ( 0 , _textLines . size ( ) - 1 ) ;
2016-12-22 18:15:43 +01:00
2017-01-31 23:14:03 +01:00
// TODO: Recalc length, adapt to _textLines
2017-02-06 08:41:09 +01:00
if ( _textLines . size ( ) )
_textLines . pop_back ( ) ;
2016-12-22 18:15:43 +01:00
splitString ( str ) ;
2017-01-31 23:14:03 +01:00
recalcDims ( ) ;
2016-12-22 18:15:43 +01:00
2017-02-06 08:41:09 +01:00
render ( oldLen , _textLines . size ( ) ) ;
2016-12-22 18:15:43 +01:00
}
2017-07-30 08:52:52 +02:00
void MacText : : removeLastLine ( ) {
if ( ! _textLines . size ( ) )
return ;
int h = getLineHeight ( _textLines . size ( ) - 1 ) + _interLinear ;
2017-08-02 22:36:10 +02:00
_surface - > fillRect ( Common : : Rect ( 0 , _textMaxHeight - h , _surface - > w , _textMaxHeight ) , _bgcolor ) ;
2017-07-30 08:52:52 +02:00
_textLines . pop_back ( ) ;
_textMaxHeight - = h ;
}
2017-08-03 09:48:01 +02:00
void MacText : : getRowCol ( int x , int y , int * sx , int * sy , int * row , int * col ) {
2017-08-07 11:59:57 +02:00
if ( y > _textMaxHeight ) {
x = _surface - > w ;
}
2017-08-05 08:12:43 +02:00
y = CLIP ( y , 0 , _textMaxHeight ) ;
2017-08-03 09:27:29 +02:00
// FIXME: We should use bsearch() here
2017-08-04 07:46:57 +02:00
* row = _textLines . size ( ) - 1 ;
2017-08-03 09:27:29 +02:00
2017-08-04 07:46:57 +02:00
while ( * row & & _textLines [ * row ] . y > y )
2017-08-03 19:25:39 +02:00
( * row ) - - ;
2017-08-04 07:46:57 +02:00
2017-08-03 09:48:01 +02:00
* sy = _textLines [ * row ] . y ;
2017-08-03 09:27:29 +02:00
* col = 0 ;
int width = 0 , pwidth = 0 ;
int mcol = 0 , pmcol = 0 ;
uint chunk ;
2017-08-04 07:34:13 +02:00
for ( chunk = 0 ; chunk < _textLines [ * row ] . chunks . size ( ) ; chunk + + ) {
2017-08-03 09:27:29 +02:00
pwidth = width ;
pmcol = mcol ;
if ( ! _textLines [ * row ] . chunks [ chunk ] . text . empty ( ) ) {
width + = _textLines [ * row ] . chunks [ chunk ] . getFont ( ) - > getStringWidth ( _textLines [ * row ] . chunks [ chunk ] . text ) ;
mcol + = _textLines [ * row ] . chunks [ chunk ] . text . size ( ) ;
}
if ( width > x )
break ;
}
2017-08-04 07:34:13 +02:00
if ( chunk = = _textLines [ * row ] . chunks . size ( ) )
chunk - - ;
2019-10-18 17:20:02 +02:00
Common : : U32String str = _textLines [ * row ] . chunks [ chunk ] . text ;
2017-08-03 09:27:29 +02:00
* col = mcol ;
for ( int i = str . size ( ) ; i > = 0 ; i - - ) {
2017-08-03 09:48:01 +02:00
int strw = _textLines [ * row ] . chunks [ chunk ] . getFont ( ) - > getStringWidth ( str ) ;
if ( strw + pwidth < x ) {
2017-08-04 08:00:56 +02:00
* col = pmcol + i ;
2017-08-03 09:48:01 +02:00
* sx = strw + pwidth ;
2017-08-03 09:27:29 +02:00
break ;
}
str . deleteLastChar ( ) ;
}
2017-08-03 09:03:09 +02:00
}
2019-10-18 17:20:02 +02:00
Common : : U32String MacText : : getTextChunk ( int startRow , int startCol , int endRow , int endCol , bool formatted , bool newlines ) {
Common : : U32String res ;
2017-08-03 22:50:01 +02:00
2017-08-05 08:12:43 +02:00
startRow = CLIP ( startRow , 0 , ( int ) _textLines . size ( ) - 1 ) ;
endRow = CLIP ( endRow , 0 , ( int ) _textLines . size ( ) - 1 ) ;
2017-08-03 22:50:01 +02:00
for ( int i = startRow ; i < = endRow ; i + + ) {
if ( i = = startRow & & i = = endRow ) {
2017-08-03 23:09:14 +02:00
for ( uint chunk = 0 ; chunk < _textLines [ i ] . chunks . size ( ) ; chunk + + ) {
2017-08-03 22:50:01 +02:00
if ( startCol < = 0 ) {
if ( formatted )
res + = _textLines [ i ] . chunks [ chunk ] . toString ( ) ;
2018-08-17 20:30:20 -07:00
if ( endCol > = ( int ) _textLines [ i ] . chunks [ chunk ] . text . size ( ) )
2017-08-03 22:50:01 +02:00
res + = _textLines [ i ] . chunks [ chunk ] . text ;
else
2019-10-18 17:20:02 +02:00
res + = Common : : U32String ( _textLines [ i ] . chunks [ chunk ] . text . c_str ( ) , endCol ) ;
2018-08-17 20:30:20 -07:00
} else if ( ( int ) _textLines [ i ] . chunks [ chunk ] . text . size ( ) > startCol ) {
2017-08-03 22:50:01 +02:00
if ( formatted )
res + = _textLines [ i ] . chunks [ chunk ] . toString ( ) ;
2019-10-18 17:20:02 +02:00
res + = Common : : U32String ( _textLines [ i ] . chunks [ chunk ] . text . c_str ( ) + startCol , endCol - startCol ) ;
2017-08-03 22:50:01 +02:00
}
startCol - = _textLines [ i ] . chunks [ chunk ] . text . size ( ) ;
endCol - = _textLines [ i ] . chunks [ chunk ] . text . size ( ) ;
if ( endCol < = 0 )
break ;
}
} else if ( i = = startRow & & startCol ! = 0 ) {
2017-08-03 23:09:14 +02:00
for ( uint chunk = 0 ; chunk < _textLines [ i ] . chunks . size ( ) ; chunk + + ) {
2017-08-03 22:50:01 +02:00
if ( startCol < = 0 ) {
if ( formatted )
res + = _textLines [ i ] . chunks [ chunk ] . toString ( ) ;
res + = _textLines [ i ] . chunks [ chunk ] . text ;
2018-08-17 20:30:20 -07:00
} else if ( ( int ) _textLines [ i ] . chunks [ chunk ] . text . size ( ) > startCol ) {
2017-08-03 22:50:01 +02:00
if ( formatted )
res + = _textLines [ i ] . chunks [ chunk ] . toString ( ) ;
2019-10-18 17:20:02 +02:00
res + = Common : : U32String ( _textLines [ i ] . chunks [ chunk ] . text . c_str ( ) + startCol ) ;
2017-08-03 22:50:01 +02:00
}
startCol - = _textLines [ i ] . chunks [ chunk ] . text . size ( ) ;
}
2017-08-15 19:48:16 +02:00
if ( newlines )
res + = ' \n ' ;
else
res + = ' ' ;
2017-08-03 22:50:01 +02:00
} else if ( i = = endRow ) {
2017-08-03 23:09:14 +02:00
for ( uint chunk = 0 ; chunk < _textLines [ i ] . chunks . size ( ) ; chunk + + ) {
2017-08-03 22:50:01 +02:00
if ( formatted )
res + = _textLines [ i ] . chunks [ chunk ] . toString ( ) ;
2018-08-17 20:30:20 -07:00
if ( endCol > = ( int ) _textLines [ i ] . chunks [ chunk ] . text . size ( ) )
2017-08-03 22:50:01 +02:00
res + = _textLines [ i ] . chunks [ chunk ] . text ;
else
2019-10-18 17:20:02 +02:00
res + = Common : : U32String ( _textLines [ i ] . chunks [ chunk ] . text . c_str ( ) , endCol ) ;
2017-08-03 22:50:01 +02:00
endCol - = _textLines [ i ] . chunks [ chunk ] . text . size ( ) ;
if ( endCol < = 0 )
break ;
}
} else {
2017-08-03 23:09:14 +02:00
for ( uint chunk = 0 ; chunk < _textLines [ i ] . chunks . size ( ) ; chunk + + ) {
2017-08-03 22:50:01 +02:00
if ( formatted )
res + = _textLines [ i ] . chunks [ chunk ] . toString ( ) ;
res + = _textLines [ i ] . chunks [ chunk ] . text ;
}
2017-08-07 22:17:26 +02:00
if ( newlines )
res + = ' \n ' ;
2017-08-15 19:48:16 +02:00
else
res + = ' ' ;
2017-08-03 22:50:01 +02:00
}
}
return res ;
}
2016-12-14 19:20:26 +01:00
} // End of namespace Graphics