mirror of
https://github.com/tuxbox-neutrino/neutrino.git
synced 2025-08-28 16:01:20 +02:00
926 lines
25 KiB
C++
926 lines
25 KiB
C++
/***************************************************************************
|
|
Neutrino-GUI - DBoxII-Project
|
|
|
|
Homepage: http://dbox.cyberphoria.org/
|
|
|
|
Kommentar:
|
|
|
|
Diese GUI wurde von Grund auf neu programmiert und sollte nun vom
|
|
Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert
|
|
auf der Client-Server Idee, diese GUI ist also von der direkten DBox-
|
|
Steuerung getrennt. Diese wird dann von Daemons uebernommen.
|
|
|
|
|
|
License: GPL
|
|
|
|
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
***********************************************************
|
|
|
|
Module Name: textbox.cpp: .
|
|
|
|
Description: implementation of the CTextBox class
|
|
This class provides a plain textbox with selectable features:
|
|
- Foot, Title
|
|
- Scroll bar
|
|
- Frame shadow
|
|
- Auto line break
|
|
- fixed position or auto width and auto height (later not tested yet)
|
|
- Center Text
|
|
|
|
Date: Nov 2005
|
|
|
|
Author: Günther@tuxbox.berlios.org
|
|
based on code of Steffen Hehn 'McClean'
|
|
|
|
Revision History:
|
|
Date Author Change Description
|
|
Nov 2005 Günther initial implementation
|
|
|
|
****************************************************************************/
|
|
|
|
//#define VISUAL_DEBUG
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <global.h>
|
|
#include <system/debug.h>
|
|
#include <gui/color.h>
|
|
#include "textbox.h"
|
|
#include <gui/widget/icons.h>
|
|
#include <driver/fontrenderer.h>
|
|
#ifdef VISUAL_DEBUG
|
|
#include <gui/color_custom.h>
|
|
#endif
|
|
#include <sstream>
|
|
|
|
#define SCROLL_FRAME_WIDTH SCROLLBAR_WIDTH
|
|
#define SCROLL_MARKER_BORDER OFFSET_INNER_MIN
|
|
|
|
#define MAX_WINDOW_WIDTH (g_settings.screen_EndX - g_settings.screen_StartX - CFrameBuffer::getInstance()->scale2Res(40))
|
|
#define MAX_WINDOW_HEIGHT (g_settings.screen_EndY - g_settings.screen_StartY - CFrameBuffer::getInstance()->scale2Res(40))
|
|
|
|
#define MIN_WINDOW_WIDTH ((g_settings.screen_EndX - g_settings.screen_StartX)>>1)
|
|
#define MIN_WINDOW_HEIGHT CFrameBuffer::getInstance()->scale2Res(40)
|
|
|
|
CTextBox::CTextBox(const char * text, Font* font_text, const int pmode,
|
|
const CBox* position, CFBWindow::color_t textBackgroundColor)
|
|
{
|
|
//TRACE("[CTextBox] new %d\n", __LINE__);
|
|
initVar();
|
|
|
|
if(text != NULL)
|
|
m_cText = m_old_cText = text;
|
|
|
|
if(font_text != NULL)
|
|
m_pcFontText = font_text;
|
|
|
|
if(position != NULL)
|
|
{
|
|
m_cFrame = *position;
|
|
m_nMaxHeight = m_cFrame.iHeight;
|
|
m_nMaxWidth = m_cFrame.iWidth;
|
|
}
|
|
|
|
m_nMode = pmode;
|
|
|
|
/* in case of auto line break, we do no support auto width yet */
|
|
if( !(pmode & NO_AUTO_LINEBREAK))
|
|
m_nMode = m_nMode & ~AUTO_WIDTH; /* delete any AUTO_WIDTH*/
|
|
|
|
//TRACE(" CTextBox::m_cText: %d, m_nMode %d\t\r\n",m_cText.size(),m_nMode);
|
|
|
|
m_textBackgroundColor = m_old_textBackgroundColor = textBackgroundColor;
|
|
m_nFontTextHeight = getFontTextHeight();
|
|
|
|
//TRACE("[CTextBox] %s Line %d\r\n", __FUNCTION__, __LINE__);
|
|
//TRACE(" CTextBox::m_nFontTextHeight: %d\t\r\n",m_nFontTextHeight);
|
|
|
|
//Initialise the window frames first and than refresh text line array
|
|
initFramesAndTextArray();
|
|
}
|
|
|
|
CTextBox::CTextBox(const char * text)
|
|
{
|
|
//TRACE("[CTextBox] new %d\r", __LINE__);
|
|
initVar();
|
|
|
|
if(text != NULL)
|
|
m_cText = m_old_cText = *text;
|
|
|
|
//TRACE_1("[CTextBox] %s Line %d text: %s\r\n", __FUNCTION__, __LINE__, text);
|
|
|
|
//Initialise the window frames first and than refresh text line array
|
|
initFramesAndTextArray();
|
|
}
|
|
|
|
CTextBox::CTextBox()
|
|
{
|
|
//TRACE("[CTextBox] new %d\n", __LINE__);
|
|
initVar();
|
|
|
|
//Initialise the window frames first and than refresh text line array
|
|
initFramesAndTextArray();
|
|
}
|
|
|
|
CTextBox::~CTextBox()
|
|
{
|
|
//TRACE("[CTextBox] del\r\n");
|
|
m_cLineArray.clear();
|
|
//hide();
|
|
clearScreenBuffer();
|
|
}
|
|
|
|
void CTextBox::initVar(void)
|
|
{
|
|
//TRACE("[CTextBox]->InitVar\r\n");
|
|
frameBuffer = NULL;
|
|
m_bgpixbuf = NULL;
|
|
|
|
m_showTextFrame = 0;
|
|
m_nNrOfNewLine = 0;
|
|
|
|
m_cText = "";
|
|
m_nMode = m_old_nMode = SCROLL;
|
|
|
|
m_FontUseDigitHeight = false;
|
|
m_pcFontText = g_Font[SNeutrinoSettings::FONT_TYPE_EPG_INFO1];
|
|
m_nFontTextHeight = getFontTextHeight();
|
|
m_nMaxTextWidth = 0;
|
|
m_bg_painted = false;
|
|
|
|
m_nNrOfPages = 1;
|
|
m_nNrOfLines = 0;
|
|
m_nLinesPerPage = 0;
|
|
m_nCurrentLine = 0;
|
|
m_nCurrentPage = 0;
|
|
text_Hborder_width = OFFSET_INNER_MID; //border left and right
|
|
text_Vborder_width = OFFSET_INNER_MID; //border top and buttom
|
|
|
|
m_cFrame.iX = m_old_x = g_settings.screen_StartX + ((g_settings.screen_EndX - g_settings.screen_StartX - MIN_WINDOW_WIDTH) >>1);
|
|
m_cFrame.iWidth = m_old_dx = MIN_WINDOW_WIDTH;
|
|
m_cFrame.iY = m_old_y = g_settings.screen_StartY + ((g_settings.screen_EndY - g_settings.screen_StartY - MIN_WINDOW_HEIGHT) >>1);
|
|
m_cFrame.iHeight = m_old_dy = MIN_WINDOW_HEIGHT;
|
|
|
|
m_has_scrolled = false;
|
|
|
|
m_nMaxHeight = MAX_WINDOW_HEIGHT;
|
|
m_nMaxWidth = MAX_WINDOW_WIDTH;
|
|
m_nMinHeight = MIN_WINDOW_HEIGHT;
|
|
m_nMinWidth = MIN_WINDOW_WIDTH;
|
|
|
|
m_textBackgroundColor = m_old_textBackgroundColor = COL_MENUCONTENT_PLUS_0;
|
|
m_textColor = COL_MENUCONTENT_TEXT;
|
|
m_old_textColor = 0;
|
|
m_nPaintBackground = true;
|
|
m_SaveScreen = false;
|
|
m_nBgRadius = m_old_nBgRadius = 0;
|
|
m_nBgRadiusType = m_old_nBgRadiusType = CORNER_NONE;
|
|
|
|
m_cLineArray.clear();
|
|
|
|
m_renderMode = 0;
|
|
m_utf8_encoded = true;
|
|
// max_width = 0;
|
|
}
|
|
|
|
void CTextBox::initFramesAndTextArray()
|
|
{
|
|
/* Initialise the window frames first */
|
|
initFramesRel();
|
|
// than refresh text line array
|
|
refreshTextLineArray();
|
|
}
|
|
|
|
int CTextBox::getFontTextHeight()
|
|
{
|
|
if (m_FontUseDigitHeight)
|
|
return m_pcFontText->getDigitHeight() + (m_pcFontText->getDigitOffset() * 18) / 10;
|
|
else
|
|
return m_pcFontText->getHeight();
|
|
}
|
|
|
|
void CTextBox::setFontUseDigitHeight(bool set/*=true*/)
|
|
{
|
|
if (m_FontUseDigitHeight != set) {
|
|
m_FontUseDigitHeight = set;
|
|
m_nFontTextHeight = getFontTextHeight();
|
|
initFramesAndTextArray();
|
|
}
|
|
}
|
|
|
|
void CTextBox::setTextFont(Font* font_text)
|
|
{
|
|
if ((m_pcFontText != font_text) && (font_text != NULL)) {
|
|
m_pcFontText = font_text;
|
|
m_nFontTextHeight = getFontTextHeight();
|
|
//Initialise the window frames first and than refresh text line array
|
|
initFramesAndTextArray();
|
|
}
|
|
}
|
|
|
|
void CTextBox::setTextBorderWidth(int Hborder, int Vborder)
|
|
{
|
|
text_Hborder_width = Hborder;
|
|
text_Vborder_width = Vborder;
|
|
//Initialise the window frames first and than refresh text line array
|
|
initFramesAndTextArray();
|
|
}
|
|
|
|
void CTextBox::setWindowMaxDimensions(const int width, const int height)
|
|
{
|
|
m_nMaxHeight = height;
|
|
m_nMaxWidth = width;
|
|
}
|
|
|
|
void CTextBox::setWindowMinDimensions(const int width, const int height)
|
|
{
|
|
m_nMinHeight = height;
|
|
m_nMinWidth = width;
|
|
}
|
|
|
|
void CTextBox::reSizeMainFrameWidth(int textWidth)
|
|
{
|
|
//TRACE("[CTextBox]->%s: \ntext width: %d\n m_cFrame.iWidth: %d\n m_cFrameTextRel.iWidth: %d\n m_nMaxWidth: %d\n m_nMinWidth: %d\n",__FUNCTION__, textWidth, m_cFrame.iWidth, m_cFrameTextRel.iWidth, m_nMaxWidth, m_nMinWidth);
|
|
|
|
int iNewWindowWidth = textWidth + m_cFrameScrollRel.iWidth + 2*text_Hborder_width;
|
|
|
|
if( iNewWindowWidth > m_nMaxWidth)
|
|
iNewWindowWidth = m_nMaxWidth;
|
|
|
|
if( iNewWindowWidth < m_nMinWidth)
|
|
iNewWindowWidth = m_nMinWidth;
|
|
|
|
m_cFrame.iWidth = iNewWindowWidth;
|
|
|
|
/* Re-Init the children frames due to new main window */
|
|
initFramesRel();
|
|
}
|
|
|
|
void CTextBox::reSizeMainFrameHeight(int textHeight)
|
|
{
|
|
//TRACE("[CTextBox]->ReSizeMainFrameHeight: %d, current: %d\r\n",textHeight,m_cFrameTextRel.iHeight);
|
|
|
|
int iNewWindowHeight = textHeight + 2*text_Vborder_width;
|
|
|
|
if( iNewWindowHeight > m_nMaxHeight)
|
|
iNewWindowHeight = m_nMaxHeight;
|
|
|
|
if( iNewWindowHeight < m_nMinHeight)
|
|
iNewWindowHeight = m_nMinHeight;
|
|
|
|
m_cFrame.iHeight = iNewWindowHeight;
|
|
|
|
/* Re-Init the children frames due to new main window */
|
|
initFramesRel();
|
|
}
|
|
|
|
void CTextBox::initFramesRel(void)
|
|
{
|
|
//TRACE("[CTextBox]->InitFramesRel\r\n");
|
|
|
|
m_cFrameTextRel.iX = 0;
|
|
m_cFrameTextRel.iY = 0;
|
|
m_cFrameTextRel.iHeight = m_cFrame.iHeight ;
|
|
|
|
if(m_nMode & SCROLL)
|
|
{
|
|
m_cFrameScrollRel.iX = m_cFrame.iWidth - SCROLL_FRAME_WIDTH;
|
|
m_cFrameScrollRel.iY = m_cFrameTextRel.iY + m_nBgRadius;
|
|
m_cFrameScrollRel.iWidth = SCROLL_FRAME_WIDTH;
|
|
m_cFrameScrollRel.iHeight = m_cFrameTextRel.iHeight - 2*m_nBgRadius;
|
|
}
|
|
else
|
|
{
|
|
m_cFrameScrollRel.iX = 0;
|
|
m_cFrameScrollRel.iY = 0;
|
|
m_cFrameScrollRel.iHeight = 0;
|
|
m_cFrameScrollRel.iWidth = 0;
|
|
}
|
|
|
|
m_cFrameTextRel.iWidth = m_cFrame.iWidth - m_cFrameScrollRel.iWidth;
|
|
|
|
m_nLinesPerPage = std::max(1, (m_cFrameTextRel.iHeight - (2*text_Vborder_width)) / m_nFontTextHeight);
|
|
|
|
#if 0
|
|
TRACE_1("Frames\r\n\tScren:\t%3d,%3d,%3d,%3d\r\n\tMain:\t%3d,%3d,%3d,%3d\r\n\tText:\t%3d,%3d,%3d,%3d \r\n\tScroll:\t%3d,%3d,%3d,%3d \r\n",
|
|
g_settings.screen_StartX,
|
|
g_settings.screen_StartY,
|
|
g_settings.screen_EndX,
|
|
g_settings.screen_EndY,
|
|
m_cFrame.iX,
|
|
m_cFrame.iY,
|
|
m_cFrame.iWidth,
|
|
m_cFrame.iHeight,
|
|
m_cFrameTextRel.iX,
|
|
m_cFrameTextRel.iY,
|
|
m_cFrameTextRel.iWidth,
|
|
m_cFrameTextRel.iHeight,
|
|
m_cFrameScrollRel.iX,
|
|
m_cFrameScrollRel.iY,
|
|
m_cFrameScrollRel.iWidth,
|
|
m_cFrameScrollRel.iHeight
|
|
);
|
|
#endif
|
|
}
|
|
|
|
void CTextBox::refreshTextLineArray(void)
|
|
{
|
|
//TRACE("[CTextBox]->RefreshLineArray \r\n");
|
|
int loop = true;
|
|
int pos_prev = 0;
|
|
int pos = 0;
|
|
int aktWidth = 0;
|
|
int aktWordWidth = 0;
|
|
int lineBreakWidth = 0;
|
|
|
|
m_nNrOfNewLine = 0;
|
|
|
|
std::string aktLine = "";
|
|
std::string aktWord = "";
|
|
|
|
/* clear current line vector */
|
|
m_cLineArray.clear();
|
|
m_nNrOfLines = 0;
|
|
|
|
int MaxWidth = m_nMaxWidth - m_cFrameScrollRel.iWidth - 2*text_Hborder_width;
|
|
if( m_nMode & AUTO_WIDTH){
|
|
/* In case of autowidth, we calculate the max allowed width of the textbox */
|
|
lineBreakWidth = MaxWidth;
|
|
}else{
|
|
/* If not autowidth, we just take the actuall textframe width */
|
|
lineBreakWidth = std::max(MaxWidth, m_cFrameTextRel.iWidth - 2*text_Hborder_width);
|
|
}
|
|
|
|
if(m_nMaxTextWidth)
|
|
lineBreakWidth = m_nMaxTextWidth - 2*text_Hborder_width;
|
|
|
|
//TRACE("[CTextBox] line %d: lineBreakWidth %d\n", __LINE__, lineBreakWidth);
|
|
|
|
int TextChars = m_cText.size();
|
|
// do not parse, if text is empty
|
|
if(TextChars == 0)
|
|
{
|
|
m_nNrOfPages = 0;
|
|
m_nNrOfLines = 0;
|
|
m_nCurrentPage = 0;
|
|
m_nCurrentLine = 0;
|
|
m_nLinesPerPage = 1;
|
|
}
|
|
else
|
|
{
|
|
while(loop)
|
|
{
|
|
//manage auto linebreak,
|
|
if(m_nMode & NO_AUTO_LINEBREAK)
|
|
pos = m_cText.find_first_of("\n", pos_prev);
|
|
else if(m_nMode & AUTO_LINEBREAK_NO_BREAKCHARS)
|
|
pos = m_cText.find_first_of("\n/ ", pos_prev);
|
|
else
|
|
pos = m_cText.find_first_of("\n/-. ", pos_prev);
|
|
|
|
//TRACE_1(" pos: %d pos_prev: %d\r\n",pos,pos_prev);
|
|
|
|
if(pos == -1)
|
|
{
|
|
pos = TextChars+1;
|
|
loop = false; // note, this is not 100% correct. if the last characters does not fit in one line, the characters after are cut
|
|
//TRACE_1(" Textend found\r\n");
|
|
}
|
|
|
|
//find current word between start pos and next pos (next possible \n)
|
|
aktWord = m_cText.substr(pos_prev, pos - pos_prev + 1);
|
|
|
|
//calculate length of current found word
|
|
aktWordWidth = m_pcFontText->getRenderWidth(aktWord, m_utf8_encoded);
|
|
|
|
//set next start pos
|
|
pos_prev = pos + 1;
|
|
//if(aktWord.find(""") == )
|
|
if(1)
|
|
{
|
|
//TRACE_1(" aktWord: >%s< pos:%d\r\n",aktWord.c_str(),pos);
|
|
|
|
if( (aktWidth + aktWordWidth) > lineBreakWidth && !(m_nMode & NO_AUTO_LINEBREAK))
|
|
{
|
|
/* we need a new line before we can continue */
|
|
m_cLineArray.push_back(aktLine);
|
|
//TRACE_1(" end line: %s\r\n", aktLine.c_str());
|
|
m_nNrOfLines++;
|
|
aktLine = "";
|
|
aktWidth = 0;
|
|
|
|
if(pos_prev >= TextChars)
|
|
loop = false;
|
|
}
|
|
|
|
//add current word to current line
|
|
aktLine += aktWord;
|
|
//set current line width
|
|
aktWidth += aktWordWidth;
|
|
|
|
//set max text width, if required
|
|
if (aktWidth > m_nMaxTextWidth)
|
|
m_nMaxTextWidth = aktWidth;
|
|
|
|
//TRACE_1(" aktLine : %s\r\n",aktLine.c_str());
|
|
//TRACE_1(" aktWidth: %d aktWordWidth:%d\r\n",aktWidth,aktWordWidth);
|
|
|
|
if( ((pos < TextChars) && (m_cText[pos] == '\n')) || loop == false)
|
|
{
|
|
// current line ends with an carriage return, make new line
|
|
if ((pos < TextChars) && (m_cText[pos] == '\n'))
|
|
aktLine.erase(aktLine.size() - 1,1);
|
|
m_cLineArray.push_back(aktLine);
|
|
m_nNrOfLines++;
|
|
aktLine = "";
|
|
aktWidth = 0;
|
|
m_nNrOfNewLine++;
|
|
|
|
if(pos_prev >= TextChars)
|
|
loop = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* check if we have to recalculate the window frame size, due to auto width and auto height */
|
|
if( m_nMode & AUTO_WIDTH)
|
|
{
|
|
reSizeMainFrameWidth(m_nMaxTextWidth);
|
|
}
|
|
|
|
if(m_nMode & AUTO_HIGH)
|
|
{
|
|
reSizeMainFrameHeight(m_nNrOfLines * m_nFontTextHeight);
|
|
}
|
|
|
|
m_nLinesPerPage = std::max(1, (m_cFrameTextRel.iHeight - (2*text_Vborder_width)) / m_nFontTextHeight);
|
|
m_nNrOfPages = ((m_nNrOfLines-1) / m_nLinesPerPage) + 1;
|
|
|
|
if(m_nCurrentPage >= m_nNrOfPages)
|
|
{
|
|
m_nCurrentPage = m_nNrOfPages - 1;
|
|
m_nCurrentLine = m_nCurrentPage * m_nLinesPerPage;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
TRACE_1(" m_nNrOfPages: %d\r\n",m_nNrOfPages);
|
|
TRACE_1(" m_nNrOfLines: %d\r\n",m_nNrOfLines);
|
|
TRACE_1(" m_nNrOfNewLine: %d\r\n",m_nNrOfNewLine);
|
|
TRACE_1(" maxTextWidth: %d\r\n",maxTextWidth);
|
|
TRACE_1(" m_nLinesPerPage: %d\r\n",m_nLinesPerPage);
|
|
TRACE_1(" m_nFontTextHeight:%d\r\n",m_nFontTextHeight);
|
|
TRACE_1(" m_nCurrentPage: %d\r\n",m_nCurrentPage);
|
|
TRACE_1(" m_nCurrentLine: %d\r\n",m_nCurrentLine);
|
|
#endif
|
|
}
|
|
|
|
void CTextBox::refreshScroll(void)
|
|
{
|
|
if(!(m_nMode & SCROLL))
|
|
return;
|
|
|
|
if( frameBuffer == NULL)
|
|
return;
|
|
|
|
/*
|
|
FIXME: Find right conditions.
|
|
So long let's paint scrollbar background in every case
|
|
to avoid transparent spaces in scrollbar corners.
|
|
*/
|
|
if (1)
|
|
{
|
|
/*
|
|
Why we paint scrollbar background seperately?
|
|
So we have to reduce roundings from the left side of background.
|
|
*/
|
|
int BgRadiusType = CORNER_NONE;
|
|
if (m_nBgRadiusType == CORNER_ALL)
|
|
BgRadiusType = CORNER_RIGHT;
|
|
else if (m_nBgRadiusType == CORNER_TOP)
|
|
BgRadiusType = CORNER_TOP_RIGHT;
|
|
else if (m_nBgRadiusType == CORNER_BOTTOM)
|
|
BgRadiusType = CORNER_BOTTOM_RIGHT;
|
|
|
|
frameBuffer->paintBoxRel(m_cFrameScrollRel.iX+m_cFrame.iX, m_cFrame.iY,
|
|
m_cFrameScrollRel.iWidth, m_cFrame.iHeight,
|
|
m_textBackgroundColor, m_nBgRadius, BgRadiusType);
|
|
}
|
|
|
|
if (m_nNrOfPages > 1)
|
|
{
|
|
frameBuffer->paintBoxRel(m_cFrameScrollRel.iX+m_cFrame.iX, m_cFrameScrollRel.iY+m_cFrame.iY,
|
|
m_cFrameScrollRel.iWidth, m_cFrameScrollRel.iHeight,
|
|
COL_SCROLLBAR_PASSIVE_PLUS_0, RADIUS_MIN);
|
|
unsigned int marker_size = (m_cFrameScrollRel.iHeight - 2*SCROLL_MARKER_BORDER) / m_nNrOfPages;
|
|
frameBuffer->paintBoxRel(m_cFrameScrollRel.iX + SCROLL_MARKER_BORDER + m_cFrame.iX,
|
|
m_cFrameScrollRel.iY + SCROLL_MARKER_BORDER + m_nCurrentPage * marker_size + m_cFrame.iY,
|
|
m_cFrameScrollRel.iWidth - 2*SCROLL_MARKER_BORDER,
|
|
marker_size, COL_SCROLLBAR_ACTIVE_PLUS_0, RADIUS_MIN);
|
|
m_has_scrolled = true;
|
|
}
|
|
else
|
|
m_has_scrolled = false;
|
|
}
|
|
|
|
//evaluate comparsion between old and current properties WITHOUT text contents, return true if found changes
|
|
//first init is done in initVar() and reinit done in reInitToCompareVar()
|
|
bool CTextBox::hasChanged(int* x, int* y, int* dx, int* dy)
|
|
{
|
|
if ( hasChangedPos(x, y)
|
|
|| hasChangedDim(dx, dy)
|
|
|| m_old_textBackgroundColor != m_textBackgroundColor
|
|
|| m_old_textColor != m_textColor
|
|
|| m_old_nBgRadius != m_nBgRadius
|
|
|| m_old_nBgRadiusType != m_nBgRadiusType
|
|
|| m_old_nMode != m_nMode){
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CTextBox::hasChangedPos(int* x, int* y)
|
|
{
|
|
return (m_old_x != *x || m_old_y != *y);
|
|
}
|
|
|
|
bool CTextBox::hasChangedDim(int* dx, int* dy)
|
|
{
|
|
return (m_old_dx != *dx || m_old_dy != *dy);
|
|
}
|
|
|
|
void CTextBox::reInitToCompareVar(int* x, int* y, int* dx, int* dy)
|
|
{
|
|
m_old_x = *x;
|
|
m_old_y = *y;
|
|
m_old_dx = *dx;
|
|
m_old_dy = *dy;
|
|
m_old_textBackgroundColor = m_textBackgroundColor;
|
|
m_old_textColor = m_textColor;
|
|
m_old_nBgRadius = m_nBgRadius;
|
|
m_old_nBgRadiusType = m_nBgRadiusType;
|
|
m_old_nMode = m_nMode;
|
|
}
|
|
|
|
void CTextBox::refreshText(void)
|
|
{
|
|
//TRACE("[CTextBox] %s Line %d\r\n", __FUNCTION__, __LINE__);
|
|
|
|
if( frameBuffer == NULL)
|
|
return;
|
|
|
|
//TRACE("[CTextBox] m_nCurrentLine: %d, m_nNrOfLines %d, m_cLineArray[m_nCurrentLine]: %s m_nBgRadius: %d\r\n",m_nCurrentLine, m_nNrOfLines, m_cLineArray[m_nCurrentLine].c_str(), m_nBgRadius, m_nBgRadiusType);
|
|
|
|
//bg variables
|
|
int ax = m_cFrameTextRel.iX+m_cFrame.iX;
|
|
int ay = m_cFrameTextRel.iY+m_cFrame.iY;
|
|
int dx = m_old_cText != m_cText || m_nNrOfPages>1 ? m_cFrameTextRel.iWidth : m_nMaxTextWidth - (m_nMode & SCROLL ? m_nBgRadius : 0);
|
|
int dy = m_cFrameTextRel.iHeight;
|
|
|
|
//avoid artefacts in transparent cornes
|
|
/*
|
|
This happens, when text width is smaller then the radius width.
|
|
*/
|
|
dx = std::max(dx, 2*m_nBgRadius);
|
|
|
|
//find changes
|
|
bool has_changed = hasChanged(&ax, &ay, &dx, &dy);
|
|
|
|
//clean up possible screen on any changes
|
|
if (has_changed || m_bgpixbuf){
|
|
/*TODO/FIXME: in some cases could be required, that we must restore old saved screen. eg. if a text without bg was painted
|
|
* and another text should be painted as next on the same position like current text, but new text will be overpaint and is
|
|
* not visible. It's currently solvable only with appropriate order of text items
|
|
*/
|
|
if (m_bgpixbuf)
|
|
frameBuffer->RestoreScreen(m_old_x, m_old_y, m_old_dx, m_old_dy, m_bgpixbuf);
|
|
clearScreenBuffer();
|
|
}
|
|
|
|
//detect corrupt position values
|
|
if ((ax<0) || (ay<0)){
|
|
dprintf(DEBUG_NORMAL, "\033[33m[CTextBox] [%s - %d] ERROR! position out of range: ax = %d, ay = %d, dx = %d, dy = %d\033[0m\n", __func__, __LINE__, ax, ay, dx, dy);
|
|
return;
|
|
}
|
|
|
|
//save screen only if no paint of background required
|
|
if (!m_nPaintBackground && m_SaveScreen) {
|
|
if (m_bgpixbuf == NULL){
|
|
if ((dx * dy) >0){
|
|
// TRACE("[CTextBox] [%s - %d] save bg for use as transparent background [%s]\n", __func__, __LINE__, m_cText.c_str());
|
|
m_bgpixbuf= new fb_pixel_t[dx * dy];
|
|
frameBuffer->SaveScreen(ax, ay, dx, dy, m_bgpixbuf);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Paint Text Background
|
|
bool allow_paint_bg = (m_old_cText != m_cText || has_changed || m_has_scrolled);
|
|
if (m_nPaintBackground && !m_SaveScreen){
|
|
clearScreenBuffer();
|
|
if (allow_paint_bg)
|
|
{
|
|
/*
|
|
Why we paint scrollbar background seperately?
|
|
So we have to reduce roundings from the right side of background.
|
|
*/
|
|
int BgRadiusType = CORNER_NONE;
|
|
if (m_nBgRadiusType == CORNER_ALL)
|
|
BgRadiusType = CORNER_LEFT;
|
|
else if (m_nBgRadiusType == CORNER_TOP)
|
|
BgRadiusType = CORNER_TOP_LEFT;
|
|
else if (m_nBgRadiusType == CORNER_BOTTOM)
|
|
BgRadiusType = CORNER_BOTTOM_LEFT;
|
|
|
|
//TRACE("[CTextBox] %s paint bg %d\r\n", __FUNCTION__, __LINE__);
|
|
//paint full background only on new text, otherwise paint required background
|
|
frameBuffer->paintBoxRel(ax, ay, dx, dy, m_textBackgroundColor, m_nBgRadius, BgRadiusType);
|
|
m_bg_painted = true;
|
|
}
|
|
}
|
|
else{
|
|
if (m_bgpixbuf){
|
|
if (allow_paint_bg){
|
|
//TRACE("[CTextBox] %s restore bg %d\r\n", __FUNCTION__, __LINE__);
|
|
frameBuffer->RestoreScreen(ax, ay, dx, dy, m_bgpixbuf);
|
|
m_bg_painted = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//save and reinit current comparsion properties
|
|
if (has_changed){
|
|
//TRACE("[CTextBox] %s set current values %d\r\n", __FUNCTION__, __LINE__);
|
|
reInitToCompareVar(&ax, &ay, &dx, &dy);
|
|
}
|
|
m_has_scrolled = false;
|
|
|
|
if( m_nNrOfLines <= 0)
|
|
return;
|
|
|
|
int y = m_cFrameTextRel.iY;
|
|
int i;
|
|
int x_center = 0;
|
|
|
|
int lines = std::min(m_nLinesPerPage, m_nNrOfLines);
|
|
|
|
// set text y position
|
|
if (m_nMode & TOP)
|
|
// move to top of frame
|
|
y += m_nFontTextHeight + ((m_cFrameTextRel.iHeight - m_nFontTextHeight * m_nLinesPerPage) >> 1);
|
|
else if (m_nMode & BOTTOM) {
|
|
/* if BOTTOM && !SCROLL, show the last lines if more than one page worth of text is in cLineArray */
|
|
if (!(m_nMode & SCROLL) && (m_nNrOfLines > m_nLinesPerPage))
|
|
m_nCurrentLine = m_nNrOfLines - m_nLinesPerPage;
|
|
// move to bottom of frame
|
|
y += m_cFrameTextRel.iHeight - (lines > 1 ? (lines - 1)*m_nFontTextHeight : 0) - text_Vborder_width;
|
|
//m_nFontTextHeight + text_Vborder_width /*- ((m_cFrameTextRel.iHeight + m_nFontTextHeight*/ * m_nLinesPerPage/*) >> 1)*/;
|
|
} else
|
|
// fit into mid of frame space
|
|
y += m_nFontTextHeight + ((m_cFrameTextRel.iHeight - m_nFontTextHeight * lines) >> 1);
|
|
|
|
#ifdef VISUAL_DEBUG
|
|
frameBuffer->paintBoxRel(m_cFrame.iX, m_cFrame.iY, m_cFrame.iWidth, m_cFrame.iHeight, COL_GREEN, m_nBgRadius, m_nBgRadiusType);
|
|
#endif
|
|
|
|
for(i = m_nCurrentLine; i < m_nNrOfLines && i < m_nCurrentLine + m_nLinesPerPage; i++)
|
|
{
|
|
//calculate xpos
|
|
if ((m_nMode & CENTER) || (m_nMode & RIGHT))
|
|
{
|
|
x_center = m_cFrameTextRel.iWidth - m_cFrameTextRel.iX - 2*text_Hborder_width - m_pcFontText->getRenderWidth(m_cLineArray[i], m_utf8_encoded);
|
|
if (m_nMode & CENTER)
|
|
x_center /= 2;
|
|
if (m_nMode & SCROLL)
|
|
x_center -= SCROLL_FRAME_WIDTH;
|
|
}
|
|
x_center = std::max(x_center, 0);
|
|
|
|
int tx = m_cFrame.iX + m_cFrameTextRel.iX + text_Hborder_width + x_center;
|
|
int ty = m_cFrame.iY + y;
|
|
int tw = m_cFrameTextRel.iWidth - m_cFrameTextRel.iX - 2*text_Hborder_width - x_center;
|
|
|
|
#ifdef VISUAL_DEBUG
|
|
int th = m_nFontTextHeight;
|
|
frameBuffer->paintBoxRel(tx, ty-th, tw, th, COL_RED, m_nBgRadius, m_nBgRadiusType);
|
|
#endif
|
|
//TRACE("[CTextBox] %s Line %d m_cFrame.iX %d m_cFrameTextRel.iX %d\r\n", __FUNCTION__, __LINE__, m_cFrame.iX, m_cFrameTextRel.iX);
|
|
if (m_bg_painted || (m_old_cText != m_cText))
|
|
m_pcFontText->RenderString(tx, ty, tw, m_cLineArray[i].c_str(), m_textColor, 0, m_renderMode | ((m_utf8_encoded) ? Font::IS_UTF8 : 0));
|
|
y += m_nFontTextHeight;
|
|
}
|
|
m_old_cText = m_cText;
|
|
}
|
|
|
|
void CTextBox::scrollPageDown(const int pages)
|
|
{
|
|
//TRACE("[CTextBox] %s Line %d\r\n", __FUNCTION__, __LINE__);
|
|
if( !(m_nMode & SCROLL))
|
|
return;
|
|
|
|
if( m_nNrOfLines <= 0)
|
|
return;
|
|
|
|
if(m_nCurrentPage + pages < m_nNrOfPages)
|
|
{
|
|
m_nCurrentPage += pages;
|
|
}
|
|
else
|
|
{
|
|
m_nCurrentPage = m_nNrOfPages - 1;
|
|
}
|
|
int oldCurrentLine = m_nCurrentLine;
|
|
m_nCurrentLine = m_nCurrentPage * m_nLinesPerPage;
|
|
if (oldCurrentLine != m_nCurrentLine)
|
|
refresh();
|
|
OnAfterScrollPage();
|
|
}
|
|
|
|
void CTextBox::scrollPageUp(const int pages)
|
|
{
|
|
//TRACE("[CTextBox] %s Line %d\r\n", __FUNCTION__, __LINE__);
|
|
if( !(m_nMode & SCROLL))
|
|
return;
|
|
|
|
if( m_nNrOfLines <= 0)
|
|
return;
|
|
|
|
if(m_nCurrentPage - pages > 0)
|
|
{
|
|
m_nCurrentPage -= pages;
|
|
}
|
|
else
|
|
{
|
|
m_nCurrentPage = 0;
|
|
}
|
|
int oldCurrentLine = m_nCurrentLine;
|
|
m_nCurrentLine = m_nCurrentPage * m_nLinesPerPage;
|
|
if (oldCurrentLine != m_nCurrentLine)
|
|
refresh();
|
|
OnAfterScrollPage();
|
|
}
|
|
|
|
void CTextBox::refresh(void)
|
|
{
|
|
//TRACE("[CTextBox] %s Line %d\r\n", __FUNCTION__, __LINE__);
|
|
if( frameBuffer == NULL)
|
|
return;
|
|
|
|
//Paint text
|
|
refreshScroll();
|
|
refreshText();
|
|
OnAfterRefresh();
|
|
}
|
|
|
|
|
|
bool CTextBox::setText(const std::string* newText, int max_width, bool force_repaint)
|
|
{
|
|
//TRACE("[CTextBox]->SetText \r\n");
|
|
m_nMaxTextWidth = max_width;
|
|
//reset text to force repaint the text, managed in hasChanged()
|
|
if (force_repaint)
|
|
m_old_cText = "";
|
|
//printf("setText: _max_width %d max_width %d\n", _max_width, max_width);
|
|
if (newText){
|
|
m_cText = *newText;
|
|
if (m_old_cText != m_cText){
|
|
//m_cText = *newText + "\n"; //FIXME test
|
|
reSizeMainFrameHeight(m_cFrame.iHeight);
|
|
//refresh text line array
|
|
refreshTextLineArray();
|
|
refresh();
|
|
return true;
|
|
}
|
|
return false;
|
|
}else
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CTextBox::paint (void)
|
|
{
|
|
//TRACE("[CTextBox] %s Line %d\r\n", __FUNCTION__, __LINE__);
|
|
#if 0
|
|
TRACE(" Mode: ");
|
|
if(m_nMode & SCROLL) TRACE("SCROLL ");
|
|
if(m_nMode & NO_AUTO_LINEBREAK) TRACE("NO_AUTO_LINEBREAK ");
|
|
if(m_nMode & AUTO_WIDTH) TRACE("AUTO_WIDTH ");
|
|
if(m_nMode & AUTO_HIGH) TRACE("AUTO_HIGH ");
|
|
if(m_nMode & CENTER) TRACE("CENTER ");
|
|
if(m_nMode & RIGHT) TRACE("RIGHT ");
|
|
if(m_nMode & TOP) TRACE("TOP ");
|
|
if(m_nMode & BOTTOM) TRACE("BOTTOM ");
|
|
TRACE("\r\n");
|
|
|
|
#endif
|
|
if(frameBuffer != NULL)
|
|
return;
|
|
|
|
frameBuffer = CFrameBuffer::getInstance();
|
|
refresh();
|
|
}
|
|
|
|
void CTextBox::hide (void)
|
|
{
|
|
//TRACE("[CTextBox] %s Line %d\r\n", __FUNCTION__, __LINE__);
|
|
if(frameBuffer == NULL)
|
|
return;
|
|
|
|
if (m_nPaintBackground)
|
|
frameBuffer->paintBackgroundBoxRel(m_cFrame.iX, m_cFrame.iY, m_cFrame.iWidth, m_cFrame.iHeight);
|
|
|
|
frameBuffer = NULL;
|
|
}
|
|
|
|
void CTextBox::clear(void)
|
|
{
|
|
//TRACE("[CTextBox] %s Line %d\r\n", __FUNCTION__, __LINE__);
|
|
if (frameBuffer == NULL)
|
|
return;
|
|
|
|
std::string empty(" ");
|
|
setText(&empty);
|
|
}
|
|
|
|
bool CTextBox::clearScreenBuffer()
|
|
{
|
|
if(m_bgpixbuf){
|
|
//TRACE("[CTextBox] %s destroy bg %d\r\n", __FUNCTION__, __LINE__);
|
|
delete[] m_bgpixbuf;
|
|
m_bgpixbuf = NULL;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CTextBox::enableSaveScreen(bool mode)
|
|
{
|
|
if (m_SaveScreen == mode)
|
|
return false;
|
|
|
|
if (!m_SaveScreen || m_SaveScreen != mode)
|
|
clearScreenBuffer();
|
|
|
|
m_SaveScreen = mode;
|
|
|
|
return true;
|
|
}
|
|
|
|
int CTextBox::getLines(const std::string& text)
|
|
{
|
|
if (text.empty())
|
|
return 0;
|
|
|
|
std::stringstream s (text);
|
|
if (!s)
|
|
return 0;
|
|
|
|
int count = 0;
|
|
std::string line;
|
|
while(getline(s, line))
|
|
count++;
|
|
|
|
return count;
|
|
}
|
|
|
|
int CTextBox::getMaxLineWidth(const std::string& text, Font* font)
|
|
{
|
|
std::string txt = text;
|
|
if (txt.find('\n', 0) == std::string::npos){
|
|
/* If found no linebreak, return pure size with additional space char.
|
|
* Space char simulates a line termination as a workaround to get
|
|
* largest possible width.
|
|
*/
|
|
txt += ' ';
|
|
return font->getRenderWidth(txt.c_str());
|
|
}
|
|
|
|
std::stringstream in (txt);
|
|
if (!in)
|
|
return 0;
|
|
|
|
int len = 0;
|
|
std::string line;
|
|
while(getline(in, line))
|
|
len = std::max(len, font->getRenderWidth(line.c_str()));
|
|
|
|
return len;
|
|
}
|