+
+
+
+bool
+wxLayoutList::MoveCursorTo(wxPoint const &p)
+{
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ wxLayoutLine *line = m_FirstLine;
+ while(line && line->GetLineNumber() != p.y)
+ line = line->GetNextLine();
+ if(line && line->GetLineNumber() == p.y) // found it
+ {
+ m_CursorPos.y = p.y;
+ m_CursorLine = line;
+ CoordType len = line->GetLength();
+ if(len >= p.x)
+ {
+ m_CursorPos.x = p.x;
+ return true;
+ }
+ else
+ {
+ m_CursorPos.x = len;
+ return false;
+ }
+ }
+ return false;
+}
+
+bool
+wxLayoutList::MoveCursorVertically(int n)
+{
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ bool rc;
+ if(n < 0) // move up
+ {
+ if(m_CursorLine == m_FirstLine) return false;
+ while(n < 0 && m_CursorLine)
+ {
+ m_CursorLine = m_CursorLine->GetPreviousLine();
+ m_CursorPos.y--;
+ n++;
+ }
+ if(! m_CursorLine)
+ {
+ m_CursorLine = m_FirstLine;
+ m_CursorPos.y = 0;
+ rc = false;
+ }
+ else
+ {
+ if(m_CursorPos.x > m_CursorLine->GetLength())
+ m_CursorPos.x = m_CursorLine->GetLength();
+ rc = true;
+ }
+ }
+ else // move down
+ {
+ wxLayoutLine *last = m_CursorLine;
+ if(! m_CursorLine->GetNextLine()) return false;
+ while(n > 0 && m_CursorLine)
+ {
+ n--;
+ m_CursorPos.y ++;
+ m_CursorLine = m_CursorLine->GetNextLine();
+ }
+ if(! m_CursorLine)
+ {
+ m_CursorLine = last;
+ m_CursorPos.y ++;
+ rc = false;
+ }
+ else
+ {
+ if(m_CursorPos.x > m_CursorLine->GetLength())
+ m_CursorPos.x = m_CursorLine->GetLength();
+ rc = true;
+ }
+ }
+ return rc;
+}
+
+bool
+wxLayoutList::MoveCursorHorizontally(int n)
+{
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ int move;
+ while(n < 0)
+ {
+ if(m_CursorPos.x == 0) // at begin of line
+ {
+ if(! MoveCursorVertically(-1))
+ break;
+ MoveCursorToEndOfLine();
+ n++;
+ continue;
+ }
+ move = -n;
+ if(move > m_CursorPos.x) move = m_CursorPos.x;
+ m_CursorPos.x -= move; n += move;
+ }
+
+ while(n > 0)
+ {
+ int len = m_CursorLine->GetLength();
+ if(m_CursorPos.x == len) // at end of line
+ {
+ if(! MoveCursorVertically(1))
+ break;
+ MoveCursorToBeginOfLine();
+ n--;
+ continue;
+ }
+ move = n;
+ if( move >= len-m_CursorPos.x) move = len-m_CursorPos.x;
+ m_CursorPos.x += move;
+ n -= move;
+ }
+ return n == 0;
+}
+
+bool
+wxLayoutList::Insert(wxString const &text)
+{
+ wxASSERT(m_CursorLine);
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ m_CursorLine->Insert(m_CursorPos.x, text);
+ m_CursorPos.x += text.Length();
+ return true;
+}
+
+bool
+wxLayoutList::Insert(wxLayoutObject *obj)
+{
+ wxASSERT(m_CursorLine);
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ m_CursorLine->Insert(m_CursorPos.x, obj);
+ m_CursorPos.x += obj->GetLength();
+ return true;
+}
+
+bool
+wxLayoutList::LineBreak(void)
+{
+ wxASSERT(m_CursorLine);
+ bool setFirst = (m_CursorLine == m_FirstLine && m_CursorPos.x == 0);
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ m_CursorLine = m_CursorLine->Break(m_CursorPos.x, this);
+ if(setFirst) // we were at beginning of first line
+ m_FirstLine = m_CursorLine->GetPreviousLine();
+ m_CursorPos.y++;
+ m_CursorPos.x = 0;
+ return true;
+}
+
+bool
+wxLayoutList::WrapLine(CoordType column)
+{
+ if(m_CursorPos.x <= column || column < 1)
+ return false; // do nothing yet
+ else
+ {
+ CoordType xpos = m_CursorLine->GetWrapPosition(column);
+ if(xpos == -1)
+ return false; // cannot break line
+ //else:
+ CoordType newpos = m_CursorPos.x - xpos - 1;
+ m_CursorPos.x = xpos;
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ LineBreak();
+ Delete(1); // delete the space
+ m_CursorPos.x = newpos;
+ return true;
+ }
+}
+
+bool
+wxLayoutList::Delete(CoordType npos)
+{
+ wxASSERT(m_CursorLine);
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ CoordType left;
+ do
+ {
+ left = m_CursorLine->Delete(m_CursorPos.x, npos);
+ if(left == 0)
+ return true;
+ // More to delete, continue on next line.
+ // First, check if line is empty:
+ if(m_CursorLine->GetLength() == 0)
+ { // in this case, updating could probably be optimised
+#ifdef WXLO_DEBUG
+ wxASSERT(DeleteLines(1) == 0);
+#else
+ DeleteLines(1);
+#endif
+
+ left--;
+ }
+ else
+ {
+ // Need to join next line
+ if(! m_CursorLine->GetNextLine())
+ break; // cannot
+ else
+ {
+ m_CursorLine->MergeNextLine(this);
+ left--;
+ }
+ }
+ }
+ while(left);
+ return left == 0;
+}
+
+int
+wxLayoutList::DeleteLines(int n)
+{
+ wxASSERT(m_CursorLine);
+ wxLayoutLine *line;
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+ while(n > 0)
+ {
+ if(!m_CursorLine->GetNextLine())
+ { // we cannot delete this line, but we can clear it
+ MoveCursorToBeginOfLine();
+ DeleteToEndOfLine();
+ return n-1;
+ }
+ //else:
+ line = m_CursorLine;
+ m_CursorLine = m_CursorLine->DeleteLine(true, this);
+ n--;
+ if(line == m_FirstLine) m_FirstLine = m_CursorLine;
+ wxASSERT(m_FirstLine);
+ wxASSERT(m_CursorLine);
+ }
+ m_CursorLine->RecalculatePositions(2, this);
+ return n;
+}
+
+void
+wxLayoutList::Recalculate(wxDC &dc, CoordType bottom)
+{
+ wxLayoutLine *line = m_FirstLine;
+
+ // first, make sure everything is calculated - this might not be
+ // needed, optimise it later
+ m_DefaultSetting->Layout(dc);
+ while(line)
+ {
+ line->RecalculatePosition(this); // so we don't need to do it all the time
+ // little condition to speed up redrawing:
+ if(bottom != -1 && line->GetPosition().y > bottom) break;
+ line = line->GetNextLine();
+ }
+}
+
+void
+wxLayoutList::UpdateCursorScreenPos(wxDC &dc)
+{
+ wxASSERT(m_CursorLine);
+ m_CursorLine->Layout(dc, this, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x);
+}
+
+wxPoint
+wxLayoutList::GetCursorScreenPos(wxDC &dc)
+{
+ UpdateCursorScreenPos(dc);
+ return m_CursorScreenPos;
+}
+
+void
+wxLayoutList::Layout(wxDC &dc, CoordType bottom)
+{
+ wxLayoutLine *line = m_FirstLine;
+
+ // first, make sure everything is calculated - this might not be
+ // needed, optimise it later
+ m_DefaultSetting->Layout(dc);
+ while(line)
+ {
+ if(line == m_CursorLine)
+ line->Layout(dc, this, (wxPoint *)&m_CursorScreenPos, (wxPoint *)&m_CursorSize, m_CursorPos.x);
+ else
+ line->Layout(dc, this);
+ // little condition to speed up redrawing:
+ if(bottom != -1 && line->GetPosition().y > bottom) break;
+ line = line->GetNextLine();
+ }
+
+///FIXME: disabled for now
+#if 0
+ // can only be 0 if we are on the first line and have no next line
+ wxASSERT(m_CursorSize.x != 0 || (m_CursorLine &&
+ m_CursorLine->GetNextLine() == NULL &&
+ m_CursorLine == m_FirstLine));
+#endif
+ SetUpdateRect(m_CursorScreenPos);
+ SetUpdateRect(m_CursorScreenPos+m_CursorSize);
+}
+
+void
+wxLayoutList::Draw(wxDC &dc, wxPoint const &offset,
+ CoordType top, CoordType bottom)
+{
+ wxLayoutLine *line = m_FirstLine;
+
+ Layout(dc, bottom);
+ m_DefaultSetting->Draw(dc, wxPoint(0,0));
+ wxBrush brush(m_ColourBG, wxSOLID);
+ dc.SetBrush(brush);
+
+ while(line)
+ {
+ // only draw if between top and bottom:
+ if((top == -1 || line->GetPosition().y >= top))
+ line->Draw(dc, this, offset);
+ // little condition to speed up redrawing:
+ if(bottom != -1 && line->GetPosition().y + line->GetHeight() > bottom) break;
+ line = line->GetNextLine();
+ }
+ // can only be 0 if we are on the first line and have no next line
+ wxASSERT(m_CursorSize.x != 0 || (m_CursorLine &&
+ m_CursorLine->GetNextLine() == NULL &&
+ m_CursorLine == m_FirstLine));
+ InvalidateUpdateRect();
+}
+
+wxLayoutObject *
+wxLayoutList::FindObjectScreen(wxDC &dc, wxPoint const pos, wxPoint *cursorPos)
+{
+ // First, find the right line:
+ wxLayoutLine *line = m_FirstLine;
+ wxPoint p;
+
+ // we need to run a layout here to get font sizes right :-(
+ m_DefaultSetting->Layout(dc);
+ while(line)
+ {
+ p = line->GetPosition();
+ if(p.y <= pos.y && p.y+line->GetHeight() >= pos.y)
+ break;
+ line->Layout(dc, this);
+ line = line->GetNextLine();
+ }
+ if(line == NULL) return NULL; // not found
+ if(cursorPos) cursorPos->y = line->GetLineNumber();
+ // Now, find the object in the line:
+ wxLOiterator i = line->FindObjectScreen(dc, pos.x, & cursorPos->x);
+ return (i == NULLIT) ? NULL : *i;
+
+}
+
+wxPoint
+wxLayoutList::GetSize(void) const
+{
+ wxLayoutLine
+ *line = m_FirstLine,
+ *last = line;
+ if(! line)
+ return wxPoint(0,0);
+
+ wxPoint maxPoint(0,0);
+
+ // find last line:
+ while(line)
+ {
+ if(line->GetWidth() > maxPoint.x)
+ maxPoint.x = line->GetWidth();
+ last = line;
+ line = line->GetNextLine();
+ }
+
+ maxPoint.y = last->GetPosition().y + last->GetHeight();
+ return maxPoint;
+}
+
+void
+wxLayoutList::DrawCursor(wxDC &dc, bool active, wxPoint const &translate)
+{
+ wxPoint coords;
+ coords = m_CursorScreenPos;
+ coords.x += translate.x;
+ coords.y += translate.y;
+
+#ifdef WXLAYOUT_DEBUG
+ WXLO_DEBUG(("Drawing cursor (%ld,%ld) at %ld,%ld, size %ld,%ld, line: %ld, len %ld",
+ (long)m_CursorPos.x, (long)m_CursorPos.y,
+ (long)coords.x, (long)coords.y,
+ (long)m_CursorSize.x, (long)m_CursorSize.y,
+ (long)m_CursorLine->GetLineNumber(),
+ (long)m_CursorLine->GetLength()));
+#endif
+
+ dc.SetBrush(*wxBLACK_BRUSH);
+ dc.SetLogicalFunction(wxXOR);
+ dc.SetPen(wxPen(*wxBLACK,1,wxSOLID));
+ if(active)
+ dc.DrawRectangle(coords.x, coords.y, m_CursorSize.x,
+ m_CursorSize.y);
+ else
+ dc.DrawLine(coords.x, coords.y+m_CursorSize.y-1,
+ coords.x+m_CursorSize.x, coords.y+m_CursorSize.y-1);
+ dc.SetLogicalFunction(wxCOPY);
+ //dc.SetBrush(wxNullBrush);
+}
+
+/** Called by the objects to update the update rectangle.
+ @param p a point to include in it
+*/
+void
+wxLayoutList::SetUpdateRect(const wxPoint &p)
+{
+ if(m_UpdateRectValid)
+ GrowRect(m_UpdateRect, p);
+ else
+ {
+ m_UpdateRect.x = p.x;
+ m_UpdateRect.y = p.y;
+ m_UpdateRect.width = 4; // large enough to avoid surprises from
+ m_UpdateRect.height = 4;// wxGTK :-)
+ m_UpdateRectValid = true;
+ }
+}
+
+void
+wxLayoutList::StartSelection(void)
+{
+ wxLogDebug("Starting selection at %ld/%ld", m_CursorPos.x, m_CursorPos.y);
+ m_Selection.m_CursorA = m_CursorPos;
+}
+
+void
+wxLayoutList::EndSelection(void)
+{
+ wxLogDebug("Ending selection at %ld/%ld", m_CursorPos.x, m_CursorPos.y);
+ m_Selection.m_CursorB = m_CursorPos;
+}
+
+bool
+wxLayoutList::IsSelected(const wxPoint &cursor)
+{
+ return m_Selection.m_CursorA <= cursor
+ && cursor <= m_Selection.m_CursorB;
+}
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+ wxLayoutPrintout
+
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+wxLayoutPrintout::wxLayoutPrintout(wxLayoutList *llist,
+ wxString const & title)
+:wxPrintout(title)
+{
+ m_llist = llist;
+ m_title = title;
+}
+
+float
+wxLayoutPrintout::ScaleDC(wxDC *dc)
+{
+ // The following bit is taken from the printing sample, let's see
+ // whether it works for us.
+
+ /* You might use THIS code to set the printer DC to ROUGHLY reflect
+ * the screen text size. This page also draws lines of actual length 5cm
+ * on the page.
+ */
+ // Get the logical pixels per inch of screen and printer
+ int ppiScreenX, ppiScreenY;
+ GetPPIScreen(&ppiScreenX, &ppiScreenY);
+ int ppiPrinterX, ppiPrinterY;
+ GetPPIPrinter(&ppiPrinterX, &ppiPrinterY);
+
+ if(ppiScreenX == 0) // not yet set, need to guess
+ {
+ ppiScreenX = 100;
+ ppiScreenY = 100;
+ }
+ if(ppiPrinterX == 0) // not yet set, need to guess
+ {
+ ppiPrinterX = 72;
+ ppiPrinterY = 72;
+ }
+
+ // This scales the DC so that the printout roughly represents the
+ // the screen scaling. The text point size _should_ be the right size
+ // but in fact is too small for some reason. This is a detail that will
+ // need to be addressed at some point but can be fudged for the
+ // moment.
+ float scale = (float)((float)ppiPrinterX/(float)ppiScreenX);
+
+ // Now we have to check in case our real page size is reduced
+ // (e.g. because we're drawing to a print preview memory DC)
+ int pageWidth, pageHeight;
+ int w, h;
+ dc->GetSize(&w, &h);
+ GetPageSizePixels(&pageWidth, &pageHeight);
+ if(pageWidth != 0) // doesn't work always
+ {
+ // If printer pageWidth == current DC width, then this doesn't
+ // change. But w might be the preview bitmap width, so scale down.
+ scale = scale * (float)(w/(float)pageWidth);
+ }
+ dc->SetUserScale(scale, scale);
+ return scale;
+}
+
+bool wxLayoutPrintout::OnPrintPage(int page)
+{
+ wxDC *dc = GetDC();
+
+ ScaleDC(dc);
+
+ if (dc)
+ {
+ int top, bottom;
+ top = (page - 1)*m_PrintoutHeight;
+ bottom = top + m_PrintoutHeight;
+ // SetDeviceOrigin() doesn't work here, so we need to manually
+ // translate all coordinates.
+ wxPoint translate(m_Offset.x,m_Offset.y-top);
+ m_llist->Draw(*dc, translate, top, bottom);
+ return true;
+ }
+ else
+ return false;
+}
+
+void wxLayoutPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo)
+{
+ /* We allocate a temporary wxDC for printing, so that we can
+ determine the correct paper size and scaling. We don't actually
+ print anything on it. */
+#ifdef __WXMSW__
+ wxPrinterDC psdc("","",WXLLIST_TEMPFILE,false);
+#else
+ wxPostScriptDC psdc(WXLLIST_TEMPFILE,false);
+#endif
+
+ float scale = ScaleDC(&psdc);
+
+ psdc.GetSize(&m_PageWidth, &m_PageHeight);
+ // This sets a left/top origin of 15% and 20%:
+ m_Offset = wxPoint((15*m_PageWidth)/100, m_PageHeight/20);
+
+ // This is the length of the printable area.
+ m_PrintoutHeight = m_PageHeight - (int) (m_PageHeight * 0.15);
+ m_PrintoutHeight = (int)( m_PrintoutHeight / scale); // we want to use the real paper height
+
+
+ m_NumOfPages = 1 +
+ (int)( m_llist->GetSize().y / (float)(m_PrintoutHeight));
+
+ *minPage = 1;
+ *maxPage = m_NumOfPages;
+
+ *selPageFrom = 1;
+ *selPageTo = m_NumOfPages;
+ wxRemoveFile(WXLLIST_TEMPFILE);
+}
+
+bool wxLayoutPrintout::HasPage(int pageNum)
+{
+ return pageNum <= m_NumOfPages;
+}
+
+/*
+ Stupid wxWindows doesn't draw proper ellipses, so we comment this
+ out. It's a waste of paper anyway.
+*/
+#if 0
+void
+wxLayoutPrintout::DrawHeader(wxDC &dc,
+ wxPoint topleft, wxPoint bottomright,
+ int pageno)
+{
+ // make backups of all essential parameters
+ const wxBrush& brush = dc.GetBrush();
+ const wxPen& pen = dc.GetPen();
+ const wxFont& font = dc.GetFont();
+
+ dc.SetBrush(*wxWHITE_BRUSH);
+ dc.SetPen(wxPen(*wxBLACK,0,wxSOLID));
+ dc.DrawRoundedRectangle(topleft.x,
+ topleft.y,bottomright.x-topleft.x,
+ bottomright.y-topleft.y);
+ dc.SetBrush(*wxBLACK_BRUSH);
+ wxFont myfont = wxFont((WXLO_DEFAULTFONTSIZE*12)/10,
+ wxSWISS,wxNORMAL,wxBOLD,false,"Helvetica");
+ dc.SetFont(myfont);
+
+ wxString page;
+ page = "9999/9999 "; // many pages...
+ long w,h;
+ dc.GetTextExtent(page,&w,&h);
+ page.Printf("%d/%d", pageno, (int) m_NumOfPages);
+ dc.DrawText(page,bottomright.x-w,topleft.y+h/2);
+ dc.GetTextExtent("XXXX", &w,&h);
+ dc.DrawText(m_title, topleft.x+w,topleft.y+h/2);
+
+ // restore settings
+ dc.SetPen(pen);
+ dc.SetBrush(brush);
+ dc.SetFont(font);
+}
+#endif
+
+