// Copyright (c) 2006, Rodrigo Braz Monteiro // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of the Aegisub Group nor the names of its contributors // may be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // Aegisub Project http://www.aegisub.org/ // // $Id$ /// @file base_grid.cpp /// @brief Base for subtitle grid in main UI /// @ingroup main_ui /// //////////// // Includes #include "config.h" #ifndef AGI_PRE #include #include #endif #include "ass_dialogue.h" #include "ass_file.h" #include "ass_style.h" #include "audio_display.h" #include "base_grid.h" #include "compat.h" #include "frame_main.h" #include "main.h" #include "options.h" #include "subs_edit_box.h" #include "utils.h" #include "vfr.h" #include "video_box.h" #include "video_context.h" #include "video_slider.h" /// @brief Constructor /// @param parent /// @param id /// @param pos /// @param size /// @param style /// @param name /// BaseGrid::BaseGrid(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name) : wxWindow(parent, id, pos, size, style, name) { // Misc variables lastRow = -1; yPos = 0; extendRow = -1; bmp = NULL; holding = false; byFrame = false; lineHeight = 1; // non-zero to avoid div by 0 // Set scrollbar scrollBar = new wxScrollBar(this,GRID_SCROLLBAR,wxDefaultPosition,wxDefaultSize,wxSB_VERTICAL); scrollBar->SetScrollbar(0,10,100,10); wxBoxSizer *scrollbarpositioner = new wxBoxSizer(wxHORIZONTAL); scrollbarpositioner->AddStretchSpacer(); scrollbarpositioner->Add(scrollBar, 0, wxEXPAND, 0); SetSizerAndFit(scrollbarpositioner); // Set style UpdateStyle(); } /// @brief Destructor /// BaseGrid::~BaseGrid() { delete bmp; } /// @brief Update style /// void BaseGrid::UpdateStyle() { // Set font wxString fontname = lagi_wxString(OPT_GET("Subtitle/Grid/Font Face")->GetString()); if (fontname.IsEmpty()) fontname = _T("Tahoma"); font.SetFaceName(fontname); font.SetPointSize(OPT_GET("Subtitle/Grid/Font Size")->GetInt()); font.SetWeight(wxFONTWEIGHT_NORMAL); // Set line height { wxClientDC dc(this); dc.SetFont(font); int fw,fh; dc.GetTextExtent(_T("#TWFfgGhH"), &fw, &fh, NULL, NULL, &font); lineHeight = fh+4; } // Set column widths std::vector column_array; OPT_GET("Subtitle/Grid/Column")->GetListBool(column_array); assert(column_array.size() == columns); for (int i=0;i maxVis) { if (center) { ScrollTo(row - h/lineHeight/2 + 1); } else { if (row < minVis) ScrollTo(row - 1); if (row > maxVis) ScrollTo(row - h/lineHeight + 3); } } } /// @brief Select a row /// @param row /// @param addToSelected /// @param select /// void BaseGrid::SelectRow(int row, bool addToSelected, bool select) { if (row < 0 || (size_t)row >= selMap.size()) return; if (!addToSelected) { // Sends change notifications for itself ClearSelection(); } if (select != !!selMap[row]) { selMap[row] = select; if (!addToSelected) { Refresh(false); } else { int w = 0; int h = 0; GetClientSize(&w,&h); RefreshRect(wxRect(0,(row+1-yPos)*lineHeight,w,lineHeight),false); } Selection lines_added; Selection lines_removed; if (select) lines_added.insert(diagPtrMap[row]); else lines_removed.insert(diagPtrMap[row]); AnnounceSelectedSetChanged(lines_added, lines_removed); } } /// @brief Selects visible lines /// void BaseGrid::SelectVisible() { Selection lines_removed; GetSelectedSet(lines_removed); int rows = GetRows(); bool selectedOne = false; for (int i=0;i= selMap.size() || row < 0) return false; return !!selMap[row]; } /// @brief Number of selected rows /// @return /// int BaseGrid::GetNumberSelection() const { return std::count(selMap.begin(), selMap.end(), 1); } /// @brief Gets first selected row /// @return /// int BaseGrid::GetFirstSelRow() const { std::vector::const_iterator first = std::find(selMap.begin(), selMap.end(), 1); if (first == selMap.end()) return -1; return std::distance(selMap.begin(), first); } /// @brief Gets last selected row from first block selection /// @return /// int BaseGrid::GetLastSelRow() const { int frow = GetFirstSelRow(); while (IsInSelection(frow)) { frow++; } return frow-1; } /// @brief Gets all selected rows /// @param[out] cont Is the selection contiguous, i.e. free from holes /// @return Array with indices of selected lines /// wxArrayInt BaseGrid::GetSelection(bool *cont) const { // Prepare int nrows = GetRows(); int last = -1; bool continuous = true; wxArrayInt selections; // Scan for (int i=0;iGetSize().GetWidth(); // Prepare bitmap if (bmp) { if (bmp->GetWidth() < w || bmp->GetHeight() < h) { delete bmp; bmp = NULL; } } if (!bmp) bmp = new wxBitmap(w,h); // Draw bitmap wxMemoryDC bmpDC; bmpDC.SelectObject(*bmp); DrawImage(bmpDC); dc.Blit(0,0,w,h,&bmpDC,0,0); } } /// @brief Draw image /// @param dc /// void BaseGrid::DrawImage(wxDC &dc) { // Get size and pos int w = 0; int h = 0; GetClientSize(&w,&h); w -= scrollBar->GetSize().GetWidth(); // Set font dc.SetFont(font); // Clear background dc.SetBackground(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Background")->GetColour()))); dc.Clear(); // Draw labels dc.SetPen(*wxTRANSPARENT_PEN); dc.SetBrush(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Left Column")->GetColour()))); dc.DrawRectangle(0,lineHeight,colWidth[0],h-lineHeight); // Visible lines int drawPerScreen = h/lineHeight + 1; int nDraw = MID(0,drawPerScreen,GetRows()-yPos); int maxH = (nDraw+1) * lineHeight; // Row colors std::vector rowColors; std::vector foreColors; rowColors.push_back(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Background")->GetColour()))); // 0 = Standard foreColors.push_back(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Standard")->GetColour())); rowColors.push_back(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Header")->GetColour()))); // 1 = Header foreColors.push_back(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Standard")->GetColour())); rowColors.push_back(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Selection")->GetColour()))); // 2 = Selected foreColors.push_back(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Selection")->GetColour())); rowColors.push_back(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Comment")->GetColour()))); // 3 = Commented foreColors.push_back(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Selection")->GetColour())); rowColors.push_back(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Inframe")->GetColour()))); // 4 = Video Highlighted foreColors.push_back(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Selection")->GetColour())); rowColors.push_back(wxBrush(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Background/Selected Comment")->GetColour()))); // 5 = Commented & selected foreColors.push_back(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Selection")->GetColour())); // First grid row bool drawGrid = true; if (drawGrid) { dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Lines")->GetColour()))); dc.DrawLine(0,0,w,0); dc.SetPen(*wxTRANSPARENT_PEN); } // Draw rows int dx = 0; int dy = 0; int curColor = 0; AssDialogue *curDiag; for (int i=0;i=0) ? GetDialogue(curRow) : NULL; dx = 0; dy = i*lineHeight; // Check for collisions bool collides = false; if (curDiag) { AssDialogue *sel = GetDialogue(editBox->linen); if (sel && sel != curDiag) { if (curDiag->CollidesWith(sel)) collides = true; } } // Text array wxArrayString strings; // Header if (i == 0) { strings.Add(_("#")); strings.Add(_("L")); strings.Add(_("Start")); strings.Add(_("End")); strings.Add(_("Style")); strings.Add(_("Actor")); strings.Add(_("Effect")); strings.Add(_("Left")); strings.Add(_("Right")); strings.Add(_("Vert")); strings.Add(_("Text")); curColor = 1; } // Lines else if (curDiag) { // Set fields strings.Add(wxString::Format(_T("%i"),curRow+1)); strings.Add(wxString::Format(_T("%i"),curDiag->Layer)); if (byFrame) { strings.Add(wxString::Format(_T("%i"),VFR_Output.GetFrameAtTime(curDiag->Start.GetMS(),true))); strings.Add(wxString::Format(_T("%i"),VFR_Output.GetFrameAtTime(curDiag->End.GetMS(),false))); } else { strings.Add(curDiag->Start.GetASSFormated()); strings.Add(curDiag->End.GetASSFormated()); } strings.Add(curDiag->Style); strings.Add(curDiag->Actor); strings.Add(curDiag->Effect); strings.Add(curDiag->GetMarginString(0)); strings.Add(curDiag->GetMarginString(1)); strings.Add(curDiag->GetMarginString(2)); // Set text int mode = OPT_GET("Subtitle/Grid/Hide Overrides")->GetInt(); wxString value = _T(""); // Hidden overrides if (mode == 1 || mode == 2) { wxString replaceWith = lagi_wxString(OPT_GET("Subtitle/Grid/Hide Overrides Char")->GetString()); int textlen = curDiag->Text.Length(); int depth = 0; wxChar curChar; for (int j=0;jText[j]; if (curChar == _T('{')) depth = 1; else if (curChar == _T('}')) { depth--; if (depth == 0 && mode == 1) value += replaceWith; else if (depth < 0) depth = 0; } else if (depth != 1) value += curChar; } } // Show overrides else value = curDiag->Text; // Cap length and set text if (value.Length() > 512) value = value.Left(512) + _T("..."); strings.Add(value); // Set color curColor = 0; bool inSel = IsInSelection(curRow,0); if (inSel && curDiag->Comment) curColor = 5; else if (inSel) curColor = 2; else if (curDiag->Comment) curColor = 3; else if (OPT_GET("Subtitle/Grid/Highlight Subtitles in Frame")->GetBool() && IsDisplayed(curDiag)) curColor = 4; } else { for (int j=0;j<11;j++) strings.Add(_T("?")); } // Draw row background color if (curColor) { dc.SetBrush(rowColors[curColor]); dc.DrawRectangle((curColor == 1) ? 0 : colWidth[0],i*lineHeight+1,w,lineHeight); } // Set text color if (collides) dc.SetTextForeground(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Collision")->GetColour())); else { dc.SetTextForeground(foreColors[curColor]); } // Draw text wxRect cur; bool isCenter; for (int j=0;j<11;j++) { // Check width if (colWidth[j] == 0) continue; // Is center? isCenter = !(j == 4 || j == 5 || j == 6 || j == 10); // Calculate clipping cur = wxRect(dx+4,dy,colWidth[j]-6,lineHeight); // Set clipping dc.DestroyClippingRegion(); dc.SetClippingRegion(cur); // Draw dc.DrawLabel(strings[j],cur,isCenter ? wxALIGN_CENTER : (wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT)); dx += colWidth[j]; } //if (collides) dc.SetPen(wxPen(wxColour(255,0,0))); // Draw grid dc.DestroyClippingRegion(); if (drawGrid) { dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Lines")->GetColour()))); dc.DrawLine(0,dy+lineHeight,w,dy+lineHeight); dc.SetPen(*wxTRANSPARENT_PEN); } } // Draw grid columns dx = 0; if (drawGrid) { dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Lines")->GetColour()))); for (int i=0;i<10;i++) { dx += colWidth[i]; dc.DrawLine(dx,0,dx,maxH); } dc.DrawLine(0,0,0,maxH); dc.DrawLine(w-1,0,w-1,maxH); } // Draw currently active line border dc.SetPen(wxPen(lagi_wxColour(OPT_GET("Colour/Subtitle Grid/Active Border")->GetColour()))); dc.SetBrush(*wxTRANSPARENT_BRUSH); dy = (editBox->linen+1-yPos) * lineHeight; dc.DrawRectangle(0,dy,w,lineHeight+1); } /// @brief On size /// @param event /// void BaseGrid::OnSize(wxSizeEvent &event) { AdjustScrollbar(); SetColumnWidths(); Refresh(false); } /// @brief On scroll /// @param event /// void BaseGrid::OnScroll(wxScrollEvent &event) { int newPos = event.GetPosition(); if (yPos != newPos) { yPos = newPos; Refresh(false); } } /// @brief Mouse events /// @param event /// @return /// void BaseGrid::OnMouseEvent(wxMouseEvent &event) { // Window size int w,h; GetClientSize(&w,&h); // Modifiers bool shift = event.m_shiftDown; bool alt = event.m_altDown; #ifdef __APPLE__ bool ctrl = event.m_metaDown; #else bool ctrl = event.m_controlDown; #endif // Row that mouse is over bool click = event.ButtonDown(wxMOUSE_BTN_LEFT); bool dclick = event.LeftDClick(); int row = event.GetY()/lineHeight + yPos - 1; bool headerClick = row < yPos; if (holding && !click) { row = MID(0,row,GetRows()-1); } bool validRow = row >= 0 && row < GetRows(); if (!validRow) row = -1; // Get focus if (event.ButtonDown()) { if (OPT_GET("Subtitle/Grid/Focus Allow")->GetBool()) { SetFocus(); } } // Click type bool startedHolding = false; if (click && !holding && validRow) { holding = true; startedHolding = true; CaptureMouse(); } if (!event.ButtonIsDown(wxMOUSE_BTN_LEFT) && holding) { holding = false; ReleaseMouse(); } // Scroll to keep visible if (holding) { // Find direction int minVis = yPos+1; int maxVis = yPos+h/lineHeight-3; int delta = 0; if (row < minVis) delta = -1; if (row > maxVis) delta = +1; // Scroll if (delta) { ScrollTo(yPos+delta*3); if (startedHolding) { holding = false; ReleaseMouse(); } } } // Click if ((click || holding || dclick) && validRow) { // Disable extending extendRow = -1; // Toggle selected if (click && ctrl && !shift && !alt) { SelectRow(row,true,!IsInSelection(row,0)); parentFrame->UpdateToolbar(); return; } // Normal click if ((click || dclick) && !shift && !ctrl && !alt) { editBox->SetToLine(row); if (dclick) VideoContext::Get()->JumpToTime(GetDialogue(row)->Start.GetMS()); SelectRow(row,false); parentFrame->UpdateToolbar(); lastRow = row; return; } // Keep selection if (click && !shift && !ctrl && alt) { editBox->SetToLine(row); return; } // Block select if ((click && shift && !ctrl && !alt) || (holding && !ctrl && !alt && !shift)) { if (lastRow != -1) { // Set boundaries int i1 = row; int i2 = lastRow; if (i1 > i2) { int aux = i1; i1 = i2; i2 = aux; } // Toggle each bool notFirst = false; for (int i=i1;i<=i2;i++) { SelectRow(i,notFirst,true); notFirst = true; } parentFrame->UpdateToolbar(); } return; } return; } // Popup if (event.ButtonDown(wxMOUSE_BTN_RIGHT)) { OnPopupMenu(headerClick); } // Mouse wheel if (event.GetWheelRotation() != 0) { int step = 3 * event.GetWheelRotation() / event.GetWheelDelta(); ScrollTo(yPos - step); return; } event.Skip(); } /// @brief Scroll to /// @param y /// void BaseGrid::ScrollTo(int y) { int w,h; GetClientSize(&w,&h); int nextY = MID(0,y,GetRows()+2 - h/lineHeight); if (yPos != nextY) { yPos = nextY; if (scrollBar->IsEnabled()) scrollBar->SetThumbPosition(yPos); Refresh(false); } } /// @brief Adjust scrollbar /// void BaseGrid::AdjustScrollbar() { // Variables int w,h,sw,sh; GetClientSize(&w,&h); int drawPerScreen = h/lineHeight; int rows = GetRows(); bool barToEnable = drawPerScreen < rows+2; bool barEnabled = scrollBar->IsEnabled(); // Set yPos yPos = MID(0,yPos,rows - drawPerScreen); // Set size scrollBar->Freeze(); scrollBar->GetSize(&sw,&sh); scrollBar->SetSize(w-sw,0,sw,h); // Set parameters if (barEnabled) { scrollBar->SetScrollbar(yPos,drawPerScreen,rows+2,drawPerScreen-2,true); } if (barToEnable != barEnabled) scrollBar->Enable(barToEnable); scrollBar->Thaw(); } /// @brief Set column widths /// @return /// void BaseGrid::SetColumnWidths() { if (!IsShownOnScreen()) return; // Width/height int w = 0; int h = 0; GetClientSize(&w,&h); // DC for text extents test wxClientDC dc(this); dc.SetFont(font); int fw,fh; //dc.GetTextExtent(_T("#TWFfgGhH"), &fw, &fh, NULL, NULL, &font); // O(1) widths dc.GetTextExtent(_T("0000"), &fw, &fh, NULL, NULL, &font); int marginLen = fw + 10; dc.GetTextExtent(wxString::Format(_T("%i"),GetRows()), &fw, &fh, NULL, NULL, &font); int labelLen = fw + 10; int startLen = 0; int endLen = 0; if (!byFrame) { AssTime time; dc.GetTextExtent(time.GetASSFormated(), &fw, &fh, NULL, NULL, &font); startLen = fw + 10; endLen = fw + 10; } // O(n) widths bool showMargin[3]; showMargin[0] = showMargin[1] = showMargin[2] = false; bool showLayer = false; int styleLen = 0; int actorLen = 0; int effectLen = 0; int maxLayer = 0; int maxStart = 0; int maxEnd = 0; AssDialogue *curDiag; for (int i=0;iLayer > maxLayer) { maxLayer = curDiag->Layer; showLayer = true; } // Actor if (!curDiag->Actor.IsEmpty()) { dc.GetTextExtent(curDiag->Actor, &fw, &fh, NULL, NULL, &font); if (fw > actorLen) actorLen = fw; } // Style if (!curDiag->Style.IsEmpty()) { dc.GetTextExtent(curDiag->Style, &fw, &fh, NULL, NULL, &font); if (fw > styleLen) styleLen = fw; } // Effect if (!curDiag->Effect.IsEmpty()) { dc.GetTextExtent(curDiag->Effect, &fw, &fh, NULL, NULL, &font); if (fw > effectLen) effectLen = fw; } // Margins for (int j=0;j<3;j++) { if (curDiag->Margin[j] != 0) showMargin[j] = true; } // Times if (byFrame) { int tmp = VFR_Output.GetFrameAtTime(curDiag->Start.GetMS(),true); if (tmp > maxStart) maxStart = tmp; tmp = VFR_Output.GetFrameAtTime(curDiag->End.GetMS(),true); if (tmp > maxEnd) maxEnd = tmp; } } } // Finish layer dc.GetTextExtent(wxString::Format(_T("%i"),maxLayer), &fw, &fh, NULL, NULL, &font); int layerLen = fw + 10; // Finish times if (byFrame) { dc.GetTextExtent(wxString::Format(_T("%i"),maxStart), &fw, &fh, NULL, NULL, &font); startLen = fw + 10; dc.GetTextExtent(wxString::Format(_T("%i"),maxEnd), &fw, &fh, NULL, NULL, &font); endLen = fw + 10; } // Style length if (false && AssFile::top) { AssStyle *curStyle; for (entryIter curIter=AssFile::top->Line.begin();curIter!=AssFile::top->Line.end();curIter++) { curStyle = dynamic_cast(*curIter); if (curStyle) { dc.GetTextExtent(curStyle->name, &fw, &fh, NULL, NULL, &font); if (fw > styleLen) styleLen = fw; } } } // Finish actor/effect/style if (actorLen) actorLen += 10; if (effectLen) effectLen += 10; if (styleLen) styleLen += 10; // Set column widths colWidth[0] = labelLen; colWidth[1] = showLayer ? layerLen : 0; colWidth[2] = startLen; colWidth[3] = endLen; colWidth[4] = styleLen; colWidth[5] = actorLen; colWidth[6] = effectLen; for (int i=0;i<3;i++) colWidth[i+7] = showMargin[i] ? marginLen : 0; // Hide columns for (int i=0;i= diagMap.size()) return NULL; return dynamic_cast(*diagMap.at(n)); } catch (...) { return NULL; } } /// @brief Check if line is being displayed /// @param line /// @return /// bool BaseGrid::IsDisplayed(AssDialogue *line) { VideoContext* con = VideoContext::Get(); if (!con->IsLoaded()) return false; int f1 = VFR_Output.GetFrameAtTime(line->Start.GetMS(),true); int f2 = VFR_Output.GetFrameAtTime(line->End.GetMS(),false); if (f1 <= con->GetFrameN() && f2 >= con->GetFrameN()) return true; return false; } /// @brief Update maps /// void BaseGrid::UpdateMaps() { // Store old int len = selMap.size(); std::vector tmpDiagPtrMap(diagPtrMap); std::vector tmpSelMap(selMap); // Clear old diagPtrMap.clear(); diagMap.clear(); selMap.clear(); // Re-generate lines for (entryIter cur=AssFile::top->Line.begin();cur != AssFile::top->Line.end();cur++) { AssDialogue *curdiag = dynamic_cast(*cur); if (curdiag) { // Find old pos int sel = 0; for (int i=0;iIsLoaded()) { parentFrame->videoBox->videoSlider->SetFocus(); parentFrame->videoBox->videoSlider->GetEventHandler()->ProcessEvent(event); return; } event.Skip(); return; } // Select all if (key == 'A' && ctrl && !alt && !shift) { int rows = GetRows(); for (int i=0;ilinen; if (extendRow != -1) { curLine = extendRow; extendRow = -1; } int next = MID(0,curLine+dir*step,GetRows()-1); editBox->SetToLine(next); SelectRow(next); MakeCellVisible(next,0,false); return; } // Move active only if (alt && !shift && !ctrl) { extendRow = -1; int next = MID(0,editBox->linen+dir*step,GetRows()-1); editBox->SetToLine(next); Refresh(false); MakeCellVisible(next,0,false); return; } // Shift-selection if (shift && !ctrl && !alt) { // Find end if (extendRow == -1) extendRow = editBox->linen; extendRow = MID(0,extendRow+dir*step,GetRows()-1); // Set range int i1 = editBox->linen; int i2 = extendRow; if (i2 < i1) { int aux = i1; i1 = i2; i2 = aux; } // Select range ClearSelection(); for (int i=i1;i<=i2;i++) { SelectRow(i,true); } MakeCellVisible(extendRow,0,false); return; } } // Other events, send to audio display if (VideoContext::Get()->audio->loaded) { VideoContext::Get()->audio->GetEventHandler()->ProcessEvent(event); } else event.Skip(); } /// @brief Sets display by frame or not /// @param state /// @return /// void BaseGrid::SetByFrame (bool state) { // Check if it's already the same if (byFrame == state) return; byFrame = state; SetColumnWidths(); Refresh(false); } /// @brief Generates an array covering inclusive range /// @param n1 /// @param n2 /// wxArrayInt BaseGrid::GetRangeArray(int n1,int n2) const { // Swap if in wrong order if (n2 < n1) { int aux = n1; n1 = n2; n2 = aux; } // Generate array wxArrayInt target; for (int i=n1;i<=n2;i++) { target.Add(i); } return target; } // SelectionController void BaseGrid::GetSelectedSet(Selection &selection) const { for (size_t i = 0; i < selMap.size(); ++i) { if (selMap[i] != 0) { selection.insert(GetDialogue((int)i)); } } }