You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
415 lines
13 KiB
415 lines
13 KiB
/*
|
|
Rosegarden
|
|
A MIDI and audio sequencer and musical notation editor.
|
|
|
|
This program is Copyright 2000-2008
|
|
Guillaume Laurent <glaurent@telegraph-road.org>,
|
|
Chris Cannam <cannam@all-day-breakfast.com>,
|
|
Richard Bown <richard.bown@ferventsoftware.com>
|
|
|
|
The moral rights of Guillaume Laurent, Chris Cannam, and Richard
|
|
Bown to claim authorship of this work have been asserted.
|
|
|
|
Other copyrights also apply to some parts of this work. Please
|
|
see the AUTHORS file and individual file headers for details.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version. See the file
|
|
COPYING included with this distribution for more information.
|
|
*/
|
|
|
|
|
|
#include "RosegardenScrollView.h"
|
|
|
|
#include "misc/Debug.h"
|
|
#include <tqapplication.h>
|
|
#include <tqcursor.h>
|
|
#include <tqpoint.h>
|
|
#include <tqrect.h>
|
|
#include <tqscrollbar.h>
|
|
#include <tqscrollview.h>
|
|
#include <tqsizepolicy.h>
|
|
#include <tqtimer.h>
|
|
#include <tqwidget.h>
|
|
|
|
|
|
namespace Rosegarden
|
|
{
|
|
|
|
// Smooth scroll checks
|
|
//
|
|
|
|
const int RosegardenScrollView::AutoscrollMargin = 16;
|
|
const int RosegardenScrollView::InitialScrollTime = 30;
|
|
const int RosegardenScrollView::InitialScrollAccel = 5;
|
|
const int RosegardenScrollView::MaxScrollDelta = 100; // max a.scroll speed
|
|
const double RosegardenScrollView::ScrollAccelValue = 1.04;// acceleration rate
|
|
|
|
RosegardenScrollView::RosegardenScrollView(TQWidget* parent,
|
|
const char* name, WFlags f)
|
|
: TQScrollView(parent, name, f),
|
|
m_bottomWidget(0),
|
|
m_currentBottomWidgetHeight( -1),
|
|
m_smoothScroll(true),
|
|
m_smoothScrollTimeInterval(DefaultSmoothScrollTimeInterval),
|
|
m_minDeltaScroll(DefaultMinDeltaScroll),
|
|
m_autoScrollTime(InitialScrollTime),
|
|
m_autoScrollAccel(InitialScrollAccel),
|
|
m_autoScrollXMargin(0),
|
|
m_autoScrollYMargin(0),
|
|
m_currentScrollDirection(None),
|
|
m_scrollDirectionConstraint(NoFollow),
|
|
m_autoScrolling(false)
|
|
{
|
|
setDragAutoScroll(true);
|
|
connect( &m_autoScrollTimer, TQ_SIGNAL( timeout() ),
|
|
this, TQ_SLOT( doAutoScroll() ) );
|
|
}
|
|
|
|
void RosegardenScrollView::setBottomFixedWidget(TQWidget* w)
|
|
{
|
|
m_bottomWidget = w;
|
|
if (m_bottomWidget) {
|
|
m_bottomWidget->reparent(this, 0, TQPoint(0, 0));
|
|
m_bottomWidget->setSizePolicy(TQSizePolicy(TQSizePolicy::Preferred, TQSizePolicy::Fixed));
|
|
setMargins(0, 0, 0, m_bottomWidget->sizeHint().height());
|
|
}
|
|
}
|
|
|
|
void RosegardenScrollView::startAutoScroll()
|
|
{
|
|
// RG_DEBUG << "RosegardenScrollView::startAutoScroll()\n";
|
|
|
|
if ( !m_autoScrollTimer.isActive() ) {
|
|
m_autoScrollTime = InitialScrollTime;
|
|
m_autoScrollAccel = InitialScrollAccel;
|
|
m_autoScrollTimer.start( m_autoScrollTime );
|
|
}
|
|
|
|
TQPoint autoScrollStartPoint = viewport()->mapFromGlobal( TQCursor::pos() );
|
|
m_autoScrollYMargin = autoScrollStartPoint.y() / 10;
|
|
m_autoScrollXMargin = autoScrollStartPoint.x() / 10;
|
|
|
|
m_autoScrolling = true;
|
|
}
|
|
|
|
void RosegardenScrollView::startAutoScroll(int directionConstraint)
|
|
{
|
|
setScrollDirectionConstraint(directionConstraint);
|
|
startAutoScroll();
|
|
}
|
|
|
|
void RosegardenScrollView::stopAutoScroll()
|
|
{
|
|
// RG_DEBUG << "RosegardenScrollView::stopAutoScroll()\n";
|
|
|
|
m_autoScrollTimer.stop();
|
|
m_minDeltaScroll = DefaultMinDeltaScroll;
|
|
m_currentScrollDirection = None;
|
|
|
|
m_autoScrolling = false;
|
|
}
|
|
|
|
void RosegardenScrollView::doAutoScroll()
|
|
{
|
|
// RG_DEBUG << "RosegardenScrollView::doAutoScroll()\n";
|
|
|
|
TQPoint p = viewport()->mapFromGlobal( TQCursor::pos() );
|
|
TQPoint dp = p - m_previousP;
|
|
m_previousP = p;
|
|
|
|
m_autoScrollTimer.start( m_autoScrollTime );
|
|
ScrollDirection scrollDirection = None;
|
|
|
|
int dx = 0, dy = 0;
|
|
if (m_scrollDirectionConstraint & FollowVertical) {
|
|
if ( p.y() < m_autoScrollYMargin ) {
|
|
dy = -(int(m_minDeltaScroll));
|
|
scrollDirection = Top;
|
|
} else if ( p.y() > visibleHeight() - m_autoScrollYMargin ) {
|
|
dy = + (int(m_minDeltaScroll));
|
|
scrollDirection = Bottom;
|
|
}
|
|
}
|
|
bool startDecelerating = false;
|
|
if (m_scrollDirectionConstraint & FollowHorizontal) {
|
|
|
|
// RG_DEBUG << "p.x() : " << p.x() << " - visibleWidth : " << visibleWidth() << " - autoScrollXMargin : " << m_autoScrollXMargin << endl;
|
|
|
|
if ( p.x() < m_autoScrollXMargin ) {
|
|
if ( dp.x() > 0 ) {
|
|
startDecelerating = true;
|
|
m_minDeltaScroll /= ScrollAccelValue;
|
|
}
|
|
dx = -(int(m_minDeltaScroll));
|
|
scrollDirection = Left;
|
|
} else if ( p.x() > visibleWidth() - m_autoScrollXMargin ) {
|
|
if ( dp.x() < 0 ) {
|
|
startDecelerating = true;
|
|
m_minDeltaScroll /= ScrollAccelValue;
|
|
}
|
|
dx = + (int(m_minDeltaScroll));
|
|
scrollDirection = Right;
|
|
}
|
|
}
|
|
|
|
// RG_DEBUG << "dx: " << dx << ", dy: " << dy << endl;
|
|
|
|
if ( (dx || dy) &&
|
|
((scrollDirection == m_currentScrollDirection) || (m_currentScrollDirection == None)) ) {
|
|
scrollBy(dx, dy);
|
|
if ( startDecelerating )
|
|
m_minDeltaScroll /= ScrollAccelValue;
|
|
else
|
|
m_minDeltaScroll *= ScrollAccelValue;
|
|
if (m_minDeltaScroll > MaxScrollDelta )
|
|
m_minDeltaScroll = MaxScrollDelta;
|
|
m_currentScrollDirection = scrollDirection;
|
|
|
|
} else {
|
|
// Don't automatically stopAutoScroll() here, the mouse button
|
|
// is presumably still pressed.
|
|
m_minDeltaScroll = DefaultMinDeltaScroll;
|
|
m_currentScrollDirection = None;
|
|
}
|
|
|
|
}
|
|
|
|
const int RosegardenScrollView::DefaultSmoothScrollTimeInterval = 10;
|
|
const double RosegardenScrollView::DefaultMinDeltaScroll = 1.2;
|
|
|
|
bool RosegardenScrollView::isTimeForSmoothScroll()
|
|
{
|
|
static int desktopWidth = TQApplication::desktop()->width(),
|
|
desktopHeight = TQApplication::desktop()->height();
|
|
|
|
if (m_smoothScroll) {
|
|
int ta = m_scrollAccelerationTimer.elapsed();
|
|
int t = m_scrollTimer.elapsed();
|
|
|
|
RG_DEBUG << "t = " << t << ", ta = " << ta << ", int " << m_smoothScrollTimeInterval << ", delta " << m_minDeltaScroll << endl;
|
|
|
|
if (t < m_smoothScrollTimeInterval) {
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
if (ta > 300) {
|
|
// reset smoothScrollTimeInterval
|
|
m_smoothScrollTimeInterval = DefaultSmoothScrollTimeInterval;
|
|
m_minDeltaScroll = DefaultMinDeltaScroll;
|
|
m_scrollAccelerationTimer.restart();
|
|
} else if (ta > 50) {
|
|
// m_smoothScrollTimeInterval /= 2;
|
|
m_minDeltaScroll *= 1.08;
|
|
m_scrollAccelerationTimer.restart();
|
|
}
|
|
|
|
m_scrollTimer.restart();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void RosegardenScrollView::slotScrollHoriz(int hpos)
|
|
{
|
|
TQScrollBar* hbar = getMainHorizontalScrollBar();
|
|
int currentContentYPos = contentsY();
|
|
|
|
/* Lots of performance hitting debug
|
|
RG_DEBUG << "RosegardenCanvasView::slotScrollHoriz: hpos is " << hpos
|
|
<< ", contentsX is " << contentsX() << ", visibleWidth is "
|
|
<< visibleWidth() << endl;
|
|
*/
|
|
|
|
if (hpos == 0) {
|
|
|
|
// returning to zero
|
|
// hbar->setValue(0);
|
|
setContentsPos(0, currentContentYPos);
|
|
|
|
} else if (hpos > (contentsX() +
|
|
visibleWidth() * 1.6) ||
|
|
hpos < (contentsX() -
|
|
visibleWidth() * 0.7)) {
|
|
|
|
// miles off one side or the other
|
|
// hbar->setValue(hpos - int(visibleWidth() * 0.4));
|
|
setContentsPos(hpos - int(visibleWidth() * 0.4), currentContentYPos);
|
|
|
|
} else if (hpos > (contentsX() +
|
|
visibleWidth() * 0.9)) {
|
|
|
|
// moving off the right hand side of the view
|
|
// hbar->setValue(hbar->value() + int(visibleWidth() * 0.6));
|
|
setContentsPos(hbar->value() + int(visibleWidth() * 0.6), currentContentYPos);
|
|
|
|
} else if (hpos < (contentsX() +
|
|
visibleWidth() * 0.1)) {
|
|
|
|
// moving off the left
|
|
// hbar->setValue(hbar->value() - int(visibleWidth() * 0.6));
|
|
setContentsPos(hbar->value() - int(visibleWidth() * 0.6), currentContentYPos);
|
|
}
|
|
}
|
|
|
|
void RosegardenScrollView::slotScrollHorizSmallSteps(int hpos)
|
|
{
|
|
TQScrollBar* hbar = getMainHorizontalScrollBar();
|
|
int currentContentYPos = contentsY();
|
|
|
|
int diff = 0;
|
|
|
|
if (hpos == 0) {
|
|
|
|
// returning to zero
|
|
// hbar->setValue(0);
|
|
setContentsPos(0, currentContentYPos);
|
|
|
|
} else if ((diff = int(hpos - (contentsX() +
|
|
visibleWidth() * 0.90))) > 0) {
|
|
|
|
// moving off the right hand side of the view
|
|
|
|
int delta = diff / 6;
|
|
int diff10 = std::min(diff, (int)m_minDeltaScroll);
|
|
delta = std::max(delta, diff10);
|
|
|
|
// hbar->setValue(hbar->value() + delta);
|
|
setContentsPos(hbar->value() + delta, currentContentYPos);
|
|
|
|
} else if ((diff = int(hpos - (contentsX() +
|
|
visibleWidth() * 0.10))) < 0) {
|
|
// moving off the left
|
|
|
|
int delta = -diff / 6;
|
|
int diff10 = std::min( -diff, (int)m_minDeltaScroll);
|
|
delta = std::max(delta, diff10);
|
|
|
|
// hbar->setValue(hbar->value() - delta);
|
|
setContentsPos(hbar->value() - delta, currentContentYPos);
|
|
|
|
}
|
|
}
|
|
|
|
void RosegardenScrollView::slotScrollVertSmallSteps(int vpos)
|
|
{
|
|
TQScrollBar* vbar = verticalScrollBar();
|
|
|
|
// RG_DEBUG << "RosegardenCanvasView::slotScrollVertSmallSteps: vpos is " << vpos << ", contentsY is " << contentsY() << ", visibleHeight is " << visibleHeight() << endl;
|
|
|
|
// As a special case (or hack), ignore any request made before we've
|
|
// actually been rendered and sized
|
|
if (visibleHeight() <= 1)
|
|
return ;
|
|
|
|
int diff = 0;
|
|
|
|
if (vpos == 0) {
|
|
|
|
// returning to zero
|
|
vbar->setValue(0);
|
|
|
|
} else if ((diff = int(vpos - (contentsY() +
|
|
visibleHeight() * 0.90))) > 0) {
|
|
|
|
// moving off up
|
|
|
|
int delta = diff / 6;
|
|
int diff10 = std::min(diff, (int)m_minDeltaScroll);
|
|
delta = std::max(delta, diff10);
|
|
|
|
vbar->setValue(vbar->value() + diff);
|
|
|
|
} else if ((diff = int(vpos - (contentsY() +
|
|
visibleHeight() * 0.10))) < 0) {
|
|
|
|
// moving off down
|
|
|
|
int delta = -diff / 6;
|
|
int diff10 = std::min( -diff, (int)m_minDeltaScroll);
|
|
delta = std::max(delta, diff10);
|
|
|
|
vbar->setValue(vbar->value() - delta);
|
|
|
|
}
|
|
}
|
|
|
|
void RosegardenScrollView::slotScrollVertToTop(int vpos)
|
|
{
|
|
TQScrollBar* vbar = verticalScrollBar();
|
|
if (vpos < visibleHeight() / 3)
|
|
vbar->setValue(0);
|
|
else
|
|
vbar->setValue(vpos - visibleHeight() / 5);
|
|
}
|
|
|
|
void RosegardenScrollView::slotSetScrollPos(const TQPoint &pos)
|
|
{
|
|
horizontalScrollBar()->setValue(pos.x());
|
|
verticalScrollBar()->setValue(pos.y());
|
|
}
|
|
|
|
void RosegardenScrollView::resizeEvent(TQResizeEvent* e)
|
|
{
|
|
TQScrollView::resizeEvent(e);
|
|
if (!horizontalScrollBar()->isVisible())
|
|
updateBottomWidgetGeometry();
|
|
|
|
}
|
|
|
|
void RosegardenScrollView::setHBarGeometry(TQScrollBar &hbar, int x, int y, int w, int h)
|
|
{
|
|
TQScrollView::setHBarGeometry(hbar, x, y, w, h);
|
|
updateBottomWidgetGeometry();
|
|
}
|
|
|
|
void RosegardenScrollView::updateBottomWidgetGeometry()
|
|
{
|
|
if (!m_bottomWidget)
|
|
return ;
|
|
|
|
int bottomWidgetHeight = m_bottomWidget->sizeHint().height();
|
|
|
|
setMargins(0, 0, 0, bottomWidgetHeight);
|
|
TQRect r = frameRect();
|
|
int hScrollBarHeight = 0;
|
|
if (horizontalScrollBar()->isVisible())
|
|
hScrollBarHeight = horizontalScrollBar()->height() + 2; // + 2 offset needed to preserve border shadow
|
|
|
|
int vScrollBarWidth = 0;
|
|
if (verticalScrollBar()->isVisible())
|
|
vScrollBarWidth = verticalScrollBar()->width();
|
|
|
|
m_bottomWidget->setGeometry(r.x(),
|
|
r.y() + r.height() - bottomWidgetHeight - hScrollBarHeight,
|
|
r.width() - vScrollBarWidth,
|
|
bottomWidgetHeight);
|
|
|
|
if (bottomWidgetHeight != m_currentBottomWidgetHeight) {
|
|
emit bottomWidgetHeightChanged(bottomWidgetHeight);
|
|
m_currentBottomWidgetHeight = bottomWidgetHeight;
|
|
}
|
|
|
|
}
|
|
|
|
void RosegardenScrollView::wheelEvent(TQWheelEvent *e)
|
|
{
|
|
if (e->state() & ControlButton) {
|
|
if (e->delta() > 0)
|
|
emit zoomIn();
|
|
else if (e->delta() < 0)
|
|
emit zoomOut();
|
|
return ;
|
|
}
|
|
TQScrollView::wheelEvent(e);
|
|
}
|
|
|
|
}
|
|
#include "RosegardenScrollView.moc"
|