8 m_defaultDuration = 10;
9 m_startTime = wxDateTime::Today();
10 m_totalDuration = 120;
11 m_totalTime = m_totalDuration;
12 m_visibleDuration = 60;
14 m_minVisibleDuration = 10;
15 m_maxVisibleDuration = m_totalDuration;
16 m_firstVisibleTime = 0;
18 m_minScrollerVisibleDuration = m_minVisibleDuration;
19 int defaultScrollerView = wxMax(m_visibleDuration + 30, m_visibleDuration * 2);
20 defaultScrollerView = wxMin(defaultScrollerView, m_totalDuration);
21 defaultScrollerView = wxMax(defaultScrollerView, m_minScrollerVisibleDuration);
22 m_scrollerVisibleDuration = defaultScrollerView;
23 m_scrollerFirstVisibleTime = 0;
24 AdjustMainViewToScrollerView();
31 m_mouseCaptured =
false;
34 m_isSelecting =
false;
35 m_selectionRect = wxRect();
37 m_ptStartPos = wxDefaultPosition;
38 m_ptEndPos = wxDefaultPosition;
40 m_selectedElement = ET_NONE;
41 m_lastElement = ET_NONE;
45 m_visibleItemBegin = m_items.end();
46 m_visibleItemEnd = m_items.end();
47 m_lastTask = m_items.end();
48 m_activeTask = m_items.end();
49 m_contextMenuItemIndex = -1;
51 m_timerMove.SetOwner(
this, wxID_ANY);
53 m_isDraggingDetachedItem =
false;
54 m_detachedDragItemOriginalIndex = -1;
55 m_showOriginalPositionPlaceholder =
false;
56 m_dragScrollerItemInitialClickTimeOffset = 0;
57 m_pFloatingItemWin =
nullptr;
59 m_dropIndicatorRect = wxRect();
60 m_dropIndicatorRectScroller = wxRect();
143 m_artProvider->DrawTimelineBackground(dc, m_rectTimeline);
145 const int visibleStart = m_firstVisibleTime;
146 const int visibleEnd = m_firstVisibleTime + m_visibleDuration;
148 if (visibleEnd <= visibleStart)
153 m_artProvider->DrawTimelineTrack(dc, m_rectTimelineMain);
155 const int timeBuffer = 1;
156 wxDateTime adjustedStart = m_startTime + wxTimeSpan::Seconds(wxMax(0, visibleStart - timeBuffer));
157 wxDateTime adjustedEnd = m_startTime + wxTimeSpan::Seconds(visibleEnd + timeBuffer);
159 wxRect clipRectTimeScale = m_rectTimelineTimeScale;
160 clipRectTimeScale.Inflate(10, 0);
161 wxDCClipper timeScaleClipper(dc, clipRectTimeScale);
163 m_artProvider->DrawTimeScale(
165 m_rectTimelineTimeScale,
170 wxDCClipper mainTimelineClipper(dc, m_rectTimelineMain);
172 wxString rangeText = FormatTime(visibleStart) +
" - " + FormatTime(visibleEnd);
173 wxString zoomText = wxString::Format(
"Zoom: %s", FormatTime(m_visibleDuration));
175 dc.SetTextForeground(wxColour(80, 80, 80));
176 dc.SetFont(wxFont(wxFontInfo(8).Family(wxFONTFAMILY_DEFAULT).Style(wxFONTSTYLE_NORMAL).Weight(wxFONTWEIGHT_NORMAL)));
177 dc.DrawText(rangeText, m_rectTimelineMain.x + 5, m_rectTimelineMain.y + 5);
178 dc.DrawText(zoomText, m_rectTimelineMain.x + 5, m_rectTimelineMain.y + 20);
180 if (m_visibleItemBegin == m_items.end() && m_visibleItemEnd == m_items.end())
185 for (
size_t index = 0; index < m_items.size(); ++index)
187 auto& item = m_items[index];
191 if (item.Rect.width <= 0) {
196 m_artProvider->DrawItem(dc, item.Rect, m_rectTimelineTrack, item,
false,
false);
198 catch (
const std::exception& ) {
202 if (m_isDraggingDetachedItem)
204 if (!m_dropIndicatorRect.IsEmpty() && m_detachedDragItemOriginalIndex != -1)
206 wxDCClipper clip(dc, m_rectTimelineTrack);
207 TimelineItem<T> previewItem = m_items[m_detachedDragItemOriginalIndex];
210 previewItem.
Colour.Set(0, 255, 0, 128);
214 wxColour c = previewItem.
Colour;
215 previewItem.
Colour.Set(c.Red(), c.Green(), c.Blue(), 128);
217 m_artProvider->DrawItem(dc, m_dropIndicatorRect, m_rectTimelineTrack, previewItem,
false,
false);
222 if (!m_selectionRect.IsEmpty())
224 wxColour selectionColor(0, 120, 215, 80);
225 dc.SetBrush(wxBrush(selectionColor));
226 dc.SetPen(wxPen(wxColour(0, 120, 215), 1));
228 wxRect clippedSelectionRect = m_selectionRect.Intersect(m_rectTimelineTrack);
229 if (!clippedSelectionRect.IsEmpty())
231 dc.DrawRectangle(clippedSelectionRect);
233 if (clippedSelectionRect.width > 20)
235 int selStartTime = m_firstVisibleTime + TimelineCoordToTime(clippedSelectionRect.GetLeft() - m_rectTimelineTrack.x);
236 int selEndTime = m_firstVisibleTime + TimelineCoordToTime(clippedSelectionRect.GetRight() - m_rectTimelineTrack.x);
237 wxString selTimeText = FormatTime(selStartTime) +
" - " + FormatTime(selEndTime);
239 dc.SetTextForeground(wxColour(0, 0, 0));
240 dc.SetFont(wxFont(wxFontInfo(8).Family(wxFONTFAMILY_DEFAULT)));
242 wxSize textSize = dc.GetTextExtent(selTimeText);
243 int textX = clippedSelectionRect.x + (clippedSelectionRect.width - textSize.GetWidth()) / 2;
244 int textY = clippedSelectionRect.y + (clippedSelectionRect.height - textSize.GetHeight()) / 2;
246 if (textY >= clippedSelectionRect.y && (textY + textSize.GetHeight()) <= clippedSelectionRect.GetBottom())
248 dc.DrawText(selTimeText, textX, textY);
258 m_artProvider->DrawScrollerBackground(dc, m_rectScroller);
259 m_artProvider->DrawScrollerTrack(dc, m_rectScrollerMain);
260 m_artProvider->DrawLeftArrow(dc, m_rectLeftArrowDraw, m_stateLeftArrow);
261 m_artProvider->DrawRightArrow(dc, m_rectRightArrowDraw, m_stateRightArrow);
262 m_artProvider->DrawTimeScale(dc, m_rectScrollerTimeScale,
263 m_startTime + wxTimeSpan::Seconds(m_scrollerFirstVisibleTime),
264 m_startTime + wxTimeSpan::Seconds(m_scrollerFirstVisibleTime + m_scrollerVisibleDuration)
266 wxDCClipper clip(dc, m_rectScrollerTrack);
267 for (
size_t i = 0; i < m_items.size(); ++i)
269 if (m_isDraggingDetachedItem && m_showOriginalPositionPlaceholder && (
int)i == m_detachedDragItemOriginalIndex)
274 auto& item = m_items[i];
277 int itemStartTime = item.Data->GetStartTime();
278 int itemEndTime = item.Data->GetEndTime();
279 if (itemEndTime <= m_scrollerFirstVisibleTime || itemStartTime >= m_scrollerFirstVisibleTime + m_scrollerVisibleDuration)
282 int itemX_start_in_track = ScrollerTimeToCoord(itemStartTime);
283 int itemX_end_in_track = ScrollerTimeToCoord(itemEndTime);
285 itemX_start_in_track = wxMax(0, itemX_start_in_track);
286 itemX_end_in_track = wxMin(m_rectScrollerTrack.width, itemX_end_in_track);
288 if (itemX_end_in_track > itemX_start_in_track)
290 wxRect itemRectInScroller = m_rectScrollerTrack;
291 itemRectInScroller.x = m_rectScrollerTrack.x + itemX_start_in_track;
292 itemRectInScroller.width = itemX_end_in_track - itemX_start_in_track;
294 m_artProvider->DrawItem(dc, itemRectInScroller, m_rectScrollerTrack, item,
true,
false);
296 if ((
int)i == m_contextMenuItemIndex)
298 wxPen oldPen = dc.GetPen();
299 wxBrush oldBrush = dc.GetBrush();
301 dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT), 2, wxPENSTYLE_SOLID));
302 dc.SetBrush(*wxTRANSPARENT_BRUSH);
303 wxRect highlightRect = itemRectInScroller;
304 dc.DrawRectangle(highlightRect);
307 dc.SetBrush(oldBrush);
312 if (m_isDraggingDetachedItem)
314 if (!m_dropIndicatorRectScroller.IsEmpty() && m_detachedDragItemOriginalIndex != -1)
317 TimelineItem<T> previewItem = m_items[m_detachedDragItemOriginalIndex];
320 previewItem.
Colour.Set(0, 255, 0, 128);
324 wxColour c = previewItem.
Colour;
325 previewItem.
Colour.Set(c.Red(), c.Green(), c.Blue(), 128);
327 m_artProvider->DrawItem(dc, m_dropIndicatorRectScroller, m_rectScrollerTrack, previewItem,
true,
false);
331 if (m_isDraggingDetachedItem && m_showOriginalPositionPlaceholder && m_originalPositionPlaceholderRectScroller.width > 0)
333 wxColour placeholderFillColour = m_originalPositionPlaceholderColour;
334 placeholderFillColour.Set(placeholderFillColour.Red(), placeholderFillColour.Green(), placeholderFillColour.Blue(), 30);
336 dc.SetPen(wxPen(m_originalPositionPlaceholderColour, 1, wxPENSTYLE_DOT));
337 dc.SetBrush(wxBrush(placeholderFillColour));
338 dc.DrawRectangle(m_originalPositionPlaceholderRectScroller);
341 m_artProvider->DrawVisibleFrame(dc, m_rectVisibleFrame, m_stateVisibleFrame);
356 m_rectBackground = GetClientRect();
359 int scrollerHeight = 60;
363 m_rectTimeline = m_rectBackground;
364 m_rectTimeline.height -= scrollerHeight + gapHeight;
366 m_rectTimelineTimeScale = wxRect(m_rectTimeline.x, m_rectTimeline.GetBottom() - 20, m_rectTimeline.width, 20);
367 m_rectTimelineMain = wxRect(m_rectTimeline.x, m_rectTimeline.y + 5, m_rectTimeline.width, m_rectTimeline.height - 25);
368 m_rectTimelineTrack = m_rectTimelineMain.Deflate(4, 4);
370 m_rectScroller = wxRect(m_rectTimeline.x, m_rectTimeline.GetBottom() + gapHeight, m_rectTimeline.width, scrollerHeight);
371 m_rectScrollerMain = wxRect(m_rectScroller.x + 20, m_rectScroller.y + 5, m_rectScroller.width - 40, scrollerHeight - 25);
372 m_rectScrollerTrack = m_rectScrollerMain.Deflate(4, 4);
374 m_rectLeftArrow = wxRect(m_rectScroller.x, m_rectScroller.y + 10, 20, 40);
375 m_rectRightArrow = wxRect(m_rectScroller.GetRight() - 20, m_rectScroller.y + 10, 20, 40);
377 m_rectLeftArrowDraw = m_rectLeftArrow.Deflate(5);
378 m_rectRightArrowDraw = m_rectRightArrow.Deflate(5);
380 m_rectScrollerTimeScale = wxRect(m_rectScrollerMain.x, m_rectScrollerMain.GetBottom() + 2, m_rectScrollerMain.width, 20);
382 RecalcVisibleFrame();
388 if (m_scrollerVisibleDuration <= 0 || m_rectScrollerTrack.width <= 0)
390 m_rectVisibleFrame = wxRect();
391 m_rectVisibleFrameLeft = wxRect();
392 m_rectVisibleFrameRight = wxRect();
396 int trackX = m_rectScrollerTrack.x;
397 int trackW = m_rectScrollerTrack.width;
399 double mainViewStartRelativeToScroller = 0.0;
400 double mainViewEndRelativeToScroller = 1.0;
402 if (m_scrollerVisibleDuration > 0) {
403 mainViewStartRelativeToScroller = (double)(m_firstVisibleTime - m_scrollerFirstVisibleTime) / m_scrollerVisibleDuration;
404 mainViewEndRelativeToScroller = (double)(m_firstVisibleTime + m_visibleDuration - m_scrollerFirstVisibleTime) / m_scrollerVisibleDuration;
407 mainViewStartRelativeToScroller = wxMax(0.0, mainViewStartRelativeToScroller);
408 mainViewEndRelativeToScroller = wxMin(1.0, mainViewEndRelativeToScroller);
409 if (mainViewEndRelativeToScroller < mainViewStartRelativeToScroller) mainViewEndRelativeToScroller = mainViewStartRelativeToScroller;
411 int x1 = trackX + wxRound(mainViewStartRelativeToScroller * trackW);
412 int x2 = trackX + wxRound(mainViewEndRelativeToScroller * trackW);
414 x1 = wxMax(trackX, x1);
415 x2 = wxMin(trackX + trackW, x2);
416 if (x2 < x1) x2 = x1;
418 m_rectVisibleFrame = wxRect(
419 wxPoint(x1, m_rectScrollerTrack.y - 5),
420 wxPoint(x2, m_rectScrollerTrack.GetBottom() + 5)
424 m_rectVisibleFrameLeft = wxRect(
425 m_rectVisibleFrame.x - gripSize,
426 m_rectVisibleFrame.y,
428 m_rectVisibleFrame.height
430 m_rectVisibleFrameRight = wxRect(
431 m_rectVisibleFrame.GetRight() - gripSize,
432 m_rectVisibleFrame.y,
434 m_rectVisibleFrame.height
442 m_firstVisibleTime, m_visibleDuration, m_rectTimelineTrack.width, m_rectTimelineTrack.y, m_rectTimelineTrack.height;
444 int visibleStart = m_firstVisibleTime;
445 int visibleDuration = m_visibleDuration;
446 int width = m_rectTimelineTrack.width;
448 m_visibleItemBegin = m_items.end();
449 m_visibleItemEnd = m_items.end();
451 for (
auto& item : m_items)
453 item.Rect = wxRect();
454 item.m_displayLane = 0;
462 std::vector<size_t> sorted_indices(m_items.size());
463 std::iota(sorted_indices.begin(), sorted_indices.end(), 0);
465 std::stable_sort(sorted_indices.begin(), sorted_indices.end(),
466 [&](
size_t a_idx,
size_t b_idx) {
467 const auto& item_a_data = m_items[a_idx].Data;
468 const auto& item_b_data = m_items[b_idx].Data;
470 if (!item_a_data && !item_b_data) return false;
471 if (!item_a_data) return false;
472 if (!item_b_data) return true;
474 if (item_a_data->GetStartTime() != item_b_data->GetStartTime()) {
475 return item_a_data->GetStartTime() < item_b_data->GetStartTime();
477 return item_a_data->GetEndTime() < item_b_data->GetEndTime();
480 std::vector<int> lane_end_times;
481 int max_lane_used = -1;
483 for (
size_t item_original_index : sorted_indices)
486 if (!current_item.
Data)
continue;
488 int item_start_time = current_item.
Data->GetStartTime();
489 int item_end_time = current_item.
Data->GetEndTime();
491 if (item_start_time >= item_end_time) {
493 item_original_index, item_start_time, item_end_time;
497 int assigned_lane = -1;
498 for (
size_t lane_idx = 0; lane_idx < lane_end_times.size(); ++lane_idx)
500 if (item_start_time >= lane_end_times[lane_idx])
502 assigned_lane = lane_idx;
503 lane_end_times[lane_idx] = item_end_time;
508 if (assigned_lane == -1)
510 assigned_lane = lane_end_times.size();
511 lane_end_times.push_back(item_end_time);
514 if (assigned_lane > max_lane_used)
516 max_lane_used = assigned_lane;
520 int num_lanes = m_items.empty() ? 1 : (max_lane_used + 1);
521 int lane_height = m_rectTimelineTrack.height;
523 if (num_lanes > 0 && m_rectTimelineTrack.height > 0)
525 lane_height = m_rectTimelineTrack.height / num_lanes;
527 if (lane_height < 1 && m_rectTimelineTrack.height > 0) lane_height = 1;
528 if (m_rectTimelineTrack.height <= 0) lane_height = 0;
530 max_lane_used, num_lanes, lane_height, m_rectTimelineTrack.height;
532 for (
auto it = m_items.begin(); it != m_items.end(); ++it)
534 size_t currentIndex = std::distance(m_items.begin(), it);
539 int itemStart = it->Data->GetStartTime();
540 int itemEnd = it->Data->GetEndTime();
542 bool isVisible = !(itemEnd <= visibleStart || itemStart >= visibleStart + visibleDuration);
546 int relativeStart = itemStart - visibleStart;
547 int relativeEnd = itemEnd - visibleStart;
549 if (relativeStart < 0) relativeStart = 0;
550 if (relativeEnd > visibleDuration) relativeEnd = visibleDuration;
552 if (visibleDuration <= 0 || width <= 0) {
556 int xStart = (relativeStart * width) / visibleDuration;
557 int xEnd = (relativeEnd * width) / visibleDuration;
559 if (xEnd < xStart) xEnd = xStart;
561 int item_rect_y = m_rectTimelineTrack.y + it->m_displayLane * lane_height;
562 int item_rect_height = lane_height;
564 if (lane_height > 0 && it->m_displayLane == num_lanes - 1) {
565 item_rect_height = (m_rectTimelineTrack.y + m_rectTimelineTrack.height) - item_rect_y;
567 if (item_rect_height < 0) item_rect_height = 0;
571 m_rectTimelineTrack.x + xStart,
577 if (rect.height <= 0 && m_rectTimelineTrack.height > 0 && num_lanes > 0) {
582 currentIndex, itemStart, itemEnd, it->m_displayLane,
583 rect.x, rect.y, rect.width, rect.height;
585 if (m_visibleItemBegin == m_items.end())
586 m_visibleItemBegin = it;
587 m_visibleItemEnd = it + 1;
591 currentIndex, itemStart, itemEnd;
600 const wxPoint pos =
event.GetPosition();
603 if (m_isDraggingDetachedItem) {
604 currentHoverType = ET_SCROLLER_ITEM_DRAG;
605 }
else if (!m_mouseCaptured) {
606 currentHoverType = GetElementFromPos(pos);
608 if (m_mouseDown && m_selectedElement != ET_NONE) {
609 currentHoverType = m_selectedElement;
611 currentHoverType = m_lastElement;
615 if (event.Moving() && !m_isDraggingDetachedItem)
617 if (currentHoverType != m_lastElement)
619 OnLeaveElement(m_lastElement);
620 OnEnterElement(currentHoverType);
624 if (event.IsButton())
627 if (event.LeftDown())
629 m_contextMenuItemIndex = -1;
631 if (event.ControlDown())
633 if (currentHoverType == ET_SCROLLER_ITEM_DRAG && m_hoveredScrollerItemIndex != -1 && !m_isDraggingDetachedItem)
636 m_selectedElement = ET_SCROLLER_ITEM_DRAG;
638 m_isDraggingDetachedItem =
true;
639 m_detachedDragItemOriginalIndex = m_hoveredScrollerItemIndex;
640 m_dragPreviewTime = -1;
642 TimelineItem<T>& originalItem = m_items[m_detachedDragItemOriginalIndex];
643 if (!originalItem.
Data) {
644 m_isDraggingDetachedItem =
false;
648 m_showOriginalPositionPlaceholder =
true;
649 m_originalPositionPlaceholderColour = originalItem.
Colour;
651 int itemStartTime = originalItem.
Data->GetStartTime();
652 int itemEndTime = originalItem.
Data->GetEndTime();
653 int x1_track = ScrollerTimeToCoord(itemStartTime);
654 int x2_track = ScrollerTimeToCoord(itemEndTime);
656 wxLogDebug(
"OnMouse LeftDown Ctrl: itemStartTime=%d, itemEndTime=%d, duration=%d", itemStartTime, itemEndTime, itemEndTime - itemStartTime);
657 wxLogDebug(
"OnMouse LeftDown Ctrl: m_scrollerFirstVisibleTime=%d, m_scrollerVisibleDuration=%d, m_rectScrollerTrack.width=%d", m_scrollerFirstVisibleTime, m_scrollerVisibleDuration, m_rectScrollerTrack.width);
658 wxLogDebug(
"OnMouse LeftDown Ctrl: x1_track=%d, x2_track=%d, pixel_width_on_scroller=%d", x1_track, x2_track, x2_track - x1_track);
660 m_originalPositionPlaceholderRectScroller = wxRect(
661 m_rectScrollerTrack.x +
wxClip(x1_track, 0, m_rectScrollerTrack.width),
662 m_rectScrollerTrack.y,
663 wxClip(x2_track, 0, m_rectScrollerTrack.width) -
wxClip(x1_track, 0, m_rectScrollerTrack.width),
664 m_rectScrollerTrack.height
667 if (m_originalPositionPlaceholderRectScroller.width < 0) {
668 m_originalPositionPlaceholderRectScroller.width = 0;
670 wxLogDebug(
"OnMouse LeftDown Ctrl: m_originalPositionPlaceholderRectScroller.width=%d, height=%d", m_originalPositionPlaceholderRectScroller.width, m_originalPositionPlaceholderRectScroller.height);
673 m_detachedDragItemVisual = originalItem;
675 int placeholderWidth = m_originalPositionPlaceholderRectScroller.width;
676 wxLogDebug(
"OnMouse LeftDown Ctrl: placeholderWidth before adjustment = %d", placeholderWidth);
678 if (placeholderWidth <= 0 && (itemEndTime - itemStartTime > 0)) {
679 placeholderWidth = 1;
680 wxLogDebug(
"OnMouse LeftDown Ctrl: placeholderWidth corrected to 1 due to zero/negative pixel width but positive duration");
681 }
else if (placeholderWidth < 0) {
682 placeholderWidth = 0;
683 wxLogDebug(
"OnMouse LeftDown Ctrl: placeholderWidth corrected to 0 due to negative pixel width");
687 int finalPopupWindowWidth = placeholderWidth;
688 if (finalPopupWindowWidth < 30 && placeholderWidth > 0) {
689 finalPopupWindowWidth = 30;
690 wxLogDebug(
"OnMouse LeftDown Ctrl: finalPopupWindowWidth adjusted to 30 (minimum for visible placeholder)");
691 }
else if (finalPopupWindowWidth < 5 && placeholderWidth == 0 && (itemEndTime - itemStartTime > 0)) {
692 finalPopupWindowWidth = 30;
693 wxLogDebug(
"OnMouse LeftDown Ctrl: finalPopupWindowWidth set to 30 (item has duration, placeholder 0)");
694 }
else if (finalPopupWindowWidth == 0 && (itemEndTime - itemStartTime == 0)) {
695 finalPopupWindowWidth = 30;
696 wxLogDebug(
"OnMouse LeftDown Ctrl: finalPopupWindowWidth set to 30 (zero duration item)");
699 wxLogDebug(
"OnMouse LeftDown Ctrl: finalPopupWindowWidth set to placeholderWidth = %d", placeholderWidth);
701 if (finalPopupWindowWidth <=0 ) finalPopupWindowWidth = 30;
703 m_detachedDragItemSize.SetWidth(finalPopupWindowWidth);
704 m_detachedDragItemSize.SetHeight(wxMax(15, m_originalPositionPlaceholderRectScroller.height > 4 ? m_originalPositionPlaceholderRectScroller.height - 2 * m_ScrollerVMargin : 15));
706 wxLogDebug(
"OnMouse LeftDown Ctrl: m_detachedDragItemSize.width=%d, height=%d", m_detachedDragItemSize.GetWidth(), m_detachedDragItemSize.GetHeight());
708 if (m_originalPositionPlaceholderRectScroller.width > 0) {
709 double relativeX =
static_cast<double>(pos.x - m_originalPositionPlaceholderRectScroller.GetLeft()) / m_originalPositionPlaceholderRectScroller.GetWidth();
710 m_cursorToDetachedVisualOffset.x =
static_cast<int>(round(relativeX * m_detachedDragItemSize.GetWidth()));
712 m_cursorToDetachedVisualOffset.x = m_detachedDragItemSize.GetWidth() / 2;
715 if (m_originalPositionPlaceholderRectScroller.height > 0) {
716 double relativeY =
static_cast<double>(pos.y - m_originalPositionPlaceholderRectScroller.GetTop()) / m_originalPositionPlaceholderRectScroller.GetHeight();
717 m_cursorToDetachedVisualOffset.y =
static_cast<int>(round(relativeY * m_detachedDragItemSize.GetHeight()));
719 m_cursorToDetachedVisualOffset.y = m_detachedDragItemSize.GetHeight() / 2;
722 wxPoint screenMousePos = ClientToScreen(pos);
723 m_detachedDragItemScreenPos = screenMousePos - m_cursorToDetachedVisualOffset;
725 int mouseTimeInScroller = ScrollerCoordToTime(pos.x - m_rectScrollerTrack.x);
726 m_dragScrollerItemInitialClickTimeOffset = mouseTimeInScroller - itemStartTime;
728 if (m_pFloatingItemWin) {
729 m_pFloatingItemWin->Destroy();
730 m_pFloatingItemWin =
nullptr;
734 m_detachedDragItemVisual,
735 m_detachedDragItemSize,
737 if (m_pFloatingItemWin) {
738 m_pFloatingItemWin->Move(m_detachedDragItemScreenPos);
739 m_pFloatingItemWin->Show();
744 else if ((
event.ShiftDown() ||
event.AltDown()) && m_rectTimelineTrack.Contains(
pos) && !m_isDraggingDetachedItem)
746 m_isSelecting =
true;
747 m_selectionStart =
pos;
748 m_selectionEnd =
pos;
752 else if (!m_isDraggingDetachedItem)
757 else if (!m_isDraggingDetachedItem)
759 if ((
event.ShiftDown() ||
event.AltDown()) && m_rectTimelineTrack.Contains(
pos))
761 m_isSelecting =
true;
762 m_selectionStart =
pos;
763 m_selectionEnd =
pos;
769 if (!
event.ShiftDown() &&
778 else if (
event.RightDown() && !m_isDraggingDetachedItem)
780 if (
currentHoverType == ET_SCROLLER_ITEM_DRAG && m_hoveredScrollerItemIndex != -1)
782 m_contextMenuItemIndex = m_hoveredScrollerItemIndex;
786 if (!m_selectedItems.empty())
788 m_selectedItems.clear();
795 m_contextMenuItemIndex = -1;
799 if (index < m_items.size())
801 if (!IsItemSelected(index))
803 if (
event.ControlDown()) ToggleItemSelection(index);
804 else SelectItem(index,
true);
806 else if (!
event.ControlDown() && m_selectedItems.size() > 1)
808 SelectItem(index,
true);
813 if (!m_selectedItems.empty())
819 else if (
event.LeftUp())
821 if (m_isDraggingDetachedItem) {
822 OnMouseUp(ET_SCROLLER_ITEM_DRAG,
pos);
824 else if (m_isSelecting)
826 m_isSelecting =
false;
827 if (m_selectionRect.width < 5) ClearSelection();
828 else if (
event.AltDown()) ZoomToSelection();
831 else if (m_selectedElement != ET_NONE)
833 OnMouseUp(m_selectedElement,
pos);
839 if (!m_isDraggingDetachedItem) {
842 OnLeaveElement(m_lastElement);
847 else if (
event.RightUp() && !m_isDraggingDetachedItem)
851 OnLeaveElement(m_lastElement);
855 else if (
event.Dragging())
857 if (m_isDraggingDetachedItem) {
858 OnMouseDrag(ET_SCROLLER_ITEM_DRAG,
pos);
860 else if (m_isSelecting)
862 m_selectionEnd =
pos;
863 int left =
wxMin(m_selectionStart.x, m_selectionEnd.x);
864 int right =
wxMax(m_selectionStart.x, m_selectionEnd.x);
866 right =
wxMin(
right, m_rectTimelineTrack.x + m_rectTimelineTrack.width);
867 m_selectionRect =
wxRect(
left, m_rectTimelineTrack.y,
right -
left, m_rectTimelineTrack.height);
869 else if (m_mouseDown)
871 OnMouseDrag(m_selectedElement,
pos);
875 if (
event.GetWheelRotation() != 0 && !m_isDraggingDetachedItem)
877 if (m_contextMenuItemIndex != -1) {
878 m_contextMenuItemIndex = -1;
881 int deltaSteps =
event.GetWheelRotation() /
event.GetWheelDelta();
884 if (m_rectScroller.Contains(
pos) && m_totalDuration > m_minScrollerVisibleDuration)
892 :
wxMin(15, GetVisibleDuration() / 10));
897 if (
event.Dragging() ||
event.IsButton() ||
event.GetWheelRotation() != 0) {
2147 if (
seconds == m_totalDuration)
2152 m_totalTime = m_totalDuration;
2154 if (m_scrollerVisibleDuration > m_totalDuration || m_scrollerFirstVisibleTime + m_scrollerVisibleDuration > m_totalDuration)
2156 m_scrollerVisibleDuration =
wxMin(m_scrollerVisibleDuration, m_totalDuration);
2157 m_scrollerVisibleDuration =
wxMax(m_minScrollerVisibleDuration, m_scrollerVisibleDuration);
2158 m_scrollerFirstVisibleTime =
wxMin(m_scrollerFirstVisibleTime, m_totalDuration - m_scrollerVisibleDuration);
2159 if (m_scrollerFirstVisibleTime < 0) m_scrollerFirstVisibleTime = 0;
2163 m_scrollerVisibleDuration = m_totalDuration;
2164 m_scrollerFirstVisibleTime = 0;
2167 if (m_maxVisibleDuration > m_totalDuration) {
2168 m_maxVisibleDuration = m_totalDuration;
2170 m_maxVisibleDuration =
wxMax(m_minVisibleDuration, m_maxVisibleDuration);
2180 if (m_firstVisibleTime + m_visibleDuration > m_totalDuration)
2182 m_firstVisibleTime = m_totalDuration - m_visibleDuration;
2184 if (m_firstVisibleTime < 0)
2186 m_firstVisibleTime = 0;
2188 AdjustMainViewToScrollerView();
2190 CalcMaxVisibleDuration();
2191 if (m_visibleDuration > m_maxVisibleDuration) {
2192 m_visibleDuration = m_maxVisibleDuration;
2193 if (m_firstVisibleTime + m_visibleDuration > m_totalDuration) {
2194 m_firstVisibleTime = m_totalDuration - m_visibleDuration;
2196 if (m_firstVisibleTime < 0) m_firstVisibleTime = 0;
2197 AdjustMainViewToScrollerView();
2201 RecalcVisibleFrame();
2209 m_visibleDuration =
wxMax(m_minVisibleDuration, m_visibleDuration);
2210 m_visibleDuration =
wxMin(m_visibleDuration, m_maxVisibleDuration);
2211 m_visibleDuration =
wxMin(m_visibleDuration, m_totalDuration);
2213 m_visibleDuration =
wxMin(m_visibleDuration, m_scrollerVisibleDuration);
2215 m_firstVisibleTime =
wxMax(m_firstVisibleTime, m_scrollerFirstVisibleTime);
2216 if (m_firstVisibleTime + m_visibleDuration > m_scrollerFirstVisibleTime + m_scrollerVisibleDuration) {
2217 m_firstVisibleTime = (m_scrollerFirstVisibleTime + m_scrollerVisibleDuration) - m_visibleDuration;
2220 m_firstVisibleTime =
wxMax(0, m_firstVisibleTime);
2221 if (m_firstVisibleTime + m_visibleDuration > m_totalDuration) {
2222 m_firstVisibleTime = m_totalDuration - m_visibleDuration;
2223 if (m_firstVisibleTime < 0) {
2224 m_firstVisibleTime = 0;
2225 m_visibleDuration =
wxMin(m_visibleDuration, m_totalDuration);
2226 m_visibleDuration =
wxMax(m_visibleDuration, m_minVisibleDuration);
2230 if (m_visibleDuration > m_totalDuration) {
2231 m_visibleDuration = m_totalDuration;
2232 m_visibleDuration =
wxMax(m_visibleDuration, m_minVisibleDuration);
2234 if (m_firstVisibleTime + m_visibleDuration > m_totalDuration) {
2235 m_firstVisibleTime = m_totalDuration - m_visibleDuration;
2236 if (m_firstVisibleTime < 0) m_firstVisibleTime = 0;
2238 if (m_firstVisibleTime < 0) m_firstVisibleTime = 0;