summaryrefslogtreecommitdiffstats
path: root/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.cpp')
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.cpp713
1 files changed, 713 insertions, 0 deletions
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.cpp
new file mode 100644
index 00000000..ead5251d
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.cpp
@@ -0,0 +1,713 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//=============================================================================
+// Prefix
+//=============================================================================
+#include "stdafx.h"
+
+//=============================================================================
+// Includes
+//=============================================================================
+#include "TimelineTimelineLayout.h"
+#include "TimeMeasure.h"
+#include "ScalableScroller.h"
+#include "StudioUtils.h"
+#include "TimelineRow.h"
+#include "TimelineControl.h"
+#include "StateRow.h"
+#include "Snapper.h"
+#include "Bindings/TimelineTranslationManager.h"
+#include "ControlData.h"
+#include "HotKeys.h"
+#include "foundation/Qt3DSLogging.h"
+
+//=============================================================================
+// Defines
+//=============================================================================
+// For Win the modifier key for keyframe multi selection is the control key.
+#define MODIFIER_KEY CHotKeys::MODIFIER_CONTROL
+
+//=============================================================================
+// Class constants
+//=============================================================================
+const double DEFAULT_TIME_RATIO = .05;
+const double CTimelineTimelineLayout::SCALING_PERCENTAGE_INC = 1.1;
+const double CTimelineTimelineLayout::SCALING_PERCENTAGE_DEC = 0.9;
+const double CTimelineTimelineLayout::MAX_ZOOM_OUT = 7e-005;
+
+//=============================================================================
+/**
+ * Constructor
+ */
+CTimelineTimelineLayout::CTimelineTimelineLayout(CTimelineControl *inTimelineControl, IDoc *inDoc)
+ : m_Playhead(this, inDoc)
+ , m_IsLayoutChanged(false)
+ , m_IsMouseDown(false)
+{
+ m_ControlData->SetMouseWheelEnabled(true);
+ m_TimelineControl = inTimelineControl;
+
+ m_TimeRatio = DEFAULT_TIME_RATIO + .01;
+ m_TimeMeasure = new CTimeMeasure(this, m_TimeRatio);
+ m_Scroller = new CScalableScroller();
+
+ m_Scroller->SetVerticalScrollMode(CScroller::ALWAYS);
+ m_Scroller->SetHorizontalScrollMode(CScroller::ALWAYS);
+ m_Scroller->AddScrollListener(this);
+ m_BoundingRect = new CAreaBoundingRect();
+ m_BoundingRect->SetName("TimelineAreaBoundingRect");
+ m_BoundingRect->SetVisible(false);
+ m_BoundingRect->SetAlpha(128);
+
+ AddChild(m_TimeMeasure);
+ AddChild(m_Scroller);
+ AddChild(&m_Playhead);
+ AddChild(m_BoundingRect);
+
+ // Blank control filling in the bottom of the timeline, under the rows
+ CBlankControl *theTimelineBlankControl = new CBlankControl();
+ m_TimebarList = new CFlowLayout(theTimelineBlankControl);
+
+ m_Scroller->AddChild(m_TimebarList);
+ m_Scroller->SetScalingListener(this);
+ m_TimebarList->SetName("TimelineTimelineLayoutList");
+
+ // Initializing flags for keyframe multi select to work.
+ m_CommitKeyframeSelection = false;
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CTimelineTimelineLayout::~CTimelineTimelineLayout()
+{
+ delete m_TimeMeasure;
+ delete m_Scroller;
+ delete m_TimebarList;
+ delete m_BoundingRect;
+}
+
+//=============================================================================
+/**
+ * Clear all the StateRows out of the top-level list.
+ * This is used when the current presentation is being cleared out.
+ */
+void CTimelineTimelineLayout::ClearRows()
+{
+ TTimelineRowList::iterator thePos = m_Rows.begin();
+ for (; thePos != m_Rows.end(); ++thePos) {
+ CTimelineRow *theRow = (*thePos);
+ m_TimebarList->RemoveChild(theRow->GetTimebarControl());
+ }
+
+ m_Rows.clear();
+}
+
+//=============================================================================
+/**
+ * Set the size of this control.
+ * Overrrides CControl::SetSize so that this can redo the layout of all inner
+ * controls.
+ * @param inSize the new size of this control.
+ */
+void CTimelineTimelineLayout::SetSize(CPt inSize)
+{
+ CControl::SetSize(inSize);
+
+ RecalcLayout();
+}
+
+//=============================================================================
+/**
+ * Recalculate the positioning of all the child components.
+ */
+void CTimelineTimelineLayout::RecalcLayout()
+{
+ CPt mySize = GetSize();
+ // Put the time measure on top taking 21 pixels high.
+ m_TimeMeasure->SetSize(CPt(mySize.x, 21));
+ m_TimeMeasure->SetPosition(CPt(0, 0));
+
+ // Make the scroller take up the rest of the space.
+ m_Scroller->SetSize(CPt(mySize.x, mySize.y - 42));
+ m_Scroller->SetPosition(CPt(0, 21));
+
+ // Make it the full length of the view, minus the bottom scroll bar.
+ m_Playhead.SetSize(CPt(13, GetSize().y - m_Scroller->GetHorizontalBar()->GetSize().y - 21));
+
+ long theMinTime = -(m_Playhead.GetCenterOffset());
+
+ if (!m_Rows.empty()) {
+ long theLatestTime = 0;
+ TTimelineRowList::iterator thePos = m_Rows.begin();
+ for (; thePos != m_Rows.end(); ++thePos) {
+ CTimelineRow *theRow = (*thePos);
+ long theRowLatestTime = theRow->GetLatestEndTime();
+ if (theRowLatestTime > theLatestTime)
+ theLatestTime = theRowLatestTime;
+ }
+
+ long theMinWidth = ::TimeToPos(theLatestTime, m_TimeRatio) + END_BUFFER_SIZE;
+ long theMinHeight = m_TimebarList->GetMinimumSize().y;
+
+ CPt theVisSize = m_Scroller->GetVisibleSize();
+
+ if (theMinHeight < theVisSize.y)
+ theMinHeight = theVisSize.y;
+ if (theMinWidth < theVisSize.x)
+ theMinWidth = theVisSize.x;
+
+ m_TimebarList->ResetMinMaxPref();
+ m_TimebarList->SetAbsoluteSize(CPt(theMinWidth, theMinHeight));
+ }
+
+ // Set up the limits.
+ m_Playhead.SetMinMaxPosition(theMinTime, mySize.x - m_Scroller->GetVerticalBar()->GetSize().x);
+
+ // Set playhead to time 0.
+ SetTime(m_TimelineControl->GetTranslationManager()->GetCurrentViewTime(), true);
+
+ // Reset! so that this isn't unnecessarily run
+ m_IsLayoutChanged = false;
+}
+
+//=============================================================================
+/**
+ * Add a timeline row to this object.
+ * This will add the row as a top level object.
+ * @param inRow the row to be added.
+ */
+void CTimelineTimelineLayout::AddRow(CTimelineRow *inRow)
+{
+ m_Rows.push_back(inRow);
+
+ m_TimebarList->AddChild(inRow->GetTimebarControl());
+
+ inRow->SetTimeRatio(m_TimeRatio);
+ // For keyframe/timebar snapping.
+ inRow->SetSnappingListProvider(this);
+}
+
+//=============================================================================
+/**
+ * Call from the ScalableScroller that it is scaling the right side of the timebar.
+ * @param inLength the length that the thumb wants to be.
+ * @param inTotalLength the maximum length that the thumb can be.
+ * @param inOffset the offset of the thumb position.
+ */
+void CTimelineTimelineLayout::OnScalingRight(long inLength, long inTotalLength, long inOffset)
+{
+ double theViewSize = m_Scroller->GetVisibleSize().x;
+ double theClientSize = m_Scroller->GetContaineeSize().x;
+ double theLength = inLength;
+ double theTotalLength = inTotalLength;
+
+ double theTimeRatio =
+ (theViewSize * theTotalLength) / (theClientSize * theLength) * m_TimeRatio;
+
+ // This means the bar was dragged to the far end, just prevent it for getting wacky.
+ if (theTimeRatio > 0) {
+ // This will set the time ratio, but will cap it at 1 or MAX_ZOOM_OUT so if the Time ratio
+ // less than max, don't need to move the timeline
+ SetTimeRatio(theTimeRatio);
+ if (theTimeRatio < 1) {
+ double theMaxVisPos = m_Scroller->GetMaxVisiblePosition().x;
+ long theVisiblePosition = ::dtol(theMaxVisPos * inOffset / (inTotalLength - inLength));
+ m_Scroller->SetVisiblePosition(
+ CPt(theVisiblePosition, m_Scroller->GetVisiblePosition().y));
+ }
+ }
+}
+
+//=============================================================================
+/**
+ * Under construction.
+ */
+void CTimelineTimelineLayout::OnScalingLeft(long inLength, long inTotalLength, long inOffset)
+{
+ // Hey- look at that, doesn't matter which side you're scaling.
+ // Hey, nice comment especially the function header
+ OnScalingRight(inLength, inTotalLength, inOffset);
+}
+
+void CTimelineTimelineLayout::OnScalingReset()
+{
+ SetTimeRatio(DEFAULT_TIME_RATIO);
+}
+
+//=============================================================================
+/**
+ * Set the TimeRatio to be used.
+ * This will propagate the time ratio down to all the child items.
+ * @param inTimeRatio the time ratio to be set.
+ */
+void CTimelineTimelineLayout::SetTimeRatio(double inTimeRatio)
+{
+ if (inTimeRatio != m_TimeRatio) {
+ if (inTimeRatio > 1)
+ inTimeRatio = 1;
+ // if ( inTimeRatio < MAX_ZOOM_OUT )
+ // inTimeRatio = MAX_ZOOM_OUT;
+
+ m_TimeRatio = inTimeRatio;
+ m_TimeMeasure->SetTimeRatio(inTimeRatio);
+
+ TTimelineRowList::iterator thePos = m_Rows.begin();
+ for (; thePos != m_Rows.end(); ++thePos) {
+ CTimelineRow *theRow = (*thePos);
+ theRow->SetTimeRatio(inTimeRatio);
+ }
+
+ RecalcLayout();
+
+ // store the timeline ratio
+ SetTimelineRatio(m_TimelineControl->GetActiveSlide(), m_TimeRatio);
+ qCInfo(qt3ds::TRACE_INFO) << "Set time ratio: " << inTimeRatio;
+ }
+}
+
+//==============================================================================
+/**
+ * When timeline layout has changed. RecalcLayout should be called to adjust the scrollbars if
+ * a asset is expanded/collapsed in the timeline.
+ */
+void CTimelineTimelineLayout::OnTimelineLayoutChanged()
+{
+ RecalcLayout();
+
+ // In addition, this has to be 'marked' for if SetScrollerPositionY is called due to
+ // new assets being added, RecalcLayout has to be called again.
+ m_IsLayoutChanged = true;
+}
+
+/**
+ * Deletes the time zoom ratio for a particular slide.
+ * @param inContext the time context of that slide to delete
+ */
+void CTimelineTimelineLayout::DeleteTimelineRatio(UICDM::CUICDMSlideHandle inSlide)
+{
+ m_TimelineRatio.erase(inSlide);
+}
+
+/**
+ * Clear all entries
+ */
+void CTimelineTimelineLayout::ClearAllTimeRatios()
+{
+ m_TimelineRatio.clear();
+}
+
+/**
+ * Retrieves the time zoom ratio for a particular slide
+ * @param inContext the time context of that slide to retrieve zoom ratio
+ * @return the zoom ratio, or -1 if it's not found
+ */
+double CTimelineTimelineLayout::GetTimelineRatio(UICDM::CUICDMSlideHandle inSlide)
+{
+ TSlideRatioMap::iterator theResult = m_TimelineRatio.find(inSlide);
+ if (theResult != m_TimelineRatio.end())
+ return theResult->second;
+ else
+ return -1;
+}
+
+/**
+ * Sets the time zoom ratio for a particular slide
+ * @param inContext the time context of that slide
+ * @param inRatio the zoom factor
+ */
+void CTimelineTimelineLayout::SetTimelineRatio(UICDM::CUICDMSlideHandle inSlide, double inRatio)
+{
+ m_TimelineRatio[inSlide] = inRatio;
+}
+
+//=============================================================================
+/**
+ * For testing purposes.
+ */
+long CTimelineTimelineLayout::GetMaximumTimebarTime()
+{
+ return 30000;
+}
+
+//=============================================================================
+/**
+ * Call from the TimelineView to notifiy this that some of its objects got filtered.
+ * This was used for redoing the layout but is no longer necessary.
+ */
+void CTimelineTimelineLayout::Filter()
+{
+}
+
+//=============================================================================
+/**
+ * Notification from the CScroller that it is scrolling.
+ * This will update the other views with the verticall scrolling and update
+ * the TimeMeasure with the horizontal scroll amount.
+ * @param inScrollAmount the amount that was scrolled by.
+ */
+void CTimelineTimelineLayout::OnScroll(CScroller *inSource, CPt inScrollAmount)
+{
+ Q_UNUSED(inSource);
+
+ m_TimelineControl->SetScrollPositionY(m_Scroller, m_Scroller->GetVisiblePosition().y);
+
+ long theTimeOffset = GetViewTimeOffset();
+ m_TimeMeasure->SetTimeOffset(theTimeOffset);
+
+ long thePlayheadPos =
+ ::TimeToPos(m_TimelineControl->GetTranslationManager()->GetCurrentViewTime()
+ - theTimeOffset,
+ m_TimeRatio)
+ - m_Playhead.GetCenterOffset();
+
+ m_Playhead.SetPosition(CPt(thePlayheadPos, 0));
+
+ m_DragBeginPoint += inScrollAmount;
+}
+
+void CTimelineTimelineLayout::SetScrollPositionY(CScroller *inSource, long inPositionY,
+ bool inAbsolute)
+{
+ Q_UNUSED(inSource);
+
+ CPt theVisPos = m_Scroller->GetVisiblePosition();
+
+ if (!inAbsolute) {
+ CPt theMaxSize = m_Scroller->GetMaxVisiblePosition();
+
+ CRct theVisibleRect(CPt(theVisPos.x, theMaxSize.y - theVisPos.y),
+ m_Scroller->GetVisibleSize());
+ CPt thePoint(theVisPos.x, inPositionY);
+ if (!theVisibleRect.IsInRect(thePoint))
+ m_Scroller->SetVisiblePosition(CPt(theVisPos.x, inPositionY));
+ } else {
+ // For new assets added, RecalcLayout needs be called here if there was a layout changed
+ // because
+ // m_TimebarList->GetMinimumSize( ).y is only updated at this point, otherwise the tree and
+ // layout will
+ // go out of sync.
+ if (m_IsLayoutChanged)
+ RecalcLayout();
+
+ m_Scroller->SetVisiblePosition(CPt(theVisPos.x, inPositionY));
+ }
+}
+
+//=============================================================================
+/**
+ * Get the scroller control this is using.
+ * Meant for testing purposes.
+ * @return the scroller this is using.
+ */
+CScalableScroller *CTimelineTimelineLayout::GetScroller()
+{
+ return m_Scroller;
+}
+
+//=============================================================================
+/**
+ * Get the playhead control this is using.
+ * Meant for testing purposes.
+ * @return the playhead this is using.
+ */
+CPlayhead *CTimelineTimelineLayout::GetPlayhead()
+{
+ return &m_Playhead;
+}
+
+//=============================================================================
+/**
+ * Scroll the contents of the timeline horizontally.
+ * This is used mainly by the playhead to scroll the view when it gets to the
+ * edge.
+ * @param inAmount the amount to scroll the view by.
+ * @return the amount actually scrolled, limited by min/max values.
+ */
+long CTimelineTimelineLayout::ScrollLayout(long inAmount)
+{
+ // Log the current position for returning
+ CPt thePosition = m_Scroller->GetVisiblePosition();
+
+ m_Scroller->SetVisiblePosition(CPt(thePosition.x + inAmount, thePosition.y));
+
+ // Return how much was actually scrolled, let the scroller handle min/max scroll amounts.
+ return m_Scroller->GetVisiblePosition().x - thePosition.x;
+}
+
+//=============================================================================
+/**
+ * Recalculate what the time is based on the location of the playhead.
+ * This will call SetTime on the TimelineView with the new time.
+ * @param inUpdateClient true if the client time should be updated.
+ */
+void CTimelineTimelineLayout::RecalcTime(bool inUpdateClient, long inFlags)
+{
+ long theOffset = m_Playhead.GetPosition().x + m_Playhead.GetCenterOffset()
+ + m_Scroller->GetVisiblePosition().x;
+
+ long theTime = ::PosToTime(theOffset, m_TimeRatio);
+ m_Snapper.InterpretTimeEx(theTime, inFlags);
+
+ // Update the time
+ m_Playhead.UpdateTime(theTime, inUpdateClient);
+}
+
+//=============================================================================
+/**
+ * Call from the timeline view that the time is changing.
+ * @param inNewTime the new time.
+ * @param inIsSecondary lame flag to prevent infinite recursion.
+ */
+void CTimelineTimelineLayout::SetTime(long inNewTime, bool inIsSecondary)
+{
+ long theOffset = ::TimeToPos(inNewTime, m_TimeRatio);
+ theOffset -= m_Scroller->GetVisiblePosition().x + m_Playhead.GetCenterOffset();
+
+ long theViewSize = m_Scroller->GetVisibleSize().x;
+
+ if (!inIsSecondary) {
+ if (theOffset < -m_Playhead.GetCenterOffset()) {
+ long thePos = ::TimeToPos(inNewTime, m_TimeRatio) - m_Playhead.GetCenterOffset();
+ m_Scroller->SetVisiblePosition(CPt(thePos, m_Scroller->GetVisiblePosition().y));
+ } else if (theOffset > (theViewSize - (m_Playhead.GetCenterOffset() + 20))) {
+ long thePos = ::TimeToPos(inNewTime, m_TimeRatio) + 20;
+ thePos -= theViewSize;
+ m_Scroller->SetVisiblePosition(CPt(thePos, m_Scroller->GetVisiblePosition().y));
+ }
+ SetTime(inNewTime, true);
+ } else {
+ m_Playhead.SetPosition(CPt(theOffset, m_Playhead.GetPosition().y));
+ }
+}
+
+//=============================================================================
+/**
+ * Notification that the TimeMeasure was clicked on.
+ * This is used to reposition the playhead wherever the mouse was clicked.
+ * @param inPoint the location of the mouse local to the time measure.
+ */
+void CTimelineTimelineLayout::OnTimeMeasureMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ Q_UNUSED(inFlags);
+
+ m_Snapper.Clear();
+ m_Snapper.SetSource(&m_Playhead);
+ PopulateSnappingList(&m_Snapper);
+ m_Snapper.SetSnappingKeyframes(true);
+
+ m_Playhead.SetPosition(
+ CPt(inPoint.x - m_Playhead.GetCenterOffset(), m_Playhead.GetPosition().y));
+ RecalcTime(true, inFlags);
+}
+
+//=============================================================================
+/**
+ * Handles left-clicks. Starts a drag operation if a child does not handle the
+ * message.
+ * @param inPoint location of the mouse when event occurred
+ * @param inFlags state of modifier keys when event occurred
+ */
+bool CTimelineTimelineLayout::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseDown(inPoint, inFlags)) {
+ m_BoundingRect->SetSize(CPt(0, 0));
+ m_BoundingRect->SetVisible(true);
+
+ // Do not deselect all keyframes as the user intends to select more keyframes,
+ // when the modifier key is pressed.
+ if (!(inFlags & MODIFIER_KEY))
+ m_TimelineControl->GetTranslationManager()->ClearKeyframeSelection();
+
+ m_IsMouseDown = true;
+ m_DragBeginPoint = inPoint;
+ }
+ return true;
+}
+
+void CTimelineTimelineLayout::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseMove(inPoint, inFlags);
+
+ if (m_IsMouseDown) {
+ CPt theSize;
+ CRct theRect;
+
+ // Tests if the user has pressed the modifier key, while moving the mouse.
+ bool theModifierKeyDown;
+ if (inFlags & MODIFIER_KEY)
+ theModifierKeyDown = true;
+ else
+ theModifierKeyDown = false;
+
+ // Calculate the rect for the bounding box
+ theSize = CPt(inPoint.x - m_DragBeginPoint.x, inPoint.y - m_DragBeginPoint.y);
+ theRect = CRct(m_DragBeginPoint, theSize);
+ theRect.Normalize();
+ m_BoundingRect->SetPosition(theRect.position);
+ m_BoundingRect->SetSize(theRect.size);
+ theRect.Offset(-m_Scroller->GetPosition());
+ theRect.Offset(m_Scroller->GetVisiblePosition());
+
+ // Select all keys inside the rect
+
+ TTimelineRowList::iterator thePos = m_Rows.begin();
+
+ for (; thePos != m_Rows.end(); ++thePos) {
+ CStateRow *theRow = reinterpret_cast<CStateRow *>(*thePos);
+ theRow->SelectKeysInRect(theRect, theModifierKeyDown, m_CommitKeyframeSelection);
+ }
+ m_CommitKeyframeSelection = false;
+ }
+}
+
+void CTimelineTimelineLayout::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ // try to prevent stuck mousetips on exceptions
+ try {
+ CControl::OnMouseUp(inPoint, inFlags);
+ m_BoundingRect->SetVisible(false);
+ } catch (...) {
+ }
+
+ m_IsMouseDown = false;
+
+ // Commits the key frame selection. This finalises the keyframes selection
+ // in the rect. When the mouse is down again, we would be able to append
+ // the commited keyframes with the new batch of keyframes.
+ m_CommitKeyframeSelection = true;
+}
+
+void CTimelineTimelineLayout::PopulateSnappingList(CSnapper *inSnappingList)
+{
+ CRct theArea(m_Scroller->GetVisibleSize());
+ theArea.Offset(-m_Scroller->GetPosition());
+ theArea.Offset(m_Scroller->GetVisiblePosition());
+
+ inSnappingList->SetVisibleArea(theArea.position.y, theArea.size.y);
+
+ inSnappingList->SetTimeRatio(m_TimeRatio);
+ if (inSnappingList->GetSource() != &m_Playhead)
+ inSnappingList->AddTime(m_Playhead.GetCurrentTime());
+
+ m_TimeMeasure->PopulateSnappingList(inSnappingList);
+
+ TTimelineRowList::iterator theRowIter = m_Rows.begin();
+ for (; theRowIter != m_Rows.end(); ++theRowIter) {
+ (*theRowIter)->PopulateSnappingList(inSnappingList);
+ }
+}
+
+long CTimelineTimelineLayout::GetViewTimeOffset()
+{
+ return ::dtol(m_Scroller->GetVisiblePosition().x / m_TimeRatio);
+}
+
+CTimeMeasure *CTimelineTimelineLayout::GetTimeMeasure()
+{
+ return m_TimeMeasure;
+}
+
+//=============================================================================
+/**
+ * Register all the events for hotkeys that are active for the entire application.
+ * Hotkeys for the entire application are ones that are not view specific in
+ * scope.
+ * @param inShortcutHandler the global shortcut handler.
+ */
+void CTimelineTimelineLayout::RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler)
+{
+ inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer<CTimelineTimelineLayout>(
+ this, &CTimelineTimelineLayout::OnScalingZoomIn),
+ 0, Qt::Key_Plus);
+ inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer<CTimelineTimelineLayout>(
+ this, &CTimelineTimelineLayout::OnScalingZoomOut),
+ 0, Qt::Key_Minus);
+ inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer<CTimelineTimelineLayout>(
+ this, &CTimelineTimelineLayout::OnScalingZoomIn),
+ Qt::KeypadModifier, Qt::Key_Plus);
+ inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer<CTimelineTimelineLayout>(
+ this, &CTimelineTimelineLayout::OnScalingZoomOut),
+ Qt::KeypadModifier, Qt::Key_Minus);
+}
+
+//=============================================================================
+/**
+ * Call from the Hotkey that it is zooming in the timebar.
+ */
+
+void CTimelineTimelineLayout::OnScalingZoomIn()
+{
+ double theTimeRatio = m_TimeRatio * SCALING_PERCENTAGE_INC;
+
+ SetTimeRatio(theTimeRatio);
+ CenterToPlayhead();
+}
+
+//=============================================================================
+/**
+ * Call from the Hotkey that it is zooming out of the timebar.
+ */
+
+void CTimelineTimelineLayout::OnScalingZoomOut()
+{
+ double theTimeRatio = m_TimeRatio * SCALING_PERCENTAGE_DEC;
+
+ SetTimeRatio(theTimeRatio);
+ CenterToPlayhead();
+}
+
+void CTimelineTimelineLayout::CenterToPlayhead()
+{
+ long theTime = m_Playhead.GetCurrentTime();
+ long thePos = ::TimeToPos(theTime, m_TimeRatio);
+ long theNewPosX = thePos - (m_Scroller->GetSize().x / 2);
+
+ m_Scroller->SetVisiblePosition(CPt(theNewPosX, m_Scroller->GetVisiblePosition().y));
+}
+
+//==============================================================================
+/**
+ * Handle mouse wheel messages to allow zooming
+ */
+bool CTimelineTimelineLayout::OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags)
+{
+ bool theRetVal = false;
+ if (inFlags & CHotKeys::MODIFIER_CONTROL) {
+ if (inAmount > 0)
+ OnScalingZoomIn();
+ else
+ OnScalingZoomOut();
+ theRetVal = true;
+ } else
+ theRetVal = CControl::OnMouseWheel(inPoint, inAmount, inFlags);
+ return theRetVal;
+}