The Pedigree Project 0.1
Scrollable.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/debugger/Scrollable.h"
21
22namespace {
23void drawClippedString(DebuggerIO* screen, const char* text, size_t row, size_t column,
24 size_t width, size_t offset, DebuggerIO::Colour colour,
25 DebuggerIO::Colour bgColour) {
26 if (!text || column >= width) {
27 return;
28 }
29
30 const size_t length = StringLength(text);
31 if (offset >= length) {
32 return;
33 }
34
35 HugeStaticString clipped(text + offset, width - column);
36 screen->drawString(clipped, row, column, colour, bgColour);
37}
38
39void drawScrolledString(DebuggerIO* screen, const char* text, size_t row, size_t left, size_t right,
40 size_t logicalColumn, size_t horizontalOffset, DebuggerIO::Colour colour,
41 DebuggerIO::Colour bgColour) {
42 if (horizontalOffset < logicalColumn) {
43 drawClippedString(screen, text, row, left + logicalColumn - horizontalOffset, right, 0, colour,
44 bgColour);
45 } else {
46 drawClippedString(screen, text, row, left, right, horizontalOffset - logicalColumn, colour,
47 bgColour);
48 }
49}
50} // namespace
51
52Scrollable::Scrollable()
53 : m_x(0),
54 m_y(0),
55 m_width(0),
56 m_height(0),
57 m_line(0),
58 m_column(0),
59 m_ScrollUp('j'),
60 m_ScrollDown('k') {}
61Scrollable::~Scrollable() = default;
62
63void Scrollable::move(size_t x, size_t y) {
64 m_x = x;
65 m_y = y;
66}
67
68void Scrollable::resize(size_t width, size_t height) {
69 m_width = width;
70 m_height = height;
71 horizontalScrollTo(m_column);
72}
73
74void Scrollable::scroll(ssize_t lines) {
75 m_line += lines;
76
77 if (m_line > (static_cast<ssize_t>(getLineCount()) - static_cast<ssize_t>(m_height)))
78 m_line = static_cast<ssize_t>(getLineCount()) - static_cast<ssize_t>(m_height);
79
80 if (m_line < 0)
81 m_line = 0;
82}
83
84void Scrollable::scrollTo(size_t absolute) {
85 m_line = absolute;
86
87 if (m_line > (static_cast<ssize_t>(getLineCount()) - static_cast<ssize_t>(m_height)))
88 m_line = static_cast<ssize_t>(getLineCount()) - static_cast<ssize_t>(m_height);
89
90 if (m_line < 0)
91 m_line = 0;
92}
93
94void Scrollable::scrollHorizontal(ssize_t columns) {
95 horizontalScrollTo(
96 static_cast<size_t>(max(static_cast<ssize_t>(0), static_cast<ssize_t>(m_column) + columns)));
97}
98
99void Scrollable::horizontalScrollTo(size_t absolute) {
100 const ssize_t maxColumn = max(static_cast<ssize_t>(0), static_cast<ssize_t>(getContentWidth()) -
101 static_cast<ssize_t>(m_width));
102 m_column = min(absolute, static_cast<size_t>(maxColumn));
103}
104
105void Scrollable::refresh(DebuggerIO* pScreen) {
106 pScreen->disableRefreshes();
107
108 // TODO: Add a scroll bar on the right side of the window
109
110 // Can we scroll up?
111 bool bCanScrollUp = (m_line > 0);
112 bool bCanScrollDown = ((m_line + m_height) < getLineCount());
113
114 // For every available line.
115 ssize_t line = m_line;
116 for (size_t i = 0; i < m_height; i++) {
117 pScreen->drawHorizontalLine(' ', m_y + i, m_x, m_x + m_width - 1, DebuggerIO::White,
118 DebuggerIO::Black);
119
120 if (line >= 0 && line < static_cast<ssize_t>(getLineCount())) {
121 DebuggerIO::Colour colour = DebuggerIO::White;
122 DebuggerIO::Colour bgColour = DebuggerIO::Black;
123 size_t colOffset;
124 const char* Line = getLine1(line, colour, bgColour);
125 drawScrolledString(pScreen, Line, m_y + i, m_x, m_x + m_width, 0, m_column, colour, bgColour);
126
127 colour = DebuggerIO::White;
128 bgColour = DebuggerIO::Black;
129 Line = getLine2(line, colOffset, colour, bgColour);
130 drawScrolledString(pScreen, Line, m_y + i, m_x, m_x + m_width, colOffset, m_column, colour,
131 bgColour);
132 }
133 line++;
134 }
135
136 // Draw scroll marks.
137 char str[4] = {'^', ' ', m_ScrollUp, '\0'};
138 if (bCanScrollUp)
139 pScreen->drawString(str, m_y, m_x + m_width - 3, DebuggerIO::White, DebuggerIO::Blue);
140 str[0] = 'v';
141 str[2] = m_ScrollDown;
142 if (bCanScrollDown)
143 pScreen->drawString(str, m_y + m_height - 1, m_x + m_width - 3, DebuggerIO::White,
144 DebuggerIO::Blue);
145
146 pScreen->enableRefreshes();
147}
148
149void Scrollable::setScrollKeys(char up, char down) {
150 m_ScrollUp = up;
151 m_ScrollDown = down;
152}
153
154ssize_t Scrollable::getLine() {
155 return m_line;
156}
157
158void Scrollable::centreOn(size_t line) {
159 if (line > getLineCount())
160 line = getLineCount();
161
162 if (line < m_height) {
163 scrollTo(0);
164 return;
165 }
166
167 scrollTo(line - (m_height / 2));
168}
169
170size_t Scrollable::height() const {
171 return m_height;
172}
173size_t Scrollable::width() const {
174 return m_width;
175}
176
177size_t Scrollable::getContentWidth() {
178 return m_width;
179}
virtual void enableRefreshes()=0
virtual void drawString(const char *str, size_t row, size_t col, Colour foreColour, Colour backColour)=0
virtual void drawHorizontalLine(char c, size_t row, size_t colStart, size_t colEnd, Colour foreColour, Colour backColour)=0