///
/// Copyright (C) 2004-2007 Andrej Vodopivec <andrejv@users.sourceforge.net>
///
/// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
///
#include "MathCell.h"
MathCell::MathCell()
{
m_next = NULL;
m_previous = NULL;
m_previousToDraw = NULL;
m_nextToDraw = NULL;
m_fullWidth = -1;
m_lineWidth = -1;
m_maxCenter = -1;
m_maxDrop = -1;
m_width = -1;
m_height = -1;
m_breakLine = false;
m_breakPage = false;
m_forceBreakLine = false;
m_bigSkip = true;
m_isFolded = false;
m_isHidden = false;
m_isBroken = false;
m_highlight = false;
m_type = MC_TYPE_TEXT;
m_textStyle = TS_NORMAL_TEXT;
}
/***
* Derived classes must test if m_next if not NULL end delete it!!!
*/
MathCell::~MathCell()
{}
/***
* Append new cell to the end of group.
*/
void MathCell::AppendCell(MathCell *p_next)
{
if (p_next == NULL)
return ;
m_maxDrop = -1;
if (m_next == NULL)
{
m_next = p_next;
m_next->m_previous = this;
MathCell *tmp = this;
while (tmp->m_nextToDraw != NULL)
tmp = tmp->m_nextToDraw;
tmp->m_nextToDraw = p_next;
p_next->m_previousToDraw = tmp;
}
else
m_next->AppendCell(p_next);
};
/***
* Get the maximum drop of the center.
*/
int MathCell::GetMaxCenter()
{
int center = m_isBroken ? 0 : m_center;
if (m_maxCenter == -1)
{
if (m_nextToDraw == NULL)
m_maxCenter = center;
else
{
// If the next cell is on a new line, maxCenter is m_center
if (m_nextToDraw->m_breakLine && !m_nextToDraw->m_isBroken)
m_maxCenter = center;
else
m_maxCenter = MAX(center, m_nextToDraw->GetMaxCenter());
}
}
return m_maxCenter;
}
/***
* Get the maximum drop of cell.
*/
int MathCell::GetMaxDrop()
{
if (m_maxDrop == -1)
{
int drop = m_isBroken ? 0 : (m_height - m_center);
if (m_nextToDraw == NULL)
m_maxDrop = drop;
else
{
if (m_nextToDraw->m_breakLine && !m_nextToDraw->m_isBroken)
m_maxDrop = drop;
else
m_maxDrop = MAX(drop, m_nextToDraw->GetMaxDrop());
}
}
return m_maxDrop;
}
/***
* Get the maximum hight of cells in line.
*/
int MathCell::GetMaxHeight()
{
return GetMaxCenter() + GetMaxDrop();
}
/***
* Get full width of this group.
*/
int MathCell::GetFullWidth(double scale)
{
if (m_fullWidth == -1)
{
if (m_next == NULL)
m_fullWidth = m_width;
else
m_fullWidth = m_width + m_next->GetFullWidth(scale) +
SCALE_PX(MC_CELL_SKIP, scale);
}
return m_fullWidth;
}
/***
* Get the width of this line.
*/
int MathCell::GetLineWidth(double scale)
{
int width = m_isBroken ? 0 : m_width;
if (m_lineWidth == -1)
{
if (m_nextToDraw == NULL || m_nextToDraw->m_breakLine ||
m_nextToDraw->m_type == MC_TYPE_MAIN_PROMPT)
m_lineWidth = width;
else
m_lineWidth = width + m_nextToDraw->GetLineWidth(scale) +
SCALE_PX(MC_CELL_SKIP, scale);
}
return m_lineWidth;
}
/***
* Draw this cell to dc (each derived class must draw the content of the cell
* and then call MathCall::Draw(...).
*/
void MathCell::Draw(CellParser& parser, wxPoint point, int fontsize, bool all)
{
m_currentPoint.x = point.x;
m_currentPoint.y = point.y;
if (m_nextToDraw != NULL && all)
{
double scale = parser.GetScale();
point.x += m_width + SCALE_PX(MC_CELL_SKIP, scale);
m_nextToDraw->Draw(parser, point, fontsize, true);
}
}
/***
* Calculate the size of cell, only needed once. Each derived class must call
* MathCell::RecalculateSize(...).
*
* Should set: m_height, m_center.
*/
void MathCell::RecalculateSize(CellParser& parser, int fontsize, bool all)
{
if (m_next != NULL && all)
m_next->RecalculateSize(parser, fontsize, all);
}
/***
* Recalculate widths of cells. (Used for changing font size - must recalculate
* all size information).
*
* Should set: set m_width.
*/
void MathCell::RecalculateWidths(CellParser& parser, int fontsize, bool all)
{
ResetData();
if (m_next != NULL && all)
m_next->RecalculateWidths(parser, fontsize, all);
}
/***
* Is this cell visible in the window.
*/
bool MathCell::DrawThisCell(CellParser& parser, wxPoint point)
{
int top = parser.GetTop();
int bottom = parser.GetBottom();
if (top == -1 || bottom == -1)
return true;
if (point.y - GetMaxCenter() > bottom || point.y + GetMaxDrop() < top)
return false;
return true;
}
/***
* Get the rectangle around this cell - if all is true then return the rectangle
* around the whole line.
*/
wxRect MathCell::GetRect(bool all)
{
if (m_isBroken)
return wxRect( -1, -1, 0, 0);
if (all)
return wxRect(m_currentPoint.x, m_currentPoint.y - GetMaxCenter(),
GetLineWidth(1.0), GetMaxHeight());
return wxRect(m_currentPoint.x, m_currentPoint.y - m_center,
m_width, m_height);
}
/***
* Draws a box around this cell - if all is true draws a box around the whole
* line.
*/
void MathCell::DrawBoundingBox(wxDC& dc, bool all)
{
wxRect rect = GetRect(all);
int x = rect.GetX(), y = rect.GetY();
int width = rect.GetWidth(), height = rect.GetHeight();
dc.DrawRectangle(x - 1, y - 1, width + 2, height + 2);
}
/***
* Do we have an operator in this line - draw () in frac...
*/
bool MathCell::IsCompound()
{
if (IsOperator())
return true;
if (m_next == NULL)
return false;
return m_next->IsCompound();
}
/***
* Is operator - draw () in frac...
*/
bool MathCell::IsOperator()
{
return false;
}
/***
* Return the string representation of cell.
*/
wxString MathCell::ToString(bool all)
{
if (all && m_next != NULL)
return m_next->ToString(all);
return wxEmptyString;
}
wxString MathCell::ToTeX(bool all)
{
if (all && m_next != NULL)
return m_next->ToTeX(all);
return wxEmptyString;
}
/***
* Get the part for diff tag support - only ExpTag overvrides this.
*/
wxString MathCell::GetDiffPart()
{
return wxEmptyString;
}
/***
* Find the first and last cell in rectangle rect in this line.
*/
void MathCell::SelectRect(wxRect& rect, MathCell** first, MathCell** last)
{
SelectFirst(rect, first);
if (*first != NULL)
{
*last = *first;
(*first)->SelectLast(rect, last);
if (*last == *first)
(*first)->SelectInner(rect, first, last);
}
else
*last = NULL;
}
/***
* Find the first cell in rectangle rect in this line.
*/
void MathCell::SelectFirst(wxRect& rect, MathCell** first)
{
if (rect.Intersects(GetRect(false)))
*first = this;
else if (m_nextToDraw != NULL)
m_nextToDraw->SelectFirst(rect, first);
else
*first = NULL;
}
/***
* Find the last cell in rectangle rect in this line.
*/
void MathCell::SelectLast(wxRect& rect, MathCell** last)
{
if (rect.Intersects(GetRect(false)))
*last = this;
if (m_nextToDraw != NULL)
m_nextToDraw->SelectLast(rect, last);
}
/***
* Select rectangle in deeper cell - derived classes should override this
*/
void MathCell::SelectInner(wxRect& rect, MathCell** first, MathCell** last)
{
*first = this;
*last = this;
}
/***
* Break line when the cell is not broken only.
*/
bool MathCell::BreakLineHere()
{
return (!m_isBroken && (m_breakLine || m_forceBreakLine));
}
/***
* Does this cell contain a rectangle sm
*/
bool MathCell::ContainsRect(wxRect& sm, bool all)
{
wxRect big = GetRect(all);
if (big.x <= sm.x &&
big.y <= sm.y &&
big.x + big.width >= sm.x + sm.width &&
big.y + big.height >= sm.y + sm.height)
return true;
return false;
}
/***
* Resets remembered data.
*/
void MathCell::ResetData()
{
m_fullWidth = -1;
m_lineWidth = -1;
m_maxCenter = -1;
m_maxDrop = -1;
// m_currentPoint.x = -1;
// m_currentPoint.y = -1;
m_breakLine = false;
}
/***
* Unbreaks broken cells
*/
void MathCell::Unbreak(bool all)
{
ResetData();
m_isBroken = false;
if (!m_isFolded)
{
m_nextToDraw = m_next;
if (m_nextToDraw != NULL)
m_nextToDraw->m_previousToDraw = this;
}
if (all && m_next != NULL)
m_next->Unbreak(all);
}
/***
* Set the pen in device context accordint to the style of the cell.
*/
void MathCell::SetPen(CellParser& parser)
{
wxDC& dc = parser.GetDC();
if (m_highlight)
dc.SetPen(*(wxThePenList->FindOrCreatePen(parser.GetColor(TS_HIGHLIGHT),
1, wxSOLID)));
else if (m_type == MC_TYPE_PROMPT)
dc.SetPen(*(wxThePenList->FindOrCreatePen(parser.GetColor(TS_OTHER_PROMPT),
1, wxSOLID)));
else if (m_type == MC_TYPE_INPUT)
dc.SetPen(*(wxThePenList->FindOrCreatePen(parser.GetColor(TS_INPUT),
1, wxSOLID)));
}
/***
* Reset the pen in the device context.
*/
void MathCell::UnsetPen(CellParser& parser)
{
wxDC& dc = parser.GetDC();
if (m_type == MC_TYPE_PROMPT || m_type == MC_TYPE_INPUT || m_highlight)
dc.SetPen(*(wxThePenList->FindOrCreatePen(parser.GetColor(TS_NORMAL_TEXT),
1, wxSOLID)));
}
/***
* Copy all importatn data from s to t
*/
void MathCell::CopyData(MathCell* s, MathCell* t)
{
t->m_forceBreakLine = s->m_forceBreakLine;
t->m_type = s->m_type;
}
void MathCell::SetForeground(CellParser& parser)
{
wxDC& dc = parser.GetDC();
if (m_highlight)
{
dc.SetTextForeground(wxTheColourDatabase->Find(parser.GetColor(TS_HIGHLIGHT)));
return ;
}
switch (m_type)
{
case MC_TYPE_PROMPT:
dc.SetTextForeground(wxTheColourDatabase->Find(parser.GetColor(TS_OTHER_PROMPT)));
break;
case MC_TYPE_MAIN_PROMPT:
dc.SetTextForeground(wxTheColourDatabase->Find(parser.GetColor(TS_MAIN_PROMPT)));
break;
case MC_TYPE_ERROR:
dc.SetTextForeground(wxTheColourDatabase->Find(wxT("red")));
break;
case MC_TYPE_LABEL:
dc.SetTextForeground(wxTheColourDatabase->Find(parser.GetColor(TS_LABEL)));
break;
default:
dc.SetTextForeground(wxTheColourDatabase->Find(parser.GetColor(m_textStyle)));
break;
}
}
syntax highlighted by Code2HTML, v. 0.9.1