diff options
-rw-r--r-- | src/Decoration.cxx | 183 | ||||
-rw-r--r-- | src/Decoration.h | 55 | ||||
-rw-r--r-- | src/RunStyles.cxx | 187 | ||||
-rw-r--r-- | src/RunStyles.h | 31 |
4 files changed, 456 insertions, 0 deletions
diff --git a/src/Decoration.cxx b/src/Decoration.cxx new file mode 100644 index 000000000..f1c9c5ae3 --- /dev/null +++ b/src/Decoration.cxx @@ -0,0 +1,183 @@ +/** @file Decoration.cxx + ** Visual elements added over text. + **/ +// Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> + +#include "Platform.h" + +#include "Scintilla.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" +#include "Decoration.h" + +Decoration::Decoration(int indicator_) : next(0), indicator(indicator_) { +} + +Decoration::~Decoration() { +} + +bool Decoration::Empty() { + return rs.starts->Partitions() == 1; +} + +DecorationList::DecorationList() : currentIndicator(0), currentValue(1), current(0), + lengthDocument(0), root(0), clickNotified(false) { +} + +DecorationList::~DecorationList() { + Decoration *deco = root; + while (deco) { + Decoration *decoNext = deco->next; + delete deco; + deco = decoNext; + } + root = 0; + current = 0; +} + +Decoration *DecorationList::DecorationFromIndicator(int indicator) { + for (Decoration *deco=root; deco; deco = deco->next) { + if (deco->indicator == indicator) { + return deco; + } + } + return 0; +} + +Decoration *DecorationList::Create(int indicator, int length) { + currentIndicator = indicator; + Decoration *decoNew = new Decoration(indicator); + decoNew->rs.InsertSpace(0, length); + + Decoration *decoPrev = 0; + Decoration *deco = root; + + while (deco && (deco->indicator < indicator)) { + decoPrev = deco; + deco = deco->next; + } + if (decoPrev == 0) { + decoNew->next = root; + root = decoNew; + } else { + decoNew->next = deco; + decoPrev->next = decoNew; + } + return decoNew; +} + +void DecorationList::Delete(int indicator) { + Decoration *decoToDelete = 0; + if (root) { + if (root->indicator == indicator) { + decoToDelete = root; + root = root->next; + } else { + Decoration *deco=root; + while (deco->next && !decoToDelete) { + if (deco->next && deco->next->indicator == indicator) { + decoToDelete = deco->next; + deco->next = decoToDelete->next; + } else { + deco = deco->next; + } + } + } + } + if (decoToDelete) { + delete decoToDelete; + current = 0; + } +} + +void DecorationList::SetCurrentIndicator(int indicator) { + currentIndicator = indicator; + current = DecorationFromIndicator(indicator); + currentValue = 1; +} + +void DecorationList::SetCurrentValue(int value) { + currentValue = value; +} + +void DecorationList::FillRange(int position, int value, int fillLength) { + if (!current) { + current = DecorationFromIndicator(currentIndicator); + if (!current) { + current = Create(currentIndicator, lengthDocument); + } + } + current->rs.FillRange(position, value, fillLength); + if (current->Empty()) { + Delete(currentIndicator); + } +} + +void DecorationList::InsertSpace(int position, int insertLength) { + lengthDocument += insertLength; + for (Decoration *deco=root; deco; deco = deco->next) { + deco->rs.InsertSpace(position, insertLength); + } +} + +void DecorationList::DeleteRange(int position, int deleteLength) { + lengthDocument -= deleteLength; + Decoration *deco; + for (deco=root; deco; deco = deco->next) { + deco->rs.DeleteRange(position, deleteLength); + } + DeleteAnyEmpty(); +} + +void DecorationList::DeleteAnyEmpty() { + Decoration *deco = root; + while (deco) { + if (deco->Empty()) { + Delete(deco->indicator); + deco = root; + } else { + deco = deco->next; + } + } +} + +int DecorationList::AllOnFor(int position) { + int mask = 0; + for (Decoration *deco=root; deco; deco = deco->next) { + if (deco->rs.ValueAt(position)) { + mask |= 1 << deco->indicator; + } + } + return mask; +} + +int DecorationList::ValueAt(int indicator, int position) { + Decoration *deco = DecorationFromIndicator(indicator); + if (deco) { + return deco->rs.ValueAt(position); + } + return 0; +} + +int DecorationList::Start(int indicator, int position) { + Decoration *deco = DecorationFromIndicator(indicator); + if (deco) { + return deco->rs.StartRun(position); + } + return 0; +} + +int DecorationList::End(int indicator, int position) { + Decoration *deco = DecorationFromIndicator(indicator); + if (deco) { + return deco->rs.EndRun(position); + } + return 0; +} diff --git a/src/Decoration.h b/src/Decoration.h new file mode 100644 index 000000000..1810b0fb3 --- /dev/null +++ b/src/Decoration.h @@ -0,0 +1,55 @@ +/** @file Decoration.h + ** Visual elements added over text. + **/ +// Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef DECORATION_H +#define DECORATION_H + +class Decoration { +public: + Decoration *next; + RunStyles rs; + int indicator; + + Decoration(int indicator_); + ~Decoration(); + + bool Empty(); +}; + +class DecorationList { + int currentIndicator; + int currentValue; + Decoration *current; + int lengthDocument; + Decoration *DecorationFromIndicator(int indicator); + Decoration *Create(int indicator, int length); + void Delete(int indicator); + void DeleteAnyEmpty(); +public: + Decoration *root; + bool clickNotified; + + DecorationList(); + ~DecorationList(); + + void SetCurrentIndicator(int indicator); + int GetCurrentIndicator() { return currentIndicator; } + + void SetCurrentValue(int value); + int GetCurrentValue() { return currentValue; } + + void FillRange(int position, int value, int fillLength); + + void InsertSpace(int position, int insertLength); + void DeleteRange(int position, int deleteLength); + + int AllOnFor(int position); + int ValueAt(int indicator, int position); + int Start(int indicator, int position); + int End(int indicator, int position); +}; + +#endif diff --git a/src/RunStyles.cxx b/src/RunStyles.cxx new file mode 100644 index 000000000..a7cf40e81 --- /dev/null +++ b/src/RunStyles.cxx @@ -0,0 +1,187 @@ +/** @file RunStyles.cxx + ** Data structure used to store sparse styles. + **/ +// Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> + +#include "Platform.h" + +#include "Scintilla.h" +#include "SplitVector.h" +#include "Partitioning.h" +#include "RunStyles.h" + +// Find the first run at a position +int RunStyles::RunFromPosition(int position) { + int run = starts->PartitionFromPosition(position); + // Go to first element with this position + while ((run > 0) && (position == starts->PositionFromPartition(run-1))) { + run--; + } + return run; +} + +// If there is no run boundary at position, insert one continuing style. +void RunStyles::SplitRun(int position) { + int run = RunFromPosition(position); + int posRun = starts->PositionFromPartition(run); + if (posRun < position) { + int runStyle = ValueAt(position); + starts->InsertPartition(run+1, position); + styles->InsertValue(run+1, 1, runStyle); + } +} + +void RunStyles::RemoveRun(int run) { + starts->RemovePartition(run); + styles->DeleteRange(run, 1); +} + +void RunStyles::RemoveRunIfEmpty(int run) { + if ((run < starts->Partitions()) && (starts->Partitions() > 1)) { + if (starts->PositionFromPartition(run) == starts->PositionFromPartition(run+1)) { + RemoveRun(run); + } + } +} + +void RunStyles::RemoveRunIfSameAsPrevious(int run) { + if ((run > 0) && (run < starts->Partitions())) { + if (styles->ValueAt(run-1) == styles->ValueAt(run)) { + RemoveRun(run); + } + } +} + +RunStyles::RunStyles() { + starts = new Partitioning(8); + styles = new SplitVector<int>(); + styles->InsertValue(0, 2, 0); +} + +RunStyles::~RunStyles() { + delete starts; + starts = NULL; + delete styles; + styles = NULL; +} + +int RunStyles::Length() { + return starts->PositionFromPartition(starts->Partitions()); +} + +int RunStyles::ValueAt(int position) { + return styles->ValueAt(starts->PartitionFromPosition(position)); +} + +int RunStyles::FindNextChange(int position, int end) { + int run = starts->PartitionFromPosition(position); + if (run < starts->Partitions()) { + int runChange = starts->PositionFromPartition(run); + if (runChange > position) + return runChange; + int nextChange = starts->PositionFromPartition(run + 1); + if (nextChange > position) { + return nextChange; + } else if (position < end) { + return end; + } else { + return end + 1; + } + } else { + return end + 1; + } +} + +int RunStyles::StartRun(int position) { + return starts->PositionFromPartition(starts->PartitionFromPosition(position)); +} + +int RunStyles::EndRun(int position) { + return starts->PositionFromPartition(starts->PartitionFromPosition(position) + 1); +} + +void RunStyles::FillRange(int position, int value, int fillLength) { + int end = position + fillLength; + SplitRun(end); + int runStart = RunFromPosition(position); + if (styles->ValueAt(runStart) != value) { + SplitRun(position); + runStart = RunFromPosition(position); + styles->SetValueAt(runStart, value); + } + int runEnd = RunFromPosition(end); + // Remove each old run over the range + for (int run=runStart+1; run<runEnd; run++) { + RemoveRun(runStart+1); + } + runEnd = RunFromPosition(end); + RemoveRunIfSameAsPrevious(runEnd); + RemoveRunIfSameAsPrevious(runStart); +} + +void RunStyles::InsertSpace(int position, int insertLength) { + int runStart = RunFromPosition(position); + if (starts->PositionFromPartition(runStart) == position) { + int runStyle = ValueAt(position); + // Inserting at start of run so make previous longer + if (runStart == 0) { + // Inserting at start of document so ensure 0 + if (runStyle) { + styles->SetValueAt(0, 0); + starts->InsertPartition(1, 0); + styles->InsertValue(1, 1, runStyle); + starts->InsertText(0, insertLength); + } else { + starts->InsertText(runStart, insertLength); + } + } else { + if (runStyle) { + starts->InsertText(runStart-1, insertLength); + } else { + // Insert at end of run so do not extend style + starts->InsertText(runStart, insertLength); + } + } + } else { + starts->InsertText(runStart, insertLength); + } +} + +void RunStyles::DeleteAll() { + delete starts; + starts = NULL; + delete styles; + styles = NULL; + starts = new Partitioning(8); + styles = new SplitVector<int>(); + styles->InsertValue(0, 2, 0); +} + +void RunStyles::DeleteRange(int position, int deleteLength) { + int end = position + deleteLength; + int runStart = RunFromPosition(position); + int runEnd = RunFromPosition(end); + if (runStart == runEnd) { + // Deleting from inside one run + starts->InsertText(runStart, -deleteLength); + } else { + SplitRun(position); + SplitRun(end); + runStart = RunFromPosition(position); + runEnd = RunFromPosition(end); + starts->InsertText(runStart, -deleteLength); + // Remove each old run over the range + for (int run=runStart; run<runEnd; run++) { + RemoveRun(runStart); + } + RemoveRunIfEmpty(runStart); + RemoveRunIfSameAsPrevious(runStart); + } +} + diff --git a/src/RunStyles.h b/src/RunStyles.h new file mode 100644 index 000000000..539e5de47 --- /dev/null +++ b/src/RunStyles.h @@ -0,0 +1,31 @@ +/** @file RunStyles.h + ** Data structure used to store sparse styles. + **/ +// Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +/// Styling buffer using one element for each run rather than using +/// a filled buffer. + +class RunStyles { +public: + Partitioning *starts; + SplitVector<int> *styles; + int RunFromPosition(int position); + void SplitRun(int position); + void RemoveRun(int run); + void RemoveRunIfEmpty(int run); + void RemoveRunIfSameAsPrevious(int run); +public: + RunStyles(); + ~RunStyles(); + int Length(); + int ValueAt(int position); + int FindNextChange(int position, int end); + int StartRun(int position); + int EndRun(int position); + void FillRange(int position, int value, int fillLength); + void InsertSpace(int position, int insertLength); + void DeleteAll(); + void DeleteRange(int position, int deleteLength); +}; |