1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2004-2021 musikcube team
4 //
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // * Redistributions of source code must retain the above copyright notice,
11 // this list of conditions and the following disclaimer.
12 //
13 // * Redistributions in binary form must reproduce the above copyright
14 // notice, this list of conditions and the following disclaimer in the
15 // documentation and/or other materials provided with the distribution.
16 //
17 // * Neither the name of the author nor the names of other contributors may
18 // be used to endorse or promote products derived from this software
19 // without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 //
33 //////////////////////////////////////////////////////////////////////////////
34
35 #include <stdafx.h>
36 #include <cursespp/ScrollAdapterBase.h>
37 #include <cursespp/ScrollableWindow.h>
38 #include <cursespp/MultiLineEntry.h>
39 #include <cursespp/ListWindow.h>
40
41 using namespace cursespp;
42
43 typedef IScrollAdapter::EntryPtr EntryPtr;
44
ScrollAdapterBase()45 ScrollAdapterBase::ScrollAdapterBase() {
46 this->height = 0;
47 this->width = 0;
48 }
49
~ScrollAdapterBase()50 ScrollAdapterBase::~ScrollAdapterBase() {
51
52 }
53
SetDisplaySize(size_t width,size_t height)54 void ScrollAdapterBase::SetDisplaySize(size_t width, size_t height) {
55 this->width = width;
56 this->height = height;
57 }
58
GetLineCount()59 size_t ScrollAdapterBase::GetLineCount() {
60 return -1;
61 }
62
GetVisibleItems(cursespp::ScrollableWindow * window,size_t desiredTopIndex,std::deque<EntryPtr> & target)63 size_t ScrollAdapterBase::GetVisibleItems(
64 cursespp::ScrollableWindow* window,
65 size_t desiredTopIndex,
66 std::deque<EntryPtr>& target)
67 {
68 size_t actualTopIndex = desiredTopIndex;
69
70 /* ensure we have enough data to draw from the specified position
71 to the end. if we don't try to back up a bit until we can fill
72 the buffer */
73 int totalHeight = (int) this->height;
74 int entryCount = (int) this->GetEntryCount();
75
76 /* we assume the general case -- we're some where in the middle of the
77 list. we'll start from the specified first item and work our way down */
78 for (int i = (int) desiredTopIndex; i < entryCount && totalHeight > 0; i++) {
79 EntryPtr entry = this->GetEntry(window, i);
80 entry->SetWidth(this->width);
81 totalHeight -= entry->GetLineCount();
82 target.push_back(entry);
83 }
84
85 /* however, if the list is short, we can actually draw more items above
86 the specified one. let's work our way backwards! */
87 if (totalHeight > 0) {
88 target.clear();
89
90 totalHeight = this->height;
91 int i = GetEntryCount() - 1;
92 while (i >= 0 && totalHeight >= 0) {
93 EntryPtr entry = this->GetEntry(window, i);
94 entry->SetWidth(this->width);
95
96 int lines = entry->GetLineCount();
97 if (lines > totalHeight) {
98 break; /* this Entry won't fit. bail. */
99 }
100
101 totalHeight -= lines;
102 target.push_front(entry);
103 --i;
104 }
105
106 actualTopIndex = i + 1;
107 }
108
109 return actualTopIndex;
110 }
111
DrawPage(ScrollableWindow * scrollable,size_t index,ScrollPosition & result)112 void ScrollAdapterBase::DrawPage(ScrollableWindow* scrollable, size_t index, ScrollPosition& result) {
113 WINDOW* window = scrollable->GetContent();
114
115 if (!scrollable->IsVisible() || !window || this->height == 0 || this->width == 0) {
116 return;
117 }
118
119 werase(window);
120
121 std::deque<EntryPtr> visible;
122 size_t drawnLines = 0;
123 size_t topIndex = 0;
124 size_t count = GetEntryCount();
125
126 if (count > 0) {
127 if (index >= count) {
128 index = count - 1;
129 }
130
131 topIndex = GetVisibleItems(scrollable, index, visible);
132
133 for (size_t e = 0; e < visible.size(); e++) {
134 EntryPtr entry = visible.at(e);
135 size_t count = entry->GetLineCount();
136
137 for (size_t i = 0; i < count && drawnLines < this->height; i++) {
138 Color attrs = Color::Default;
139
140 if (this->decorator) {
141 attrs = this->decorator(scrollable, topIndex + e, i, entry);
142 }
143
144 if (attrs == -1) {
145 attrs = entry->GetAttrs(i);
146 }
147
148 if (attrs != -1) {
149 wattron(window, attrs);
150 }
151
152 std::string line = entry->GetLine(i);
153 size_t len = u8cols(line);
154
155 /* pad with empty spaces to the end of the line. this allows us to
156 do highlight rows. this should probably be configurable. */
157
158 int remain = this->width - len;
159 if (remain > 0) {
160 line += std::string(remain, ' ');
161 }
162
163 /* string is padded above, we don't need a \n */
164
165 checked_wprintw(window, "%s", line.c_str());
166
167 if (attrs != -1) {
168 wattroff(window, attrs);
169 }
170
171 ++drawnLines;
172 }
173 }
174 }
175
176 result.visibleEntryCount = visible.size();
177 result.firstVisibleEntryIndex = topIndex;
178 result.lineCount = drawnLines;
179 result.totalEntries = count;
180 }
181