]> git.saurik.com Git - wxWidgets.git/blobdiff - src/stc/scintilla/src/ContractionState.cxx
Update setup fort OpenVMS
[wxWidgets.git] / src / stc / scintilla / src / ContractionState.cxx
index 45694890031a1bb23b9506de9163954733d8cb5a..08de5cf1f7aa9ce89f3417d65b6bbbf921d7960c 100644 (file)
 // Scintilla source code edit control
-// ContractionState.cxx - manages visibility of lines for folding
-// Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
+/** @file ContractionState.cxx
+ ** Manages visibility of lines for folding and wrapping.
+ **/
+// Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org>
 // The License.txt file describes the conditions under which this software may be distributed.
 
+#include <string.h>
+
 #include "Platform.h"
 
+#include "SplitVector.h"
+#include "Partitioning.h"
+#include "RunStyles.h"
 #include "ContractionState.h"
 
-OneLine::OneLine() {
-       displayLine = 0;
-       docLine = 0;
-       visible = true;
-       expanded = true;
-}
+#ifdef SCI_NAMESPACE
+using namespace Scintilla;
+#endif
 
-ContractionState::ContractionState() {
-       lines = 0;
-       size = 0;
-       linesInDoc = 1;
-       linesInDisplay = 1;
-       valid = false;
+ContractionState::ContractionState() : visible(0), expanded(0), heights(0), displayLines(0), linesInDocument(1) {
+       //InsertLine(0);
 }
 
 ContractionState::~ContractionState() {
        Clear();
 }
 
-void ContractionState::MakeValid() const {
-       if (!valid) {
-               // Could be cleverer by keeping the index of the last still valid entry 
-               // rather than invalidating all.
-               int lineDisplay = 0;
-               for (int line=0; line<linesInDoc; line++) {
-                       lines[line].displayLine = lineDisplay;
-                       if (lines[line].visible) {
-                               lines[lineDisplay].docLine = line;
-                               lineDisplay++;
-                       }
-               }
-               valid = true;
+void ContractionState::EnsureData() {
+       if (OneToOne()) {
+               visible = new RunStyles();
+               expanded = new RunStyles();
+               heights = new RunStyles();
+               displayLines = new Partitioning(4);
+               InsertLines(0, linesInDocument);
        }
 }
 
 void ContractionState::Clear() {
-       delete []lines;
-       lines = 0;
-       size = 0;
-       linesInDoc = 1;
-       linesInDisplay = 1;
+       delete visible;
+       visible = 0;
+       delete expanded;
+       expanded = 0;
+       delete heights;
+       heights = 0;
+       delete displayLines;
+       displayLines = 0;
+       linesInDocument = 1;
 }
 
 int ContractionState::LinesInDoc() const {
-       return linesInDoc;
+       if (OneToOne()) {
+               return linesInDocument;
+       } else {
+               return displayLines->Partitions() - 1;
+       }
 }
 
 int ContractionState::LinesDisplayed() const {
-       return linesInDisplay;
+       if (OneToOne()) {
+               return linesInDocument;
+       } else {
+               return displayLines->PositionFromPartition(LinesInDoc());
+       }
 }
 
 int ContractionState::DisplayFromDoc(int lineDoc) const {
-       if (size == 0) {
+       if (OneToOne()) {
                return lineDoc;
+       } else {
+               if (lineDoc > displayLines->Partitions())
+                       lineDoc = displayLines->Partitions();
+               return displayLines->PositionFromPartition(lineDoc);
        }
-       MakeValid();
-       if ((lineDoc >= 0) && (lineDoc < linesInDoc)) {
-               return lines[lineDoc].displayLine;
-       }
-       return -1;
 }
 
 int ContractionState::DocFromDisplay(int lineDisplay) const {
-       if (lineDisplay <= 0)
-               return 0;
-       if (lineDisplay >= linesInDisplay)
-               return linesInDoc-1;
-       if (size == 0)
+       if (OneToOne()) {
                return lineDisplay;
-       MakeValid();
-       return lines[lineDisplay].docLine;
-}
-
-void ContractionState::Grow(int sizeNew) {
-       OneLine *linesNew = new OneLine[sizeNew];
-       if (linesNew) {
-               int i = 0;
-               for (; i < size; i++) {
-                       linesNew[i] = lines[i];
+       } else {
+               if (lineDisplay <= 0) {
+                       return 0;
                }
-               for (; i < sizeNew; i++) {
-                       linesNew[i].displayLine = i;
+               if (lineDisplay > LinesDisplayed()) {
+                       return displayLines->PartitionFromPosition(LinesDisplayed());
                }
-               delete []lines;
-               lines = linesNew;
-               size = sizeNew;
-               valid = false;
+               int lineDoc = displayLines->PartitionFromPosition(lineDisplay);
+               PLATFORM_ASSERT(GetVisible(lineDoc));
+               return lineDoc;
+       }
+}
+
+void ContractionState::InsertLine(int lineDoc) {
+       if (OneToOne()) {
+               linesInDocument++;
        } else {
-               Platform::DebugPrintf("No memory available\n");
-               // TODO: Blow up
+               visible->InsertSpace(lineDoc, 1);
+               visible->SetValueAt(lineDoc, 1);
+               expanded->InsertSpace(lineDoc, 1);
+               expanded->SetValueAt(lineDoc, 1);
+               heights->InsertSpace(lineDoc, 1);
+               heights->SetValueAt(lineDoc, 1);
+               int lineDisplay = DisplayFromDoc(lineDoc);
+               displayLines->InsertPartition(lineDoc, lineDisplay);
+               displayLines->InsertText(lineDoc, 1);
        }
 }
 
 void ContractionState::InsertLines(int lineDoc, int lineCount) {
-       if (size == 0) {
-               linesInDoc += lineCount;
-               linesInDisplay += lineCount;
-               return;
-       }
-       //Platform::DebugPrintf("InsertLine[%d] = %d\n", lineDoc);
-       if ((linesInDoc + lineCount + 2) >= size) {
-               Grow(linesInDoc + lineCount + growSize);
-       }
-       linesInDoc += lineCount;
-       linesInDisplay += lineCount;
-       for (int i = linesInDoc; i >= lineDoc + lineCount; i--) {
-               lines[i].visible = lines[i - lineCount].visible;
-               lines[i].expanded = lines[i - lineCount].expanded;
+       for (int l = 0; l < lineCount; l++) {
+               InsertLine(lineDoc + l);
        }
-       for (int d=0;d<lineCount;d++) {
-               lines[lineDoc+d].visible = true;        // Should inherit visibility from context ?
-               lines[lineDoc+d].expanded = true;
+       Check();
+}
+
+void ContractionState::DeleteLine(int lineDoc) {
+       if (OneToOne()) {
+               linesInDocument--;
+       } else {
+               if (GetVisible(lineDoc)) {
+                       displayLines->InsertText(lineDoc, -heights->ValueAt(lineDoc));
+               }
+               displayLines->RemovePartition(lineDoc);
+               visible->DeleteRange(lineDoc, 1);
+               expanded->DeleteRange(lineDoc, 1);
+               heights->DeleteRange(lineDoc, 1);
        }
-       valid = false;
 }
 
 void ContractionState::DeleteLines(int lineDoc, int lineCount) {
-       if (size == 0) {
-               linesInDoc -= lineCount;
-               linesInDisplay -= lineCount;
-               return;
-       }
-       int deltaDisplayed = 0;
-       for (int d=0;d<lineCount;d++) {
-               if (lines[lineDoc+d].visible)
-                       deltaDisplayed--;
-       }
-       for (int i = lineDoc; i < linesInDoc-lineCount; i++) {
-               if (i != 0) // Line zero is always visible
-                       lines[i].visible = lines[i + lineCount].visible;
-               lines[i].expanded = lines[i + lineCount].expanded;
+       for (int l = 0; l < lineCount; l++) {
+               DeleteLine(lineDoc);
        }
-       linesInDoc -= lineCount;
-       linesInDisplay += deltaDisplayed;
-       valid = false;
+       Check();
 }
 
 bool ContractionState::GetVisible(int lineDoc) const {
-       if (size == 0)
+       if (OneToOne()) {
                return true;
-       if ((lineDoc >= 0) && (lineDoc < linesInDoc)) {
-               return lines[lineDoc].visible;
        } else {
-               return false;
+               if (lineDoc >= visible->Length())
+                       return true;
+               return visible->ValueAt(lineDoc) == 1;
        }
 }
 
-bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible) {
-    if (lineDocStart == 0)
-        lineDocStart++;
-    if (lineDocStart > lineDocEnd)
-        return false;
-       if (size == 0) {
-               Grow(linesInDoc + growSize);
-       }
-       // TODO: modify docLine members to mirror displayLine
-       int delta = 0;
-       // Change lineDocs
-       if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < linesInDoc)) {
-               for (int line=lineDocStart; line <= lineDocEnd; line++) {
-                       if (lines[line].visible != visible) {
-                               delta += visible ? 1 : -1;              
-                               lines[line].visible = visible;
-                       }
-                       lines[line].displayLine += delta;
-               }
-               if (delta != 0) {
-                       for (int line=lineDocEnd+1; line <= linesInDoc; line++) {
-                               lines[line].displayLine += delta;
+bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible_) {
+       if (OneToOne() && visible_) {
+               return false;
+       } else {
+               EnsureData();
+               int delta = 0;
+               Check();
+               if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < LinesInDoc())) {
+                       for (int line = lineDocStart; line <= lineDocEnd; line++) {
+                               if (GetVisible(line) != visible_) {
+                                       int difference = visible_ ? heights->ValueAt(line) : -heights->ValueAt(line);
+                                       visible->SetValueAt(line, visible_ ? 1 : 0);
+                                       displayLines->InsertText(line, difference);
+                                       delta += difference;
+                               }
                        }
+               } else {
+                       return false;
                }
+               Check();
+               return delta != 0;
        }
-       linesInDisplay += delta;
-       valid = false;
-       return delta != 0;
 }
 
 bool ContractionState::GetExpanded(int lineDoc) const {
-       if (size == 0) 
+       if (OneToOne()) {
                return true;
-       if ((lineDoc >= 0) && (lineDoc < linesInDoc)) {
-               return lines[lineDoc].expanded;
        } else {
+               Check();
+               return expanded->ValueAt(lineDoc) == 1;
+       }
+}
+
+bool ContractionState::SetExpanded(int lineDoc, bool expanded_) {
+       if (OneToOne() && expanded_) {
                return false;
+       } else {
+               EnsureData();
+               if (expanded_ != (expanded->ValueAt(lineDoc) == 1)) {
+                       expanded->SetValueAt(lineDoc, expanded_ ? 1 : 0);
+                       Check();
+                       return true;
+               } else {
+                       Check();
+                       return false;
+               }
        }
 }
 
-bool ContractionState::SetExpanded(int lineDoc, bool expanded) {
-       if (size == 0) {
-               Grow(linesInDoc + growSize);
+int ContractionState::GetHeight(int lineDoc) const {
+       if (OneToOne()) {
+               return 1;
+       } else {
+               return heights->ValueAt(lineDoc);
        }
-       if ((lineDoc >= 0) && (lineDoc < linesInDoc)) {
-               if (lines[lineDoc].expanded != expanded) {
-                       lines[lineDoc].expanded = expanded;
+}
+
+// Set the number of display lines needed for this line.
+// Return true if this is a change.
+bool ContractionState::SetHeight(int lineDoc, int height) {
+       if (OneToOne() && (height == 1)) {
+               return false;
+       } else {
+               EnsureData();
+               if (GetHeight(lineDoc) != height) {
+                       if (GetVisible(lineDoc)) {
+                               displayLines->InsertText(lineDoc, height - GetHeight(lineDoc));
+                       }
+                       heights->SetValueAt(lineDoc, height);
+                       Check();
                        return true;
+               } else {
+                       Check();
+                       return false;
+               }
+       }
+}
+
+void ContractionState::ShowAll() {
+       int lines = LinesInDoc();
+       Clear();
+       linesInDocument = lines;
+}
+
+// Debugging checks
+
+void ContractionState::Check() const {
+#ifdef CHECK_CORRECTNESS
+       for (int vline = 0;vline < LinesDisplayed(); vline++) {
+               const int lineDoc = DocFromDisplay(vline);
+               PLATFORM_ASSERT(GetVisible(lineDoc));
+       }
+       for (int lineDoc = 0;lineDoc < LinesInDoc(); lineDoc++) {
+               const int displayThis = DisplayFromDoc(lineDoc);
+               const int displayNext = DisplayFromDoc(lineDoc + 1);
+               const int height = displayNext - displayThis;
+               PLATFORM_ASSERT(height >= 0);
+               if (GetVisible(lineDoc)) {
+                       PLATFORM_ASSERT(GetHeight(lineDoc) == height);
+               } else {
+                       PLATFORM_ASSERT(0 == height);
                }
        }
-       return false;
+#endif
 }