Files
Upsilon/escher/src/scroll_view.cpp
Émilie Feral 8eefe8e490 [escher] Improve scroll indicator render
Change-Id: I22fa1035ba33d2cadfc68fa6727fbaecdadd4efe
2017-01-27 11:52:02 +01:00

163 lines
5.5 KiB
C++

#include <escher/scroll_view.h>
extern "C" {
#include <assert.h>
}
ScrollView::ScrollView(View * contentView, KDCoordinate topMargin, KDCoordinate rightMargin,
KDCoordinate bottomMargin, KDCoordinate leftMargin, bool showIndicators, bool colorBackground,
KDColor backgroundColor, KDCoordinate indicatorThickness, KDColor indicatorColor,
KDColor backgroundIndicatorColor, KDCoordinate indicatorMargin) :
View(),
m_topMargin(topMargin),
m_offset(KDPointZero),
m_contentView(contentView),
m_verticalScrollIndicator(ScrollViewIndicator(ScrollViewIndicator::Direction::Vertical, indicatorColor, backgroundIndicatorColor, indicatorMargin)),
m_horizontalScrollIndicator(ScrollViewIndicator(ScrollViewIndicator::Direction::Horizontal, indicatorColor, backgroundIndicatorColor, indicatorMargin)),
m_rightMargin(rightMargin),
m_bottomMargin(bottomMargin),
m_leftMargin(leftMargin),
m_indicatorThickness(indicatorThickness),
m_showIndicators(showIndicators),
m_colorBackground(colorBackground),
m_backgroundColor(backgroundColor)
{
}
bool ScrollView::hasVerticalIndicator() const {
if (m_showIndicators) {
return m_verticalScrollIndicator.end() < 1 || m_verticalScrollIndicator.start() > 0;
}
return false;
}
bool ScrollView::hasHorizontalIndicator() const {
if (m_showIndicators) {
return m_horizontalScrollIndicator.end() < 1 || m_horizontalScrollIndicator.start() > 0;
}
return false;
}
int ScrollView::numberOfSubviews() const {
return 1 + hasVerticalIndicator() + hasHorizontalIndicator();
}
View * ScrollView::subviewAtIndex(int index) {
switch (index) {
case 0:
return m_contentView;
case 1:
return hasHorizontalIndicator() ? &m_horizontalScrollIndicator : &m_verticalScrollIndicator;
case 2:
return &m_verticalScrollIndicator;
}
return nullptr;
}
void ScrollView::drawRect(KDContext * ctx, KDRect rect) const {
if (!m_colorBackground) {
return;
}
KDCoordinate width = bounds().width();
KDCoordinate height = bounds().height();
ctx->fillRect(KDRect(0, 0, width, height), m_backgroundColor);
// Future optimization: avoid drawing behind the content view/
//ctx->fillRect(KDRect(m_leftMargin, m_contentView->bounds().height()+m_topMargin, width-m_leftMargin-m_rightMargin, height- m_contentView->bounds().height())-m_topMargin, m_backgroundColor);
}
void ScrollView::layoutSubviews() {
// Layout contentView
// We're only re-positionning the contentView, not modifying its size.
KDPoint absoluteOffset = m_offset.opposite().translatedBy(KDPoint(m_leftMargin, m_topMargin));
KDRect contentFrame = KDRect(absoluteOffset, m_contentView->bounds().size());
m_contentView->setFrame(contentFrame);
// We recompute the size of the scroll indicator
updateScrollIndicator();
// Layout indicators
/* If the two indicators are visible, we leave an empty rectangle in the right
* bottom corner. Otherwise, the only indicator uses all the height/width. */
if (hasHorizontalIndicator() && hasVerticalIndicator()) {
KDRect verticalIndicatorFrame = KDRect(
m_frame.width() - m_indicatorThickness, 0,
m_indicatorThickness, m_frame.height() - m_indicatorThickness
);
m_verticalScrollIndicator.setFrame(verticalIndicatorFrame);
KDRect horizontalIndicatorFrame = KDRect(
0, m_frame.height() - m_indicatorThickness,
m_frame.width() - m_indicatorThickness, m_indicatorThickness
);
m_horizontalScrollIndicator.setFrame(horizontalIndicatorFrame);
} else {
if (hasVerticalIndicator()) {
KDRect verticalIndicatorFrame = KDRect(
m_frame.width() - m_indicatorThickness, 0,
m_indicatorThickness, m_frame.height()
);
m_verticalScrollIndicator.setFrame(verticalIndicatorFrame);
}
if (hasHorizontalIndicator()) {
KDRect horizontalIndicatorFrame = KDRect(
0, m_frame.height() - m_indicatorThickness,
m_frame.width(), m_indicatorThickness
);
m_horizontalScrollIndicator.setFrame(horizontalIndicatorFrame);
}
}
}
void ScrollView::updateScrollIndicator() {
if (m_showIndicators) {
float contentHeight = m_contentView->bounds().height()+m_topMargin+m_bottomMargin;
float verticalStart = m_offset.y();
float verticalEnd = m_offset.y() + m_frame.height();
m_verticalScrollIndicator.setStart(verticalStart/contentHeight);
m_verticalScrollIndicator.setEnd(verticalEnd/contentHeight);
float contentWidth = m_contentView->bounds().width()+m_leftMargin+m_rightMargin;
float horizontalStart = m_offset.x();
float horizontalEnd = m_offset.x() + m_frame.width();
m_horizontalScrollIndicator.setStart(horizontalStart/contentWidth);
m_horizontalScrollIndicator.setEnd(horizontalEnd/contentWidth);
}
}
void ScrollView::setContentOffset(KDPoint offset) {
if (offset != m_offset) {
m_offset = offset;
layoutSubviews();
}
}
KDPoint ScrollView::contentOffset() {
return m_offset;
}
KDCoordinate ScrollView::topMargin() const {
return m_topMargin;
}
KDCoordinate ScrollView::leftMargin() const {
return m_leftMargin;
}
KDCoordinate ScrollView::maxContentWidthDisplayableWithoutScrolling() {
return m_frame.width() - m_leftMargin - m_rightMargin;
}
KDCoordinate ScrollView::maxContentHeightDisplayableWithoutScrolling() {
return m_frame.height() - m_topMargin - m_bottomMargin;
}
#if ESCHER_VIEW_LOGGING
const char * ScrollView::className() const {
return "ScrollView";
}
void ScrollView::logAttributes(std::ostream &os) const {
View::logAttributes(os);
os << " offset=\"" << (int)m_offset.x << "," << (int)m_offset.y << "\"";
}
#endif