///
/// 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 "wxMaxima.h"
#include "MathCtrl.h"
#include "Bitmap.h"
#include "Setup.h"
#include <wx/clipbrd.h>
#include <wx/config.h>
#include <wx/settings.h>
#include <wx/filename.h>
#include <wx/textfile.h>
#include <wx/tokenzr.h>
#if wxUSE_DRAG_AND_DROP && WXM_DND
#include <wx/dnd.h>
#endif
#define SCROLL_UNIT 10
#define CARET_TIMER_TIMEOUT 500
void AddLineToFile(wxTextFile& output, wxString s, bool unicode = true);
enum {
TIMER_ID,
CARET_TIMER_ID
};
MathCtrl::MathCtrl(wxWindow* parent, int id, wxPoint position, wxSize size):
wxScrolledWindow(parent, id, position, size,
wxVSCROLL | wxHSCROLL | wxSUNKEN_BORDER | wxWANTS_CHARS)
{
m_scrollTo = -1;
m_tree = NULL;
m_memory = NULL;
m_selectionStart = NULL;
m_selectionEnd = NULL;
m_last = NULL;
m_insertPoint = NULL;
m_activeCell = NULL;
m_leftDown = false;
m_mouseDrag = false;
m_mouseOutside = false;
m_forceUpdate = false;
m_editingEnabled = true;
m_switchDisplayCaret = true;
m_timer.SetOwner(this, TIMER_ID);
m_caretTimer.SetOwner(this, CARET_TIMER_ID);
AdjustSize(false);
}
MathCtrl::~MathCtrl ()
{
if (m_tree != NULL)
DestroyTree();
if (m_memory != NULL)
delete m_memory;
}
/***
* Redraw the control
*/
void MathCtrl::OnPaint(wxPaintEvent& event)
{
wxPaintDC dc(this);
wxMemoryDC dcm;
// Get the font size
wxConfig *config = (wxConfig *)wxConfig::Get();
int fontsize = 12;
config->Read(wxT("fontSize"), &fontsize);
// Prepare data
wxRect rect = GetUpdateRegion().GetBox();
//printf("Updating rect [%d, %d] -> [%d, %d]\n", rect.x, rect.y, rect.width, rect.height);
wxSize sz = GetSize();
int tmp, top, bottom, drop;
CalcUnscrolledPosition(0, rect.GetTop(), &tmp, &top);
CalcUnscrolledPosition(0, rect.GetBottom(), &tmp, &bottom);
// Thest if m_memory is NULL (resize event)
if (m_memory == NULL)
m_memory = new wxBitmap(sz.x, sz.y);
// Prepare memory DC
wxString bgColStr = wxT("white");
config->Read(wxT("Style/Background/color"), &bgColStr);
SetBackgroundColour(wxTheColourDatabase->Find(bgColStr));
dcm.SelectObject(*m_memory);
dcm.SetBackground(*(wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID)));
dcm.Clear();
PrepareDC(dcm);
dcm.SetMapMode(wxMM_TEXT);
dcm.SetBackgroundMode(wxTRANSPARENT);
// Draw content
if (m_tree != NULL)
{
wxPoint point;
point.x = MC_BASE_INDENT;
point.y = MC_BASE_INDENT + m_tree->GetMaxCenter();
// Draw tree
MathCell* tmp = m_tree;
drop = tmp->GetMaxDrop();
CellParser parser(dcm);
parser.SetBouns(top, bottom);
while (tmp != NULL)
{
if (!tmp->m_isBroken)
{
tmp->m_currentPoint.x = point.x;
tmp->m_currentPoint.y = point.y;
if (tmp->DrawThisCell(parser, point))
tmp->Draw(parser, point, fontsize, false);
if (tmp->m_nextToDraw != NULL)
{
if (tmp->m_nextToDraw->BreakLineHere())
{
point.x = MC_BASE_INDENT;
point.y += drop + tmp->m_nextToDraw->GetMaxCenter();
if (tmp->m_bigSkip)
point.y += MC_LINE_SKIP;
drop = tmp->m_nextToDraw->GetMaxDrop();
}
else
point.x += (tmp->GetWidth() + MC_CELL_SKIP);
}
}
else
{
if (tmp->m_nextToDraw != NULL && tmp->m_nextToDraw->BreakLineHere())
{
point.x = MC_BASE_INDENT;
point.y += drop + tmp->m_nextToDraw->GetMaxCenter();
if (tmp->m_bigSkip)
point.y += MC_LINE_SKIP;
drop = tmp->m_nextToDraw->GetMaxDrop();
}
}
tmp = tmp->m_nextToDraw;
}
// Draw selection
if (m_selectionStart != NULL)
{
MathCell* tmp = m_selectionStart;
dcm.SetLogicalFunction(wxAND);
dcm.SetBrush(*wxLIGHT_GREY_BRUSH);
dcm.SetPen(*wxLIGHT_GREY_PEN);
// We have a selection with click
if (m_selectWholeLine)
{
if (m_selectionStart == m_selectionEnd)
m_selectionStart->DrawBoundingBox(dcm);
else
{
while (tmp != NULL && tmp->m_isBroken)
tmp = tmp->m_nextToDraw;
if (tmp != NULL)
tmp->DrawBoundingBox(dcm, true);
while (tmp != NULL)
{
tmp = tmp->m_nextToDraw;
if (tmp == NULL)
break;
if (tmp->BreakLineHere() && !tmp->m_isBroken)
tmp->DrawBoundingBox(dcm, true);
if (tmp == m_selectionEnd)
break;
}
}
}
// We have a selection by dragging
else
{
while (1)
{
if (!tmp->m_isBroken && !tmp->m_isHidden)
tmp->DrawBoundingBox(dcm, false);
if (tmp == m_selectionEnd)
break;
tmp = tmp->m_nextToDraw;
if (tmp == NULL)
break;
}
}
}
}
// Blit the memory image to the window
dcm.SetDeviceOrigin(0, 0);
dc.Blit(0, rect.GetTop(),
sz.x, rect.GetBottom() - rect.GetTop() + 1,
&dcm,
0, rect.GetTop());
}
/***
* Add a new line
*/
void MathCtrl::InsertLine(MathCell *newNode, bool forceNewLine)
{
if (newNode == NULL)
return ;
if (m_insertPoint == NULL)
AddLine(newNode, forceNewLine);
else
{
MathCell *tmp = newNode;
while (tmp->m_next != NULL)
tmp = tmp->m_next;
InsertAfter(m_insertPoint, newNode, forceNewLine);
m_insertPoint = tmp;
}
}
void MathCtrl::AddLine(MathCell *newNode, bool forceNewLine)
{
Freeze();
if (newNode == NULL)
return ;
if (m_tree == NULL)
{
m_tree = newNode;
m_last = m_tree;
}
else
{
while (m_last->m_next != NULL)
m_last = m_last->m_next;
m_last->AppendCell(newNode);
}
newNode->ForceBreakLine(forceNewLine);
Recalculate(newNode, true);
m_selectionStart = NULL;
m_selectionEnd = NULL;
Thaw();
if (m_insertPoint == NULL)
Refresh();
}
/***
* Recalculate dimensions of cells
*/
void MathCtrl::RecalculateForce()
{
if (m_tree != NULL)
{
m_forceUpdate = true;
Recalculate(m_tree, false);
m_forceUpdate = false;
}
}
void MathCtrl::Recalculate(bool scroll)
{
UnBreakUpCells();
if (m_tree != NULL)
Recalculate(m_tree, scroll);
}
/***
* Recalculate size of this line
*/
void MathCtrl::Recalculate(MathCell *cell, bool scroll)
{
RecalculateWidths(cell);
RecalculateSize(cell);
BreakUpCells(cell);
BreakLines(cell);
AdjustSize(scroll);
}
/***
* Recalculate widths of cells
*/
void MathCtrl::RecalculateWidths()
{
if (m_tree != NULL)
RecalculateWidths(m_tree);
}
void MathCtrl::RecalculateWidths(MathCell* tmp)
{
wxConfig *config = (wxConfig *)wxConfig::Get();
int fontsize = 12;
config->Read(wxT("fontSize"), &fontsize);
wxClientDC dc(this);
CellParser parser(dc);
parser.SetForceUpdate(m_forceUpdate);
while (tmp != NULL)
{
tmp->RecalculateWidths(parser, fontsize, false);
tmp = tmp->m_next;
}
}
/***
* Recalculate sizes of cells
*/
void MathCtrl::RecalculateSize()
{
if (m_tree != NULL)
RecalculateSize(m_tree);
}
void MathCtrl::RecalculateSize(MathCell* tmp)
{
wxConfig *config = (wxConfig *)wxConfig::Get();
int fontsize = 12;
config->Read(wxT("fontSize"), &fontsize);
wxClientDC dc(this);
CellParser parser(dc);
parser.SetForceUpdate(m_forceUpdate);
while (tmp != NULL)
{
if (!tmp->m_isBroken)
tmp->RecalculateSize(parser, fontsize, false);
tmp = tmp->m_nextToDraw;
}
}
/***
* Resize the controll
*/
void MathCtrl::OnSize(wxSizeEvent& event)
{
wxDELETE(m_memory);
if (m_tree != NULL)
{
m_selectionStart = NULL;
m_selectionEnd = NULL;
Recalculate(false);
}
Refresh();
wxScrolledWindow::OnSize(event);
}
/***
* Clear the window
*/
void MathCtrl::ClearWindow()
{
if (m_tree != NULL)
{
SetActiveCell(NULL);
DestroyTree();
m_selectionStart = NULL;
m_selectionEnd = NULL;
m_last = NULL;
}
Refresh();
Scroll(0, 0);
}
/***
* Right mouse - popup-menu
*/
void MathCtrl::OnMouseRightUp(wxMouseEvent& event)
{
wxMenu* popupMenu = new wxMenu();
if (m_activeCell == NULL)
{
/* If we have no selection or we are not in editing mode don't popup a menu!*/
if (!(CanCopy() || CanAddComment()) || m_editingEnabled == false)
return ;
if (m_selectionStart != NULL &&
m_selectionStart == m_selectionEnd &&
m_selectionStart->GetType() == MC_TYPE_IMAGE)
{
#if defined __WXMSW__
popupMenu->Append(popid_image_copy, _("Copy"), wxEmptyString, wxITEM_NORMAL);
#endif
popupMenu->Append(popid_image, _("Save image"), wxEmptyString, wxITEM_NORMAL);
}
else
{
if (CanCopy())
{
popupMenu->Append(popid_copy, _("Copy"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_copy_text, _("Copy text"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_copy_tex, _("Copy TeX"),
wxEmptyString, wxITEM_NORMAL);
#if defined __WXMSW__
popupMenu->Append(popid_copy_image, _("Copy as image"),
wxEmptyString, wxITEM_NORMAL);
#endif
if (CanDeleteSelection())
popupMenu->Append(popid_delete, _("Delete selection"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->AppendSeparator();
}
if (CanEdit())
{
if (m_selectionStart->GetType() == MC_TYPE_INPUT)
{
popupMenu->Append(popid_edit, _("Edit input"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_reeval, _("Re-evaluate input"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_insert_input, _("Insert input"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_add_comment, _("Insert text"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_comment, _("Comment out"),
wxEmptyString, wxITEM_NORMAL);
}
else
{
popupMenu->Append(popid_edit, _("Edit text"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_reeval, _("Re-evaluate input"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_insert_input, _("Insert input"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_add_comment, _("Insert text"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_uncomment, _("Uncomment"),
wxEmptyString, wxITEM_NORMAL);
}
}
else if (CanAddComment())
{
popupMenu->Append(popid_insert_input, _("Insert input"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_add_comment, _("Insert text"),
wxEmptyString, wxITEM_NORMAL);
}
else
{
popupMenu->Append(popid_float, _("To float"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->AppendSeparator();
popupMenu->Append(popid_solve, _("Solve ..."),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_solve_num, _("Solve numerically ..."),
wxEmptyString, wxITEM_NORMAL);
popupMenu->AppendSeparator();
popupMenu->Append(popid_simplify, _("Simplify expression"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_factor, _("Factor expression"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_expand, _("Expand expression"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_subst, _("Substitute ..."),
wxEmptyString, wxITEM_NORMAL);
popupMenu->AppendSeparator();
popupMenu->Append(popid_integrate, _("Integrate ..."),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_diff, _("Differentiate ..."),
wxEmptyString, wxITEM_NORMAL);
popupMenu->AppendSeparator();
popupMenu->Append(popid_plot2d, _("Plot 2d ..."),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_plot3d, _("Plot 3d ..."),
wxEmptyString, wxITEM_NORMAL);
}
}
}
else {
popupMenu->Append(popid_copy, _("Copy"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_cut, _("Cut"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Append(popid_paste, _("Paste"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->AppendSeparator();
popupMenu->Append(popid_select_all, _("Select all"),
wxEmptyString, wxITEM_NORMAL);
popupMenu->Enable(popid_copy, m_activeCell->CanCopy());
popupMenu->Enable(popid_cut, m_activeCell->CanCopy());
}
PopupMenu(popupMenu);
delete popupMenu;
}
/***
* Left mouse - selection handling
*/
void MathCtrl::OnMouseLeftDown(wxMouseEvent& event)
{
CalcUnscrolledPosition(event.GetX(), event.GetY(), &m_down.x, &m_down.y);
#if wxUSE_DRAG_AND_DROP && WXM_DND
if (m_selectionStart != NULL)
{
MathCell *tmp = NULL;
for (tmp = m_selectionStart; tmp != NULL && tmp != m_selectionEnd; tmp = tmp->m_nextToDraw)
if (tmp->ContainsPoint(m_down))
break;
if (tmp != NULL && (tmp != m_selectionEnd ||
(tmp == m_selectionEnd && tmp->ContainsPoint(m_down))))
{
wxDropSource dragSource(this);
wxTextDataObject my_data(GetString());
dragSource.SetData( my_data );
dragSource.DoDragDrop(true);
}
else
m_leftDown = true;
}
else
m_leftDown = true;
#else
m_leftDown = true;
#endif
}
void MathCtrl::OnMouseLeftUp(wxMouseEvent& event)
{
if (!m_mouseDrag)
SelectPoint(m_down);
m_leftDown = false;
m_mouseDrag = false;
CheckUnixCopy();
SetFocus();
}
void MathCtrl::OnMouseMotion(wxMouseEvent& event)
{
if (m_tree == NULL || !m_leftDown)
return ;
m_mouseDrag = true;
m_selectWholeLine = false;
CalcUnscrolledPosition(event.GetX(), event.GetY(), &m_up.x, &m_up.y);
if (m_mouseOutside)
{
m_mousePoint.x = event.GetX();
m_mousePoint.y = event.GetY();
}
SelectRect(m_down, m_up);
}
/***
* Select the rectangle sorounded by point one and two.
*/
void MathCtrl::SelectRect(wxPoint one, wxPoint two)
{
if (m_tree == NULL)
return ;
if (m_activeCell != NULL)
{
if (m_activeCell->ContainsPoint(one) && m_activeCell->ContainsPoint(two))
{
wxClientDC dc(this);
m_activeCell->SelectRectText(dc, one, two);
m_switchDisplayCaret = false;
wxRect rect = m_activeCell->GetRect();
CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
RefreshRect(rect);
}
else
{
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, deactivate_cell_cancel);
(wxGetApp().GetTopWindow())->ProcessEvent(ev);
}
return ;
}
MathCell* tmp;
wxPoint start, end;
wxRect rect;
MathCell* st = m_selectionStart;
MathCell* en = m_selectionEnd;
m_selectionStart = m_selectionEnd = NULL;
if (one.y < two.y || (one.y == two.y && one.x < two.x))
{
start = one;
end = two;
}
else
{
start = two;
end = one;
}
rect.x = MIN(m_down.x, m_up.x);
rect.y = MIN(m_down.y, m_up.y);
rect.width = MAX(ABS(m_down.x - m_up.x), 1);
rect.height = MAX(ABS(m_down.y - m_up.y), 1);
// Lets select a rectangle
tmp = m_tree;
while (tmp != NULL && !rect.Intersects(tmp->GetRect()))
tmp = tmp->m_nextToDraw;
m_selectionStart = tmp;
m_selectionEnd = tmp;
while (tmp != NULL)
{
if (rect.Intersects(tmp->GetRect()))
m_selectionEnd = tmp;
tmp = tmp->m_nextToDraw;
}
if (m_selectionStart != NULL && m_selectionEnd != NULL)
{
// If selection is on multiple lines, we need to correct it
if (m_selectionStart->GetCurrentY() != m_selectionEnd->GetCurrentY())
{
MathCell *tmp = m_selectionEnd;
MathCell *curr;
// Find the first cell in selection
while (m_selectionStart != tmp &&
(m_selectionStart->GetCurrentX() +
m_selectionStart->GetWidth() < start.x ||
m_selectionStart->GetCurrentY() +
m_selectionStart->GetDrop() < start.y))
m_selectionStart = m_selectionStart->m_nextToDraw;
// Find the last cell in selection
curr = m_selectionEnd = m_selectionStart;
while (1)
{
curr = curr->m_nextToDraw;
if (curr == NULL)
break;
if ((curr->GetCurrentX() <= end.x &&
curr->GetCurrentY() - curr->GetMaxCenter() <= end.y))
m_selectionEnd = curr;
if (curr == tmp)
break;
}
}
if (m_selectionStart == m_selectionEnd)
m_selectionStart->SelectInner(rect, &m_selectionStart, &m_selectionEnd);
}
// Refresh only if the selection has changed
if (st != m_selectionStart || en != m_selectionEnd)
Refresh();
}
/***
* Do selection when selecting by click
*/
void MathCtrl::SelectPoint(wxPoint& point)
{
if (m_tree == NULL)
return ;
// If we have active cell handle it spacial.
if (m_activeCell != NULL)
{
if (m_activeCell->ContainsPoint(m_down))
{
wxClientDC dc(this);
m_activeCell->SelectPointText(dc, m_down);
m_switchDisplayCaret = false;
Refresh();
return ;
}
else
{
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, deactivate_cell_cancel);
(wxGetApp().GetTopWindow())->ProcessEvent(ev);
}
}
MathCell* tmp = NULL;
m_selectWholeLine = true;
//
// Which cell did we select.
//
tmp = m_tree;
while (tmp != NULL)
{
if (tmp->ContainsPoint(point))
break;
tmp = tmp->m_nextToDraw;
}
if (tmp == NULL)
{
if (m_selectionStart != NULL)
{
m_selectionStart = NULL;
m_selectionEnd = NULL;
Refresh();
}
return ;
}
m_selectionStart = tmp;
m_selectionEnd = tmp;
//
// We selected output - select whole line.
//
int type = m_selectionStart->GetType();
if (type == MC_TYPE_TEXT)
{
if (m_selectionStart->GetType() == type)
{
while (m_selectionStart->m_previousToDraw != NULL &&
m_selectionStart->m_previousToDraw->GetType() == type)
m_selectionStart = m_selectionStart->m_previousToDraw;
while (m_selectionEnd->m_nextToDraw != NULL &&
m_selectionEnd->m_nextToDraw->GetType() == type)
m_selectionEnd = m_selectionEnd->m_nextToDraw;
}
}
//
// We selected a label - fold the output.
//
else if (m_selectionStart->GetType() == MC_TYPE_LABEL)
{
if (m_selectionStart->m_isFolded)
{
m_selectionStart->m_nextToDraw = m_selectionStart->m_next;
m_selectionStart->Fold(false);
m_selectionStart->ResetData();
}
else
{
while (m_selectionStart->m_nextToDraw != NULL)
{
m_selectionStart->m_nextToDraw = m_selectionStart->m_nextToDraw->m_nextToDraw;
if (m_selectionStart->m_nextToDraw != NULL &&
m_selectionStart->m_nextToDraw->GetType() != MC_TYPE_TEXT) /// BUG ...
break;
}
m_selectionStart->Fold(true);
m_selectionStart->ResetData();
}
m_selectionStart = NULL;
m_selectionEnd = NULL;
Recalculate(false);
Refresh();
return ;
}
//
// We selected prompt - fold everything to the prompt.
//
else if (m_selectionStart->GetType() == MC_TYPE_MAIN_PROMPT)
{
if (m_selectionStart->m_nextToDraw == NULL)
{
m_selectionStart = NULL;
m_selectionEnd = NULL;
Refresh();
return ;
}
if (m_selectionStart->m_isFolded)
{
m_selectionStart->m_nextToDraw = m_selectionStart->m_next;
m_selectionStart->Fold(false);
m_selectionStart->ResetData();
}
else
{
while (m_selectionStart->m_nextToDraw != NULL)
{
m_selectionStart->m_nextToDraw = m_selectionStart->m_nextToDraw->m_nextToDraw;
if (m_selectionStart->m_nextToDraw != NULL &&
m_selectionStart->m_nextToDraw->GetType() == MC_TYPE_MAIN_PROMPT)
break;
}
m_selectionStart->Fold(true);
m_selectionStart->ResetData();
}
m_selectionStart = NULL;
m_selectionEnd = NULL;
Recalculate(false);
Refresh();
return ;
}
//
// We selected something we can edit.
//
/*
if (m_selectionStart->IsEditable())
{
wxClientDC dc(this);
m_selectionStart->SelectPointText(dc, m_down);
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, popid_edit);
(wxGetApp().GetTopWindow())->ProcessEvent(ev);
}
*/
Refresh();
}
/***
* Get the string representation of the selection
*/
wxString MathCtrl::GetString(bool lb)
{
if (m_selectionStart == NULL)
return wxEmptyString;
wxString s;
MathCell* tmp = m_selectionStart;
while (tmp != NULL)
{
if (lb && tmp->BreakLineHere() && s.Length() > 0)
s += wxT("\n");
s += tmp->ToString(false);
if (tmp == m_selectionEnd)
break;
tmp = tmp->m_nextToDraw;
}
return s;
}
/***
* Copy selection to clipboard.
*/
bool MathCtrl::Copy(bool lb)
{
if (m_activeCell != NULL)
{
return m_activeCell->CopyToClipboard();
}
if (m_selectionStart == NULL)
return false;
wxString s;
MathCell* tmp = m_selectionStart;
while (tmp != NULL)
{
if (lb && tmp->BreakLineHere() && s.Length() > 0)
s += wxT("\n");
if (lb && (tmp->GetType() == MC_TYPE_PROMPT || tmp->GetType() == MC_TYPE_INPUT))
{
if (s.Length() > 0 && s.Right(1) != wxT("\n") && s.Right(1) != wxT(" "))
s += wxT(" ");
}
s += tmp->ToString(false);
if (tmp == m_selectionEnd)
break;
tmp = tmp->m_nextToDraw;
}
if (wxTheClipboard->Open())
{
wxTheClipboard->SetData(new wxTextDataObject(s));
wxTheClipboard->Close();
return true;
}
return false;
}
bool MathCtrl::CopyTeX()
{
if (m_activeCell != NULL)
return false;
if (m_selectionStart == NULL)
return false;
wxString s;
MathCell* tmp = m_selectionStart;
bool inMath = false;
bool inVerbatim = false;
wxString label;
while (tmp != NULL)
{
if (tmp->GetType() == MC_TYPE_MAIN_PROMPT || tmp->GetType() == MC_TYPE_INPUT)
{
if (inMath)
{
s += label + wxT("$$\n");
label = wxEmptyString;
inMath = false;
}
if (!inVerbatim)
{
s += wxT("\\begin{verbatim}\n");
inVerbatim = true;
}
s += tmp->ToString(false);
}
else if (tmp->GetType() == MC_TYPE_LABEL)
{
label = tmp->ToTeX(false);
}
else
{
if (inVerbatim)
{
s += wxT("\n\\end{verbatim}\n");
inVerbatim = false;
}
if (!inMath)
{
s += wxT("$$");
inMath = true;
}
s += tmp->ToTeX(false);
}
if (tmp == m_selectionEnd)
{
if (inMath)
{
s += label + wxT("$$");
label = wxEmptyString;
}
if (inVerbatim)
s += wxT("\n\\end{verbatim}\n");
break;
}
tmp = tmp->m_nextToDraw;
}
if (wxTheClipboard->Open())
{
wxTheClipboard->SetData(new wxTextDataObject(s));
wxTheClipboard->Close();
return true;
}
return false;
}
/***
* Can delete selection - we can't delete the last prompt!
*/
bool MathCtrl::CanDeleteSelection()
{
if (m_selectionStart == NULL || m_selectionEnd == NULL || m_insertPoint != NULL)
return false;
MathCell* end = m_selectionEnd;
while (end->m_nextToDraw != NULL &&
end->m_nextToDraw->m_isHidden)
end = end->m_nextToDraw;
if (end->m_nextToDraw == NULL)
return false;
if (m_selectionStart->GetType() == MC_TYPE_MAIN_PROMPT &&
(end == m_selectionStart ||
end->m_nextToDraw->GetType() == MC_TYPE_MAIN_PROMPT))
return true;
return false;
}
/***
* Delete the selection
*/
void MathCtrl::DeleteSelection(bool deletePrompt)
{
if (!CanDeleteSelection())
return ;
MathCell *start = m_selectionStart;
if (!deletePrompt)
start = start->m_next;
MathCell *end = m_selectionEnd->m_nextToDraw;
while (end != NULL && end->GetType() != MC_TYPE_MAIN_PROMPT)
end = end->m_nextToDraw;
if (end == NULL || start == NULL || end->m_previous == NULL)
return ;
// We are deleting the first cell in the tree
if (start == m_tree)
{
end->m_previous->m_next = NULL;
m_tree = end;
if (m_tree != NULL)
{
m_tree->m_previous = NULL;
m_tree->m_previousToDraw = NULL;
}
delete start;
}
// the cell to be deleted is not the first in the tree
else
{
MathCell* previous = start->m_previous;
MathCell* previousToDraw = start->m_previousToDraw;
end->m_previous->m_next = NULL;
end->m_previous = previous;
previous->m_next = end;
previousToDraw->m_nextToDraw = end;
end->m_previousToDraw = previousToDraw;
// We have to correct the m_nextToDraw for hidden group just before
// the first to be deleted - check previous label and main prompt.
// Not needed if we are not deleting the prompt.
if (deletePrompt)
{
while (previous != NULL && previous->GetType() != MC_TYPE_LABEL)
previous = previous->m_previous;
if (previous != NULL && previous->m_isFolded)
previous->m_nextToDraw = end;
while (previous != NULL && previous->GetType() != MC_TYPE_MAIN_PROMPT)
previous = previous->m_previous;
if (previous != NULL && previous->m_isFolded)
previous->m_nextToDraw = end;
}
delete start;
}
m_selectionStart = NULL;
m_selectionEnd = NULL;
m_last = m_tree;
if (m_insertPoint != NULL)
{
AdjustSize(false);
Refresh();
}
}
/***
* Support for copying and deleting with keyboard
*/
void MathCtrl::OnKeyDown(wxKeyEvent& event)
{
switch (event.GetKeyCode())
{
case 'c':
case 'C':
if (!event.ControlDown() || event.AltDown())
{
event.Skip();
break;
}
if (m_activeCell != NULL)
m_activeCell->CopyToClipboard();
else if (CanCopy())
Copy();
else
event.Skip();
break;
case 'x':
case 'X':
if (!event.ControlDown() || event.AltDown())
{
event.Skip();
break;
}
if (m_activeCell != NULL)
{
m_activeCell->CutToClipboard();
RecalculateForce();
Refresh();
}
break;
case 'v':
case 'V':
if (!event.ControlDown() || event.AltDown())
{
event.Skip();
break;
}
if (m_activeCell != NULL)
{
m_activeCell->PasteFromClipboard();
RecalculateForce();
Refresh();
}
break;
case 'a':
case 'A':
if (!event.ControlDown() || event.AltDown())
{
event.Skip();
break;
}
if (m_activeCell != NULL)
{
m_activeCell->SelectAll();
Refresh();
}
break;
case WXK_DELETE:
if (CanDeleteSelection())
{
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, popid_delete);
(wxGetApp().GetTopWindow())->ProcessEvent(ev);
}
else
event.Skip();
break;
case WXK_RETURN:
if (CanEdit())
{
if (event.ControlDown())
{
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, popid_reeval);
(wxGetApp().GetTopWindow())->ProcessEvent(ev);
}
else
{
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, popid_edit);
(wxGetApp().GetTopWindow())->ProcessEvent(ev);
}
}
else if (m_activeCell != NULL)
{
if (event.ControlDown())
{
if (m_activeCell->GetType() == MC_TYPE_INPUT)
m_activeCell->AddEnding();
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, deactivate_cell_ok);
(wxGetApp().GetTopWindow())->ProcessEvent(ev);
}
else
event.Skip();
}
else
event.Skip();
break;
case WXK_ESCAPE:
if (m_activeCell == NULL)
{
SetSelection(NULL);
Refresh();
}
else
{
if (m_activeCell->GetType() == MC_TYPE_INPUT)
m_activeCell->AddEnding();
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, deactivate_cell_cancel);
(wxGetApp().GetTopWindow())->ProcessEvent(ev);
}
break;
default:
event.Skip();
}
}
void MathCtrl::OnChar(wxKeyEvent& event)
{
if (m_activeCell != NULL)
{
bool hasHeightChanged = false;
m_activeCell->ProcessEvent(event);
m_switchDisplayCaret = false;
wxClientDC dc(this);
CellParser parser(dc);
wxPoint point = m_activeCell->PositionToPoint(parser);
if (m_activeCell->IsDirty())
{
int height = m_activeCell->GetHeight();
wxConfig *config = (wxConfig *)wxConfig::Get();
int fontsize = 12;
wxConfig::Get()->Read(wxT("fontSize"), &fontsize);
m_activeCell->ResetData();
m_activeCell->RecalculateWidths(parser, fontsize, false);
m_activeCell->RecalculateSize(parser, fontsize, false);
int width = m_activeCell->GetWidth() + m_activeCell->m_previous->GetWidth();
if (height != m_activeCell->GetHeight())
hasHeightChanged = true;
if (width >= GetSize().GetWidth())
hasHeightChanged = true;
}
if (hasHeightChanged)
{
Recalculate(false);
Refresh();
}
else
{
wxRect rect = m_activeCell->GetRect();
CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
rect.width = GetSize().x;
RefreshRect(rect);
}
ShowPoint(point);
}
else
{
switch (event.GetKeyCode())
{
case WXK_LEFT:
if (SelectPrompt())
return;
case WXK_UP:
if (!SelectPrevInput())
event.Skip();
break;
case WXK_DOWN:
case WXK_RIGHT:
if (!SelectNextInput())
event.Skip();
break;
default:
event.Skip();
}
}
}
/***
* Get maximum x and y in the tree.
*/
void MathCtrl::GetMaxPoint(int* width, int* height)
{
MathCell* tmp = m_tree;
int currentHeight = MC_BASE_INDENT;
int currentWidth = MC_BASE_INDENT;
*width = MC_BASE_INDENT;
*height = MC_BASE_INDENT;
bool bigSkip = false;
while (tmp != NULL)
{
if (!tmp->m_isBroken)
{
if (tmp->BreakLineHere())
{
currentHeight += tmp->GetMaxHeight();
if (bigSkip)
currentHeight += MC_LINE_SKIP;
*height = currentHeight;
currentWidth = MC_BASE_INDENT + tmp->GetWidth();
*width = MAX(currentWidth + MC_BASE_INDENT, *width);
}
else
{
currentWidth += (tmp->GetWidth() + MC_CELL_SKIP);
*width = MAX(currentWidth - MC_CELL_SKIP, *width);
}
bigSkip = tmp->m_bigSkip;
}
tmp = tmp->m_nextToDraw;
}
//*width = *width+10;
}
/***
* Break lines.
*
* m_widths must be set before calling BreakLines.
* Only the top line is broken.
*/
void MathCtrl::BreakLines(MathCell* tmp)
{
int fullWidth = GetClientSize().GetWidth() - 9;
int currentWidth = MC_BASE_INDENT;
while (tmp != NULL)
{
tmp->ResetData();
tmp->BreakLine(false);
if (!tmp->m_isBroken)
{
if (tmp->BreakLineHere() ||
(currentWidth + tmp->GetWidth() >= fullWidth))
{
currentWidth = MC_BASE_INDENT + tmp->GetWidth();
tmp->BreakLine(true);
}
else
currentWidth += (tmp->GetWidth() + MC_CELL_SKIP);
}
tmp = tmp->m_nextToDraw;
}
}
/***
* Adjust the virtual size and scrollbars.
*/
void MathCtrl::AdjustSize(bool scroll)
{
int width = MC_BASE_INDENT, height = MC_BASE_INDENT;
int clientWidth, clientHeight, virtualHeight;
GetClientSize(&clientWidth, &clientHeight);
if (m_tree != NULL)
GetMaxPoint(&width, &height);
virtualHeight = MAX(clientHeight, height) + 10;
SetVirtualSize(width + 9, virtualHeight + 9);
SetScrollRate(SCROLL_UNIT, SCROLL_UNIT);
if (scroll && height > clientHeight)
{
if (m_scrollTo > -1)
Scroll(0, m_scrollTo);
else
Scroll(0, height);
}
}
/***
* Support for selecting cells outside display
*/
void MathCtrl::OnMouseExit(wxMouseEvent& event)
{
m_mouseOutside = true;
if (m_leftDown)
{
m_mousePoint.x = event.GetX();
m_mousePoint.y = event.GetY();
m_timer.Start(200, true);
}
}
void MathCtrl::OnMouseEnter(wxMouseEvent& event)
{
m_mouseOutside = false;
}
void MathCtrl::OnTimer(wxTimerEvent& event)
{
if (event.GetId() == TIMER_ID)
{
if (!m_leftDown || !m_mouseOutside)
return ;
int dx = 0, dy = 0;
int currX, currY;
wxSize size = GetClientSize();
CalcUnscrolledPosition(0, 0, &currX, &currY);
if (m_mousePoint.x <= 0)
dx = -10;
else if (m_mousePoint.x >= size.GetWidth())
dx = 10;
if (m_mousePoint.y <= 0)
dy = -10;
else if (m_mousePoint.y >= size.GetHeight())
dy = 10;
Scroll((currX + dx) / 10, (currY + dy) / 10);
m_timer.Start(50, true);
}
else
{
if (m_activeCell != NULL)
{
if (m_switchDisplayCaret)
{
m_activeCell->SwitchCaretDisplay();
wxRect rect = m_activeCell->GetRect();
CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
RefreshRect(rect);
}
m_switchDisplayCaret = true;
m_caretTimer.Start(CARET_TIMER_TIMEOUT, true);
}
}
}
/***
* Destroy the tree
*/
void MathCtrl::DestroyTree()
{
DestroyTree(m_tree);
m_tree = NULL;
}
void MathCtrl::DestroyTree(MathCell* tmp)
{
MathCell* tmp1;
while (tmp != NULL)
{
tmp1 = tmp;
tmp = tmp->m_next;
tmp1->Destroy();
delete tmp1;
}
}
/***
* Copy tree
*/
MathCell* MathCtrl::CopyTree()
{
if (m_tree == NULL)
return (MathCell*)NULL;
MathCell* tmp1 = m_tree;
MathCell* tmp;
MathCell* copy;
tmp = tmp1->Copy(false);
copy = tmp;
if (tmp1->m_isFolded)
tmp1 = tmp1->m_nextToDraw;
else
tmp1 = tmp1->m_next;
while (tmp1 != NULL)
{
tmp->AppendCell(tmp1->Copy(false));
tmp = tmp->m_next;
if (tmp1->m_isFolded)
tmp1 = tmp1->m_nextToDraw;
else
tmp1 = tmp1->m_next;
}
return copy;
}
/***
* Copy selection as bitmap
*/
bool MathCtrl::CopyBitmap()
{
MathCell* tmp = CopySelection();
Bitmap bmp;
bmp.SetData(tmp);
return bmp.ToClipboard();
}
bool MathCtrl::CopyToFile(wxString file)
{
MathCell* tmp = CopySelection();
Bitmap bmp;
bmp.SetData(tmp);
return bmp.ToFile(file);
}
bool MathCtrl::CopyToFile(wxString file, MathCell* start, MathCell* end,
bool asData)
{
MathCell* tmp = CopySelection(start, end, asData);
Bitmap bmp;
bmp.SetData(tmp);
return bmp.ToFile(file);
}
/***
* Copy selection
*/
MathCell* MathCtrl::CopySelection()
{
return CopySelection(m_selectionStart, m_selectionEnd);
}
MathCell* MathCtrl::CopySelection(MathCell* start, MathCell* end, bool asData)
{
MathCell *tmp, *tmp1 = NULL, *tmp2 = NULL;
tmp = start;
while (tmp != NULL)
{
if (tmp1 == NULL)
{
tmp1 = tmp->Copy(false);
tmp2 = tmp1;
}
else
{
tmp2->AppendCell(tmp->Copy(false));
tmp2 = tmp2->m_next;
}
if (tmp == end)
break;
if (asData)
tmp = tmp->m_next;
else
tmp = tmp->m_nextToDraw;
}
return tmp1;
}
/***
* Export content to a HTML file.
*/
void AddLineToFile(wxTextFile& output, wxString s, bool unicode)
{
if (s == wxT("\n") || s == wxEmptyString)
output.AddLine(wxEmptyString);
else
{
wxStringTokenizer lines(s, wxT("\n"), wxTOKEN_RET_EMPTY_ALL);
wxString line;
while (lines.HasMoreTokens())
{
line = lines.GetNextToken();
if (unicode)
{
#if wxUNICODE
output.AddLine(line);
#else
wxString t(line.wc_str(wxConvLocal), wxConvUTF8);
output.AddLine(t);
#endif
}
else
output.AddLine(line);
}
}
}
bool MathCtrl::ExportToHTML(wxString file)
{
wxString imgDir;
wxString path, filename, ext;
int count = 0;
MathCell *tmp = m_tree, *start = NULL, *end = NULL;
wxFileName::SplitPath(file, &path, &filename, &ext);
imgDir = path + wxT("/") + filename + wxT("_img");
if (!wxDirExists(imgDir))
if (!wxMkdir(imgDir))
return false;
wxTextFile output(file);
if (output.Exists())
{
if (!output.Open(file))
return false;
output.Clear();
}
else if (!output.Create(file))
return false;
AddLineToFile(output, wxT("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">"));
AddLineToFile(output, wxT("<HTML>"));
AddLineToFile(output, wxT(" <HEAD>"));
AddLineToFile(output, wxT(" <TITLE>wxMaxima HTML export</TITLE>"));
AddLineToFile(output, wxT(" <META NAME=\"generator\" CONTENT=\"wxMaxima\">"));
AddLineToFile(output, wxT(" <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=utf-8\">"));
//
// Write styles
//
wxString font;
wxString colorInput(wxT("blue"));
wxString colorPrompt(wxT("red"));
wxString colorMain(wxT("black"));
wxString colorTextBg(wxT("white"));
bool italicInput = false;
bool boldInput = false;
bool italicPrompt = false;
bool boldPrompt = false;
bool italicHidden = false;
bool boldHidden = false;
bool underlinedHidden = false;
bool boldString = false;
bool italicString = false;
int fontSize = 12;
wxConfigBase* config = wxConfig::Get();
config->Read(wxT("Style/fontname"), &font);
config->Read(wxT("Style/Input/color"), &colorInput);
config->Read(wxT("Style/MainPrompt/color"), &colorPrompt);
config->Read(wxT("Style/NormalText/color"), &colorMain);
config->Read(wxT("fontSize"), &fontSize);
config->Read(wxT("Style/Input/bold"), &boldInput);
config->Read(wxT("Style/String/bold"), &boldString);
config->Read(wxT("Style/Input/italic"), &italicInput);
config->Read(wxT("Style/String/italic"), &italicString);
config->Read(wxT("Style/MainPrompt/bold"), &boldPrompt);
config->Read(wxT("Style/MainPrompt/italic"), &italicPrompt);
config->Read(wxT("Style/HiddenText/bold"), &boldHidden);
config->Read(wxT("Style/HiddenText/italic"), &italicHidden);
config->Read(wxT("Style/HiddenText/underlined"), &underlinedHidden);
config->Read(wxT("Style/TextBackground/color"), &colorTextBg);
AddLineToFile(output, wxT(" <STYLE TYPE=\"text/css\">"));
// BODY STYLE
AddLineToFile(output, wxT("body {"));
if (font.Length())
{
AddLineToFile(output, wxT(" font-family: ") +
font +
wxT(";"));
}
if (colorMain.Length())
{
wxColour color(colorMain);
AddLineToFile(output, wxT(" color: ") +
wxString::Format(wxT("rgb(%d,%d,%d)"), color.Red(), color.Green(), color.Blue()) +
wxT(";"));
}
AddLineToFile(output, wxT("}"));
// INPUT STYLE
AddLineToFile(output, wxT(".input {"));
if (colorInput.Length())
{
wxColour color(colorInput);
AddLineToFile(output, wxT(" color: ") +
wxString::Format(wxT("rgb(%d,%d,%d)"), color.Red(), color.Green(), color.Blue()) +
wxT(";"));
}
if (boldInput)
AddLineToFile(output, wxT(" font-weight: bold;"));
if (italicInput)
AddLineToFile(output, wxT(" font-style: italic;"));
AddLineToFile(output, wxT("}"));
// COMMENT STYLE
AddLineToFile(output, wxT(".comment {"));
if (colorMain.Length())
{
wxColour color(colorMain);
AddLineToFile(output, wxT(" color: ") +
wxString::Format(wxT("rgb(%d,%d,%d)"), color.Red(), color.Green(), color.Blue()) +
wxT(";"));
}
if (colorTextBg.Length())
{
wxColour color(colorTextBg);
AddLineToFile(output, wxT(" background-color: ") +
wxString::Format(wxT("rgb(%d,%d,%d)"), color.Red(), color.Green(), color.Blue()) +
wxT(";"));
}
AddLineToFile(output, wxT(" padding: 2mm;"));
AddLineToFile(output, wxT("}"));
AddLineToFile(output, wxT(".section {"));
if (colorMain.Length())
{
wxColour color(colorMain);
AddLineToFile(output, wxT(" color: ") +
wxString::Format(wxT("rgb(%d,%d,%d)"), color.Red(), color.Green(), color.Blue()) +
wxT(";"));
}
if (colorTextBg.Length())
{
wxColour color(colorTextBg);
AddLineToFile(output, wxT(" background-color: ") +
wxString::Format(wxT("rgb(%d,%d,%d)"), color.Red(), color.Green(), color.Blue()) +
wxT(";"));
}
AddLineToFile(output, wxT(" font-weight: bold;"));
AddLineToFile(output, wxT(" text-decoration: underline;"));
AddLineToFile(output, wxT(" font-size: 1.5em;"));
AddLineToFile(output, wxT(" padding: 2mm;"));
AddLineToFile(output, wxT("}"));
AddLineToFile(output, wxT(".title {"));
if (colorMain.Length())
{
wxColour color(colorMain);
AddLineToFile(output, wxT(" color: ") +
wxString::Format(wxT("rgb(%d,%d,%d)"), color.Red(), color.Green(), color.Blue()) +
wxT(";"));
}
if (colorTextBg.Length())
{
wxColour color(colorTextBg);
AddLineToFile(output, wxT(" background-color: ") +
wxString::Format(wxT("rgb(%d,%d,%d)"), color.Red(), color.Green(), color.Blue()) +
wxT(";"));
}
AddLineToFile(output, wxT(" font-weight: bold;"));
AddLineToFile(output, wxT(" font-style: italic;"));
AddLineToFile(output, wxT(" text-decoration: underline;"));
AddLineToFile(output, wxT(" font-size: 2em;"));
AddLineToFile(output, wxT(" padding: 2mm;"));
AddLineToFile(output, wxT("}"));
// PROMPT STYLE
AddLineToFile(output, wxT(".prompt {"));
if (colorPrompt.Length())
{
wxColour color(colorPrompt);
AddLineToFile(output, wxT(" color: ") +
wxString::Format(wxT("rgb(%d,%d,%d)"), color.Red(), color.Green(), color.Blue()) +
wxT(";"));
}
if (boldPrompt)
AddLineToFile(output, wxT(" font-weight: bold;"));
if (italicPrompt)
AddLineToFile(output, wxT(" font-style: italic;"));
AddLineToFile(output, wxT("}"));
// HIDDEN STYLE
AddLineToFile(output, wxT(".hidden {"));
if (colorPrompt.Length())
{
wxColour color(colorPrompt);
AddLineToFile(output, wxT(" color: ") +
wxString::Format(wxT("rgb(%d,%d,%d)"), color.Red(), color.Green(), color.Blue()) +
wxT(";"));
}
if (boldHidden)
AddLineToFile(output, wxT(" font-weight: bold;"));
if (italicHidden)
AddLineToFile(output, wxT(" font-style: italic;"));
if (underlinedHidden)
AddLineToFile(output, wxT(" text-decoration: underline;"));
AddLineToFile(output, wxT("}"));
AddLineToFile(output, wxT(" </STYLE>"));
AddLineToFile(output, wxT(" </HEAD>"));
AddLineToFile(output, wxT(" <BODY>"));
wxString version(wxT(VERSION));
AddLineToFile(output, wxEmptyString);
AddLineToFile(output, wxT("<!---------------------------------------------------------->"));
AddLineToFile(output, wxT("<!-- Created by wxMaxima version ") + version + wxT(" -->"));
AddLineToFile(output, wxT("<!---------------------------------------------------------->"));
//
// Write maxima header
//
if (tmp != NULL && tmp->GetType() != MC_TYPE_MAIN_PROMPT)
{
AddLineToFile(output, wxEmptyString);
AddLineToFile(output, wxT(" <P>"));
while (tmp != NULL && tmp->GetType() != MC_TYPE_MAIN_PROMPT)
{
AddLineToFile(output, wxT(" ") + tmp->ToString(false));
AddLineToFile(output, wxT(" <BR/>"));
tmp = tmp->m_nextToDraw;
}
AddLineToFile(output, wxT(" </P>"));
}
AddLineToFile(output, wxEmptyString);
//
// Write contents
//
int type = 0;
wxString closeTag;
while (tmp != NULL)
{
AddLineToFile(output, wxT("<!-- Input/output group -->"));
AddLineToFile(output, wxEmptyString);
AddLineToFile(output, wxT(" <P>"));
// PROMPT
if (tmp->GetValue() != wxT("/*"))
{
if (!tmp->m_isFolded)
AddLineToFile(output, wxT(" <SPAN CLASS=\"prompt\">"));
else
AddLineToFile(output, wxT(" <SPAN CLASS=\"hidden\">"));
while (tmp != NULL && tmp->GetType() == MC_TYPE_MAIN_PROMPT)
{
AddLineToFile(output, tmp->ToString(false));
tmp = tmp->m_next;
}
AddLineToFile(output, wxT(" </SPAN>"));
}
else
tmp = tmp->m_nextToDraw;
// INPUT
if (tmp != NULL)
{
type = tmp->GetType();
if (type == MC_TYPE_COMMENT)
{
AddLineToFile(output, wxT(" <DIV CLASS=\"comment\">"));
closeTag = wxT(" </DIV>");
}
else if (type == MC_TYPE_SECTION)
{
AddLineToFile(output, wxT(" <DIV CLASS=\"section\">"));
closeTag = wxT(" </DIV>");
}
else if (type == MC_TYPE_TITLE)
{
AddLineToFile(output, wxT(" <DIV CLASS=\"title\">"));
closeTag = wxT(" </DIV>");
}
else
{
AddLineToFile(output, wxT(" <SPAN CLASS=\"input\">"));
closeTag = wxT(" </SPAN>");
}
}
while (tmp != NULL && tmp->GetType() == type)
{
wxString input = tmp->ToString(false);
wxString line = wxEmptyString;
for (unsigned int i = 0; i < input.Length(); i++)
{
while (input.GetChar(i) == '\n')
{
line += wxT("<BR>\n");
i++;
while (i < input.Length() && input.GetChar(i) == ' ')
{
line += wxT(" ");
i++;
}
}
line += input.GetChar(i);
}
AddLineToFile(output, wxT(" ") + line);
AddLineToFile(output, wxT(" <BR>"));
tmp = tmp->m_nextToDraw;
}
AddLineToFile(output, closeTag);
// Check if there is no optput (commands with $)
if (tmp != NULL && tmp->GetType() == MC_TYPE_MAIN_PROMPT)
{
AddLineToFile(output, wxT(" </P>"));
AddLineToFile(output, wxEmptyString);
continue;
}
// OUTPUT
start = tmp;
if (tmp != NULL && tmp->m_isFolded)
{
end = tmp;
}
else
{
while (tmp != NULL && tmp->m_next != NULL &&
tmp->m_next->GetType() != MC_TYPE_MAIN_PROMPT)
tmp = tmp->m_next;
end = tmp;
}
if (start != NULL && end != NULL)
{
if (!CopyToFile(imgDir + wxT("/") + filename +
wxString::Format(wxT("_%d.png"), count),
start, end, true))
return false;
AddLineToFile(output, wxT(" <BR>"));
AddLineToFile(output, wxT(" <IMG ALT=\"Result\" SRC=\"") + filename + wxT("_img/") +
filename +
wxString::Format(wxT("_%d.png\">"), count));
count++;
}
AddLineToFile(output, wxT(" </P>"));
AddLineToFile(output, wxEmptyString);
if (tmp != NULL)
{
if (start->m_isFolded)
tmp = tmp->m_nextToDraw;
else
tmp = tmp->m_next;
}
}
//
// Footer
//
AddLineToFile(output, wxT(" <HR>"));
AddLineToFile(output, wxT(" <SMALL> Created with")
wxT(" <A HREF=\"http://wxmaxima.sourceforge.net/\">")
wxT("wxMaxima</A>")
wxT(".</SMALL>"));
AddLineToFile(output, wxEmptyString);
//
// Close document
//
AddLineToFile(output, wxT(" </BODY>"));
AddLineToFile(output, wxT("</HTML>"));
bool done = output.Write(wxTextFileType_None);
output.Close();
return done;
}
bool MathCtrl::ExportToMAC(wxString file)
{
wxTextFile output(file);
if (output.Exists())
{
if (!output.Open(file))
return false;
output.Clear();
}
else if (!output.Create(file))
return false;
AddLineToFile(output, wxT("/* [wxMaxima batch file version 1] [ DO NOT EDIT BY HAND! ]*/"), false);
wxString version(wxT(VERSION));
AddLineToFile(output, wxT("/* [ Created by wxMaxima version ") + version + wxT(" ] */"), false);
MathCell* tmp = m_tree;
//
// Write contents
//
while (tmp != NULL)
{
// Go to first main prompt
while (tmp != NULL && tmp->GetType() != MC_TYPE_MAIN_PROMPT)
tmp = tmp->m_next;
// Go to input
tmp = tmp->m_next;
// Write input
if (tmp != NULL && tmp->GetType() == MC_TYPE_INPUT)
{
AddLineToFile(output, wxEmptyString, false);
AddLineToFile(output, wxT("/* [wxMaxima: input start ] */"), false);
while (tmp != NULL && tmp->GetType() == MC_TYPE_INPUT)
{
wxString input = tmp->ToString(false);
AddLineToFile(output, input, false);
tmp = tmp->m_next;
}
AddLineToFile(output, wxT("/* [wxMaxima: input end ] */"), false);
}
// Write comment
if (tmp != NULL && tmp->GetType() == MC_TYPE_COMMENT)
{
AddLineToFile(output, wxEmptyString, false);
AddLineToFile(output, wxT("/* [wxMaxima: comment start ]"), false);
while (tmp != NULL && tmp->GetType() == MC_TYPE_COMMENT)
{
wxString input = tmp->ToString(false);
AddLineToFile(output, input, false);
tmp = tmp->m_next;
}
AddLineToFile(output, wxT(" [wxMaxima: comment end ] */"), false);
}
if (tmp != NULL && tmp->GetType() == MC_TYPE_SECTION)
{
AddLineToFile(output, wxEmptyString, false);
AddLineToFile(output, wxT("/* [wxMaxima: section start ]"), false);
while (tmp != NULL && tmp->GetType() == MC_TYPE_SECTION)
{
wxString input = tmp->ToString(false);
AddLineToFile(output, input, false);
tmp = tmp->m_next;
}
AddLineToFile(output, wxT(" [wxMaxima: section end ] */"), false);
}
if (tmp != NULL && tmp->GetType() == MC_TYPE_TITLE)
{
AddLineToFile(output, wxEmptyString, false);
AddLineToFile(output, wxT("/* [wxMaxima: title start ]"), false);
while (tmp != NULL && tmp->GetType() == MC_TYPE_TITLE)
{
wxString input = tmp->ToString(false);
AddLineToFile(output, input, false);
tmp = tmp->m_next;
}
AddLineToFile(output, wxT(" [wxMaxima: title end ] */"), false);
}
}
AddLineToFile(output, wxEmptyString, false);
AddLineToFile(output, wxT("/* Maxima can't load/batch files which end with a comment! */"), false);
AddLineToFile(output, wxT("\"Created with wxMaxima\"$"), false);
bool done = output.Write(wxTextFileType_None);
output.Close();
return done;
}
void MathCtrl::BreakUpCells()
{
if (m_tree != NULL)
BreakUpCells(m_tree);
}
void MathCtrl::BreakUpCells(MathCell *cell)
{
wxClientDC dc(this);
CellParser parser(dc);
int fontsize = 12;
MathCell *tmp = cell;
wxConfig::Get()->Read(wxT("fontSize"), &fontsize);
int clientWidth = GetClientSize().GetWidth() - 9;
while (tmp != NULL)
{
if (tmp->GetWidth() > clientWidth)
{
if (tmp->BreakUp())
{
tmp->RecalculateWidths(parser, fontsize, false);
tmp->RecalculateSize(parser, fontsize, false);
}
}
tmp = tmp->m_nextToDraw;
}
}
void MathCtrl::UnBreakUpCells()
{
wxClientDC dc(this);
CellParser parser(dc);
int fontsize = 12;
wxConfig::Get()->Read(wxT("fontSize"), &fontsize);
MathCell *tmp = m_tree;
while (tmp != NULL)
{
if (tmp->m_isBroken)
{
tmp->Unbreak(false);
}
tmp = tmp->m_next;
}
}
/**
* CanEdit: we can edit the input if the we have the whole input in selection!
*/
bool MathCtrl::CanEdit()
{
if (m_selectionStart == NULL || m_selectionEnd != m_selectionStart ||
m_insertPoint != NULL || m_editingEnabled == false)
return false;
if (!m_selectionStart->IsEditable())
return false;
if (m_selectionStart->m_previous == NULL ||
m_selectionStart->m_previous->GetType() != MC_TYPE_MAIN_PROMPT)
return false;
// if (m_selectionStart->m_next == NULL)
// return false;
return true;
}
/***
* Insert a new cell newCell just after insertPoint
*/
void MathCtrl::InsertAfter(MathCell* insertPoint, MathCell* newCell, bool forceLineBreak)
{
MathCell* tmp = insertPoint->m_next;
insertPoint->m_next = NULL;
insertPoint->m_nextToDraw = NULL;
m_last = insertPoint;
Freeze();
AddLine(newCell, forceLineBreak);
if (tmp != NULL)
AddLine(tmp, tmp->ForceBreakLineHere());
Thaw();
Refresh();
}
MathCell* MathCtrl::GetLastCell()
{
if (m_last == NULL)
m_last = m_tree;
if (m_last == NULL)
return NULL;
while (m_last->m_next)
m_last = m_last->m_next;
return m_last;
}
MathCell* MathCtrl::GetLastPrompt()
{
MathCell *tmp = m_tree;
MathCell *last = NULL;
if (tmp == NULL)
return NULL;
while (tmp != NULL)
{
if (tmp->GetType() == MC_TYPE_MAIN_PROMPT)
last = tmp;
tmp = tmp->m_nextToDraw;
}
return last;
}
void MathCtrl::OnDoubleClick(wxMouseEvent &event)
{
if (CanEdit())
{
if (event.ControlDown())
{
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, popid_reeval);
(wxGetApp().GetTopWindow())->ProcessEvent(ev);
}
else
{
wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, popid_edit);
(wxGetApp().GetTopWindow())->ProcessEvent(ev);
}
}
}
bool MathCtrl::CanAddInput()
{
if (m_tree == NULL)
return false;
if (m_selectionStart == NULL)
return true;
else if (m_selectionStart == m_selectionEnd &&
m_selectionStart->GetType() == MC_TYPE_MAIN_PROMPT &&
!m_selectionStart->m_isFolded)
return true;
else if (CanEdit())
return true;
return false;
}
bool MathCtrl::CanAddComment()
{
return CanAddInput();
}
void MathCtrl::UnfoldAll()
{
MathCell* tmp = m_tree;
while (tmp != NULL)
{
if (tmp->m_isFolded)
{
if (tmp->m_nextToDraw != NULL)
tmp->m_nextToDraw->m_previousToDraw = tmp->m_nextToDraw->m_previous;
tmp->m_nextToDraw = tmp->m_next;
tmp->m_isFolded = false;
tmp->Fold(false);
}
tmp = tmp->m_next;
}
Recalculate(false);
Refresh();
}
bool MathCtrl::SelectPrevInput()
{
if (m_selectionStart == NULL)
return false;
MathCell *tmp = m_selectionStart;
// Move in front of current input
if (tmp != NULL &&
tmp->IsEditable())
{
while (tmp != NULL &&
tmp->IsEditable())
tmp = tmp->m_previousToDraw;
}
if (tmp == NULL)
return false;
// Move to prev input
while (tmp != NULL &&
!tmp->IsEditable())
tmp = tmp->m_previousToDraw;
if (tmp == NULL)
return false;
// Selection ends here
m_selectionEnd = tmp;
while (tmp != NULL &&
tmp->IsEditable())
{
m_selectionStart = tmp;
tmp = tmp->m_previousToDraw;
}
ScrollToSelectionStart();
return true;
}
bool MathCtrl::SelectNextInput()
{
if (m_selectionStart == NULL)
return false;
MathCell *tmp = m_selectionEnd;
// Move to the back of current input
if (tmp != NULL &&
tmp->IsEditable())
{
while (tmp != NULL &&
tmp->IsEditable())
tmp = tmp->m_nextToDraw;
}
if (tmp == NULL)
return false;
// Move to next input
while (tmp != NULL &&
!tmp->IsEditable())
tmp = tmp->m_nextToDraw;
if (tmp == NULL)
return false;
// Selection starts here
m_selectionStart = tmp;
while (tmp != NULL &&
tmp->IsEditable())
{
m_selectionEnd = tmp;
tmp = tmp->m_nextToDraw;
}
ScrollToSelectionStart();
return true;
}
bool MathCtrl::SelectLastInput()
{
MathCell *tmp = m_tree, *tmp1 = NULL, *tmp2 = NULL;
if (tmp == NULL)
return false;
if (m_activeCell != NULL)
return false;
while (tmp != NULL)
{
while (tmp != NULL && tmp->GetType() != MC_TYPE_INPUT)
tmp = tmp->m_nextToDraw;
if (tmp != NULL)
tmp1 = tmp;
while (tmp != NULL && tmp->GetType() == MC_TYPE_INPUT)
{
tmp2 = tmp;
tmp = tmp->m_nextToDraw;
}
}
if (tmp1 != NULL && tmp2 != NULL)
{
m_selectionStart = tmp1;
m_selectionEnd = tmp2;
ScrollToSelectionStart();
return true;
}
return false;
}
bool MathCtrl::SelectPrompt()
{
if (m_selectionStart == NULL)
{
m_selectionStart = m_selectionEnd = GetLastPrompt();
if (m_selectionStart != NULL)
return true;
}
else if (m_selectionStart == m_selectionEnd &&
m_selectionStart->GetType() == MC_TYPE_MAIN_PROMPT)
return true;
else if (m_selectionStart->m_previousToDraw != NULL &&
m_selectionStart->m_previousToDraw->GetType() == MC_TYPE_MAIN_PROMPT)
{
m_selectionStart = m_selectionStart->m_previousToDraw;
m_selectionEnd = m_selectionStart;
ScrollToSelectionStart();
return true;
}
return false;
}
void MathCtrl::ScrollToSelectionStart()
{
if (m_selectionStart == NULL)
return ;
int cellY = m_selectionStart->GetCurrentY();
if (cellY == -1)
return ;
int cellDrop = m_selectionStart->GetDrop();
int cellCenter = m_selectionStart->GetCenter();
int view_x, view_y;
int height, width;
GetViewStart(&view_x, &view_y);
GetSize(&width, &height);
view_y *= SCROLL_UNIT;
if ((cellY - cellCenter - SCROLL_UNIT < view_y) ||
(cellY + cellDrop + SCROLL_UNIT > view_y + height))
{
Scroll(-1, MAX(cellY/SCROLL_UNIT - 2, 0));
}
Refresh();
}
void MathCtrl::SetActiveCell(MathCell *cell)
{
if (m_activeCell != NULL)
{
m_activeCell->ActivateCell();
}
m_activeCell = cell;
if (m_activeCell != NULL)
{
bool match = false;
if (m_activeCell->GetType() == MC_TYPE_INPUT)
wxConfig::Get()->Read(wxT("matchParens"), &match);
m_activeCell->ActivateCell();
m_activeCell->SetMatchParens(match);
m_switchDisplayCaret = false;
m_caretTimer.Start(CARET_TIMER_TIMEOUT, true);
}
}
void MathCtrl::ShowPoint(wxPoint point)
{
if (point.x == -1 || point.y == -1)
return ;
int view_x, view_y;
int height, width;
bool sc = false;
int scrollToX = -1, scrollToY = -1;
GetViewStart(&view_x, &view_y);
GetSize(&width, &height);
view_x *= SCROLL_UNIT;
view_y *= SCROLL_UNIT;
if ((point.y < view_y) ||
(point.y > view_y + height - wxSystemSettings::GetMetric(wxSYS_HTHUMB_X) - 20))
{
sc = true;
scrollToY = point.y - height / 2;
}
else
scrollToY = view_y;
if ((point.x < view_x) ||
(point.x > view_x + width - wxSystemSettings::GetMetric(wxSYS_HTHUMB_X) - 20))
{
sc = true;
scrollToX = point.x - width / 2;
}
else
scrollToX = view_x;
if (sc)
Scroll(scrollToX / SCROLL_UNIT, scrollToY / SCROLL_UNIT);
}
bool MathCtrl::CutToClipboard()
{
if (m_activeCell == NULL)
return false;
m_activeCell->CutToClipboard();
Recalculate(false);
Refresh();
return true;
}
void MathCtrl::PasteFromClipboard()
{
if (m_activeCell == NULL)
return ;
m_activeCell->PasteFromClipboard();
Recalculate(false);
Refresh();
}
void MathCtrl::SelectAll()
{
if (m_activeCell == NULL)
return;
m_activeCell->SelectAll();
Refresh();
}
void MathCtrl::OnSetFocus(wxFocusEvent& event)
{
if (m_activeCell != NULL)
m_activeCell->SetFocus(true);
}
void MathCtrl::OnKillFocus(wxFocusEvent& event)
{
if (m_activeCell != NULL)
m_activeCell->SetFocus(false);
}
void MathCtrl::CheckUnixCopy()
{
bool copy = false;
wxConfig::Get()->Read(wxT("unixCopy"), ©);
if (copy)
{
#if defined __WXGTK__
wxTheClipboard->UsePrimarySelection(true);
#endif
if (CanCopy() && wxTheClipboard->Open())
{
wxTheClipboard->SetData(new wxTextDataObject(GetString()));
wxTheClipboard->Close();
}
#if defined __WXGTK__
wxTheClipboard->UsePrimarySelection(false);
#endif
}
}
BEGIN_EVENT_TABLE(MathCtrl, wxScrolledWindow)
EVT_SIZE(MathCtrl::OnSize)
EVT_PAINT(MathCtrl::OnPaint)
EVT_LEFT_UP(MathCtrl::OnMouseLeftUp)
EVT_RIGHT_UP(MathCtrl::OnMouseRightUp)
EVT_LEFT_DOWN(MathCtrl::OnMouseLeftDown)
EVT_LEFT_DCLICK(MathCtrl::OnDoubleClick)
EVT_MOTION(MathCtrl::OnMouseMotion)
EVT_ENTER_WINDOW(MathCtrl::OnMouseEnter)
EVT_LEAVE_WINDOW(MathCtrl::OnMouseExit)
EVT_TIMER(TIMER_ID, MathCtrl::OnTimer)
EVT_TIMER(CARET_TIMER_ID, MathCtrl::OnTimer)
EVT_KEY_DOWN(MathCtrl::OnKeyDown)
EVT_CHAR(MathCtrl::OnChar)
EVT_ERASE_BACKGROUND(MathCtrl::OnEraseBackground)
EVT_KILL_FOCUS(MathCtrl::OnKillFocus)
EVT_SET_FOCUS(MathCtrl::OnSetFocus)
END_EVENT_TABLE()
syntax highlighted by Code2HTML, v. 0.9.1