mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-12 07:13:23 +00:00
Fixed SimpleScrollAdapter to run in O(log_n) when refreshing the screen. Previously was O(n)
This commit is contained in:
parent
2407547325
commit
8f972ad4d8
@ -49,7 +49,7 @@ void ScrollableWindow::ScrollToBottom() {
|
||||
int total = (int) adapter->GetLineCount(this->GetWidth());
|
||||
int height = this->GetContentHeight();
|
||||
|
||||
int actual = total - height + 1;
|
||||
int actual = total - height;
|
||||
actual = (actual < 0) ? 0 : actual;
|
||||
|
||||
adapter->DrawPage(this->GetContents(), actual);
|
||||
@ -75,7 +75,7 @@ void ScrollableWindow::ScrollDown(int delta) {
|
||||
|
||||
int total = adapter->GetLineCount(this->GetWidth());
|
||||
int height = this->GetContentHeight();
|
||||
int optimal = total - height + 1;
|
||||
int optimal = total - height;
|
||||
int max = max(0, optimal);
|
||||
|
||||
int actual = (int) this->scrollPosition + delta;
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "SimpleScrollAdapter.h"
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
@ -14,18 +15,11 @@ void SimpleScrollAdapter::SetDisplaySize(size_t width, size_t height) {
|
||||
if (height != this->height || width != this->width) {
|
||||
this->height = height;
|
||||
this->width = width;
|
||||
this->lineCount = -1;
|
||||
Reindex();
|
||||
}
|
||||
}
|
||||
|
||||
size_t SimpleScrollAdapter::GetLineCount(size_t width) {
|
||||
if (this->lineCount == -1) {
|
||||
Iterator it = this->entries.begin();
|
||||
for ( ; it != entries.end(); it++) {
|
||||
this->lineCount += (*it)->GetLineCount(width);
|
||||
}
|
||||
}
|
||||
|
||||
return this->lineCount;
|
||||
}
|
||||
|
||||
@ -36,32 +30,18 @@ size_t SimpleScrollAdapter::GetEntryCount() {
|
||||
void SimpleScrollAdapter::DrawPage(WINDOW* window, size_t lineNumber) {
|
||||
wclear(window);
|
||||
|
||||
/* find the entry at the specified line number. this is really inefficient,
|
||||
and runs in O(n) time. need to figure out a way to speed this up. */
|
||||
/* binary search to find where we need to start */
|
||||
|
||||
int line = 0, curr = 0;
|
||||
bool found = false;
|
||||
Iterator it = this->entries.begin();
|
||||
for ( ; it != this->entries.end(); it++) {
|
||||
curr = (*it)->GetLineCount(this->width);
|
||||
|
||||
if (line + curr > lineNumber) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
line += curr;
|
||||
}
|
||||
}
|
||||
size_t offset = this->FindEntryIndex(lineNumber);
|
||||
Iterator it = this->entries.begin() + offset;
|
||||
|
||||
/* if found, the iterator will be pointing at the first visible
|
||||
element. */
|
||||
|
||||
if (found) {
|
||||
Iterator end = this->entries.end();
|
||||
size_t remaining = this->height;
|
||||
size_t w = this->width;
|
||||
size_t c = lineNumber - line;
|
||||
size_t c = lineNumber - (*it)->GetIndex();
|
||||
|
||||
do {
|
||||
size_t count = (*it)->GetLineCount(w);
|
||||
@ -74,31 +54,62 @@ void SimpleScrollAdapter::DrawPage(WINDOW* window, size_t lineNumber) {
|
||||
++it;
|
||||
c = 0;
|
||||
} while (it != end && remaining != 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SimpleScrollAdapter::AddLine(const std::string& str) {
|
||||
lineCount = -1;
|
||||
|
||||
std::vector<std::string> lines;
|
||||
boost::algorithm::split(lines, str, boost::is_any_of("\n"));
|
||||
|
||||
for (size_t i = 0; i < lines.size(); i++) {
|
||||
boost::shared_ptr<Entry> entry(new Entry(lines[i]));
|
||||
entry->SetIndex(this->lineCount++);
|
||||
entries.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
size_t SimpleScrollAdapter::FindEntryIndex(int lineNumber) {
|
||||
if (lineCount == -1) {
|
||||
Reindex();
|
||||
}
|
||||
|
||||
size_t min = 0, max = this->entries.size();
|
||||
|
||||
while (true) {
|
||||
size_t guess = (min + max) / 2;
|
||||
|
||||
Entry* entry = this->entries.at(guess).get();
|
||||
size_t first = entry->GetIndex();
|
||||
size_t last = first + entry->GetLineCount(this->width);
|
||||
if (lineNumber >= first && lineNumber <= last) {
|
||||
return guess;
|
||||
}
|
||||
else if (lineNumber > first) { /* guess too low */
|
||||
min = guess + 1;
|
||||
}
|
||||
else if (lineNumber < last) { /* guess too high */
|
||||
max = guess - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleScrollAdapter::Reindex() {
|
||||
int index = 0;
|
||||
for (Iterator it = this->entries.begin(); it != this->entries.end(); it++) {
|
||||
(*it)->SetIndex(index);
|
||||
index += (*it)->GetLineCount(this->width);
|
||||
}
|
||||
}
|
||||
|
||||
SimpleScrollAdapter::Entry::Entry(const std::string& value) {
|
||||
this->value = value;
|
||||
this->charCount = value.size(); // u8len(value);
|
||||
this->charCount = value.size();
|
||||
}
|
||||
|
||||
size_t SimpleScrollAdapter::Entry::GetLineCount(size_t width) {
|
||||
int full = (charCount / width);
|
||||
int remain = (charCount % width == 0 ? 0 : 1);
|
||||
return full + remain;
|
||||
return max(1, full + remain);
|
||||
}
|
||||
|
||||
std::string SimpleScrollAdapter::Entry::GetLine(size_t n, size_t width) {
|
||||
@ -112,3 +123,11 @@ std::string SimpleScrollAdapter::Entry::GetValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
size_t SimpleScrollAdapter::Entry::GetIndex() {
|
||||
return this->index;
|
||||
}
|
||||
|
||||
void SimpleScrollAdapter::Entry::SetIndex(size_t index) {
|
||||
this->index = index;
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <curses.h>
|
||||
#include "IScrollAdapter.h";
|
||||
|
||||
class SimpleScrollAdapter : public IScrollAdapter {
|
||||
@ -18,23 +16,31 @@ class SimpleScrollAdapter : public IScrollAdapter {
|
||||
virtual void AddLine(const std::string& str);
|
||||
|
||||
private:
|
||||
size_t lineCount, width, height;
|
||||
|
||||
class Entry : public IEntry {
|
||||
class Entry {
|
||||
public:
|
||||
Entry(const std::string& value);
|
||||
|
||||
virtual size_t GetLineCount(size_t width);
|
||||
virtual std::string GetLine(size_t line, size_t width);
|
||||
virtual std::string GetValue();
|
||||
size_t GetIndex();
|
||||
void SetIndex(size_t index);
|
||||
size_t GetLineCount(size_t width);
|
||||
std::string GetLine(size_t line, size_t width);
|
||||
std::string GetValue();
|
||||
|
||||
private:
|
||||
size_t index;
|
||||
std::string value;
|
||||
size_t charCount;
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
typedef std::vector<boost::shared_ptr<Entry>> EntryList;
|
||||
typedef EntryList::iterator Iterator;
|
||||
|
||||
|
||||
void Reindex();
|
||||
size_t FindEntryIndex(int index);
|
||||
|
||||
EntryList entries;
|
||||
size_t lineCount, width, height;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user