1
// Copyright (c) 2006, Rodrigo Braz Monteiro
2
// All rights reserved.
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions are met:
7
// * Redistributions of source code must retain the above copyright notice,
8
// this list of conditions and the following disclaimer.
9
// * Redistributions in binary form must reproduce the above copyright notice,
10
// this list of conditions and the following disclaimer in the documentation
11
// and/or other materials provided with the distribution.
12
// * Neither the name of the Aegisub Group nor the names of its contributors
13
// may be used to endorse or promote products derived from this software
14
// without specific prior written permission.
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
// POSSIBILITY OF SUCH DAMAGE.
28
// -----------------------------------------------------------------------------
32
// Website: http://aegisub.cellosoft.com
33
// Contact: mailto:zeratul@cellosoft.com
41
#include "base_grid.h"
44
#include "ass_dialogue.h"
45
#include "ass_style.h"
48
#include "subs_edit_box.h"
49
#include "frame_main.h"
50
#include "video_box.h"
51
#include "video_slider.h"
52
#include "video_context.h"
53
#include "audio_display.h"
58
BaseGrid::BaseGrid(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
59
: wxWindow(parent, id, pos, size, style, name)
70
scrollBar = new wxScrollBar(this,GRID_SCROLLBAR,wxDefaultPosition,wxDefaultSize,wxSB_VERTICAL);
71
scrollBar->SetScrollbar(0,10,100,10);
80
BaseGrid::~BaseGrid() {
87
void BaseGrid::UpdateStyle() {
89
wxString fontname = Options.AsText(_T("Grid Font Face"));
90
if (fontname.IsEmpty()) fontname = _T("Tahoma");
91
font.SetFaceName(fontname);
93
font.SetFamily(wxFONTFAMILY_SWISS );
94
font.SetWeight(wxFONTWEIGHT_NORMAL);
95
font.SetPointSize(Options.AsInt(_T("Grid font size")));
102
dc.GetTextExtent(_T("#TWFfgGhH"), &fw, &fh, NULL, NULL, &font);
107
for (int i=0;i<10;i++) showCol[i] = Options.AsBool(_T("Grid show column ") + AegiIntegerToString(i));
118
void BaseGrid::Clear () {
129
void BaseGrid::BeginBatch() {
136
void BaseGrid::EndBatch() {
142
//////////////////////
143
// Makes cell visible
144
void BaseGrid::MakeCellVisible(int row, int col,bool center) {
145
// Update last row selection
151
GetClientSize(&w,&h);
152
bool forceCenter = !center;
154
// Get min and max visible
156
int maxVis = yPos+h/lineHeight-3;
159
if (forceCenter || row < minVis || row > maxVis) {
161
ScrollTo(row - h/lineHeight/2 + 1);
165
if (row < minVis) ScrollTo(row - 1);
166
if (row > maxVis) ScrollTo(row - h/lineHeight + 3);
174
void BaseGrid::SelectRow(int row, bool addToSelected, bool select) {
176
if (row >= GetRows()) row = GetRows()-1;
177
else if (row < 0) row = 0;
179
if (!addToSelected) ClearSelection();
181
bool cur = selMap.at(row);
183
selMap.at(row) = select;
185
if (!addToSelected) {
191
GetClientSize(&w,&h);
192
RefreshRect(wxRect(0,(row+1-yPos)*lineHeight,w,lineHeight),false);
200
/////////////////////////
201
// Selects visible lines
202
void BaseGrid::SelectVisible() {
203
int rows = GetRows();
204
bool selectedOne = false;
205
for (int i=0;i<rows;i++) {
206
if (IsDisplayed(GetDialogue(i))) {
209
MakeCellVisible(i,0);
220
///////////////////////
221
// Unselects all cells
222
void BaseGrid::ClearSelection() {
223
int rows = selMap.size();
224
for (int i=0;i<rows;i++) {
231
/////////////////////////
232
// Is cell in selection?
233
bool BaseGrid::IsInSelection(int row, int col) const {
234
if (row >= GetRows() || row < 0) return false;
237
return selMap.at(row);
245
///////////////////////////
246
// Number of selected rows
247
int BaseGrid::GetNumberSelection() {
249
int rows = selMap.size();
250
for (int i=0;i<rows;i++) {
251
if (selMap[i]) count++;
257
///////////////////////////
258
// Gets first selected row
259
int BaseGrid::GetFirstSelRow() {
260
int nrows = GetRows();
261
for (int i=0;i<nrows;i++) {
262
if (IsInSelection(i,0)) {
270
/////////////////////////////////////////////////////
271
// Gets last selected row from first block selection
272
int BaseGrid::GetLastSelRow() {
273
int frow = GetFirstSelRow();
274
while (IsInSelection(frow)) {
281
//////////////////////////
282
// Gets all selected rows
283
wxArrayInt BaseGrid::GetSelection(bool *cont) {
285
int nrows = GetRows();
287
bool continuous = true;
288
wxArrayInt selections;
291
for (int i=0;i<nrows;i++) {
294
if (last != -1 && i != last+1) continuous = false;
300
if (cont) *cont = continuous;
305
//////////////////////
306
// Get number of rows
307
int BaseGrid::GetRows() const {
308
return diagMap.size();
314
BEGIN_EVENT_TABLE(BaseGrid,wxWindow)
315
EVT_PAINT(BaseGrid::OnPaint)
316
EVT_SIZE(BaseGrid::OnSize)
317
EVT_COMMAND_SCROLL(GRID_SCROLLBAR,BaseGrid::OnScroll)
318
EVT_MOUSE_EVENTS(BaseGrid::OnMouseEvent)
319
EVT_KEY_DOWN(BaseGrid::OnKeyPress)
325
void BaseGrid::OnPaint (wxPaintEvent &event) {
338
GetClientSize(&w,&h);
339
w -= scrollBar->GetSize().GetWidth();
343
if (bmp->GetWidth() < w || bmp->GetHeight() < h) {
348
if (!bmp) bmp = new wxBitmap(w,h);
352
bmpDC.SelectObject(*bmp);
354
dc.Blit(0,0,w,h,&bmpDC,0,0);
361
void BaseGrid::DrawImage(wxDC &dc) {
365
GetClientSize(&w,&h);
366
w -= scrollBar->GetSize().GetWidth();
372
dc.SetBackground(wxBrush(Options.AsColour(_T("Grid Background"))));
376
dc.SetPen(*wxTRANSPARENT_PEN);
377
dc.SetBrush(wxBrush(Options.AsColour(_T("Grid left column"))));
378
dc.DrawRectangle(0,lineHeight,colWidth[0],h-lineHeight);
381
int drawPerScreen = h/lineHeight + 1;
382
int nDraw = MID(0,drawPerScreen,GetRows()-yPos);
383
int maxH = (nDraw+1) * lineHeight;
386
std::vector<wxBrush> rowColors;
387
std::vector<wxColor> foreColors;
388
rowColors.push_back(wxBrush(Options.AsColour(_T("Grid Background")))); // 0 = Standard
389
foreColors.push_back(Options.AsColour(_T("Grid standard foreground")));
390
rowColors.push_back(wxBrush(Options.AsColour(_T("Grid Header")))); // 1 = Header
391
foreColors.push_back(Options.AsColour(_T("Grid standard foreground")));
392
rowColors.push_back(wxBrush(Options.AsColour(_T("Grid selection background")))); // 2 = Selected
393
foreColors.push_back(Options.AsColour(_T("Grid selection foreground")));
394
rowColors.push_back(wxBrush(Options.AsColour(_T("Grid comment background")))); // 3 = Commented
395
foreColors.push_back(Options.AsColour(_T("Grid selection foreground")));
396
rowColors.push_back(wxBrush(Options.AsColour(_T("Grid inframe background")))); // 4 = Video Highlighted
397
foreColors.push_back(Options.AsColour(_T("Grid selection foreground")));
398
rowColors.push_back(wxBrush(Options.AsColour(_T("Grid selected comment background")))); // 5 = Commented & selected
399
foreColors.push_back(Options.AsColour(_T("Grid selection foreground")));
402
bool drawGrid = true;
404
dc.SetPen(wxPen(Options.AsColour(_T("Grid lines"))));
405
dc.DrawLine(0,0,w,0);
406
dc.SetPen(*wxTRANSPARENT_PEN);
413
AssDialogue *curDiag;
414
for (int i=0;i<nDraw+1;i++) {
416
int curRow = i+yPos-1;
417
curDiag = (curRow>=0) ? GetDialogue(curRow) : NULL;
421
// Check for collisions
422
bool collides = false;
424
AssDialogue *sel = GetDialogue(editBox->linen);
425
if (sel && sel != curDiag) {
426
if (curDiag->CollidesWith(sel)) collides = true;
431
wxArrayString strings;
435
for (int columnIndex = 0; columnIndex < GetColumnCount(); columnIndex++) {
436
strings.Add(GetColumnHeaderText(columnIndex));
444
strings.Add(wxString::Format(_T("%i"),curRow+1));
445
strings.Add(wxString::Format(_T("%i"),curDiag->Layer));
447
strings.Add(wxString::Format(_T("%i"),VFR_Output.GetFrameAtTime(curDiag->Start.GetMS(),true)));
448
strings.Add(wxString::Format(_T("%i"),VFR_Output.GetFrameAtTime(curDiag->End.GetMS(),false)));
451
strings.Add(curDiag->Start.GetASSFormated());
452
strings.Add(curDiag->End.GetASSFormated());
454
strings.Add(curDiag->Style);
455
strings.Add(curDiag->Actor);
456
strings.Add(curDiag->Effect);
457
strings.Add(curDiag->GetMarginString(0));
458
strings.Add(curDiag->GetMarginString(1));
459
strings.Add(curDiag->GetMarginString(2));
462
int mode = Options.AsInt(_T("Grid Hide Overrides"));
463
wxString value = _T("");
466
if (mode == 1 || mode == 2) {
467
wxString replaceWith = Options.AsText(_T("Grid hide overrides char"));
468
int textlen = curDiag->Text.Length();
471
for (int i=0;i<textlen;i++) {
472
curChar = curDiag->Text[i];
473
if (curChar == _T('{')) depth = 1;
474
else if (curChar == _T('}')) {
476
if (depth == 0 && mode == 1) value += replaceWith;
477
if (depth < 0) depth = 0;
479
else if (depth != 1) value += curChar;
484
else value = curDiag->Text;
486
// Cap length and set text
487
if (value.Length() > 512) value = value.Left(512) + _T("...");
492
bool inSel = IsInSelection(curRow,0);
493
if (inSel && curDiag->Comment) curColor = 5;
494
else if (inSel) curColor = 2;
495
else if (curDiag->Comment) curColor = 3;
496
else if (Options.AsBool(_T("Highlight subs in frame")) && IsDisplayed(curDiag)) curColor = 4;
500
for (int j=0;j<11;j++) strings.Add(_T("?"));
503
// Draw row background color
505
dc.SetBrush(rowColors[curColor]);
506
dc.DrawRectangle((curColor == 1) ? 0 : colWidth[0],i*lineHeight+1,w,lineHeight);
510
if (collides) dc.SetTextForeground(Options.AsColour(_T("Grid collision foreground")));
512
dc.SetTextForeground(foreColors[curColor]);
518
for (int j=0;j<11;j++) {
520
if (colWidth[j] == 0) continue;
523
isCenter = !(j == 4 || j == 5 || j == 6 || j == 10);
525
// Calculate clipping
526
cur = wxRect(dx+4,dy,colWidth[j]-6,lineHeight);
529
dc.DestroyClippingRegion();
530
dc.SetClippingRegion(cur);
533
dc.DrawLabel(strings[j],cur,isCenter ? wxALIGN_CENTER : (wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT));
536
//if (collides) dc.SetPen(wxPen(wxColour(255,0,0)));
539
dc.DestroyClippingRegion();
541
dc.SetPen(wxPen(Options.AsColour(_T("Grid lines"))));
542
dc.DrawLine(0,dy+lineHeight,w,dy+lineHeight);
543
dc.SetPen(*wxTRANSPARENT_PEN);
550
dc.SetPen(wxPen(Options.AsColour(_T("Grid lines"))));
551
for (int i=0;i<10;i++) {
553
dc.DrawLine(dx,0,dx,maxH);
555
dc.DrawLine(0,0,0,maxH);
556
dc.DrawLine(w-1,0,w-1,maxH);
559
// Draw currently active line border
560
dc.SetPen(wxPen(Options.AsColour(_T("Grid Active border"))));
561
dc.SetBrush(*wxTRANSPARENT_BRUSH);
562
dy = (editBox->linen+1-yPos) * lineHeight;
563
dc.DrawRectangle(0,dy,w,lineHeight+1);
569
void BaseGrid::OnSize(wxSizeEvent &event) {
578
void BaseGrid::OnScroll(wxScrollEvent &event) {
579
int newPos = event.GetPosition();
580
if (yPos != newPos) {
589
void BaseGrid::OnMouseEvent(wxMouseEvent &event) {
592
GetClientSize(&w,&h);
595
bool shift = event.ShiftDown();
596
bool alt = event.AltDown();
597
bool ctrl = event.CmdDown();
599
// Row that mouse is over
600
bool click = event.LeftDown();
601
bool left_up = event.LeftUp();
602
bool dclick = event.LeftDClick();
603
int row = event.GetY() / lineHeight + yPos - 1;
605
row = MID(0, row, GetRows() - 1);
608
// If holding is false the left up event has already been handled
609
if (left_up && !holding) {
614
if (event.ButtonDown() && Options.AsBool(L"Grid Allow Focus")) {
619
if (event.RightDown()) {
620
OnPopupMenu(row < yPos, event.GetPosition());
625
if (event.GetWheelRotation() != 0) {
626
int step = 3 * event.GetWheelRotation() / event.GetWheelDelta();
627
ScrollTo(yPos - step);
631
if (row < 0 || row >= GetRows()) {
638
if (!shift && !alt) lastRow = row;
641
if (left_up && holding) {
646
// Scroll to keep visible
650
int maxVis = yPos+h/lineHeight-3;
652
if (row < minVis) delta = -3;
653
if (row > maxVis) delta = +3;
656
ScrollTo(MID(row - (h / lineHeight), yPos + delta, row));
658
// End the hold if this was a mousedown to avoid accidental
659
// selection of extra lines
669
if (left_up && ctrl && !shift && !alt) {
670
SelectRow(row,true,!IsInSelection(row,0));
671
parentFrame->UpdateToolbar();
676
if (!shift && !ctrl && !alt) {
677
if (click || dclick) {
678
SelectRow(row,false);
679
parentFrame->UpdateToolbar();
682
if (left_up || dclick) {
683
int old = editBox->linen;
684
editBox->SetToLine(row);
685
Refresh(false); // always redraw the entire grid, to ensure colliding lines are shown properly (#1371)
689
VideoContext::Get()->JumpToFrame(VFR_Output.GetFrameAtTime(GetDialogue(row)->Start.GetMS(),true));
691
if (click || dclick || left_up)
696
if (left_up && !shift && !ctrl && alt) {
697
editBox->SetToLine(row);
702
if ((left_up && shift && !alt) || (holding && !ctrl && !alt && !shift)) {
704
// Keyboard selection continues from where the mouse was last used
717
bool notFirst = false;
718
for (int i=i1;i<=i2;i++) {
719
SelectRow(i,notFirst || ctrl,true);
722
parentFrame->UpdateToolbar();
731
void BaseGrid::ScrollTo(int y) {
733
GetClientSize(&w,&h);
734
int nextY = MID(0,y,GetRows()+2 - h/lineHeight);
737
if (scrollBar->IsEnabled()) scrollBar->SetThumbPosition(yPos);
745
void BaseGrid::AdjustScrollbar() {
748
GetClientSize(&w,&h);
749
int drawPerScreen = h/lineHeight;
750
int rows = GetRows();
751
bool barToEnable = drawPerScreen < rows+2;
752
bool barEnabled = scrollBar->IsEnabled();
755
yPos = MID(0,yPos,rows - drawPerScreen);
759
scrollBar->GetSize(&sw,&sh);
760
scrollBar->SetSize(w-sw,0,sw,h);
764
scrollBar->SetScrollbar(yPos,drawPerScreen,rows+2,drawPerScreen-2,true);
766
if (barToEnable != barEnabled) scrollBar->Enable(barToEnable);
771
/////////////////////
773
void BaseGrid::SetColumnWidths() {
777
GetClientSize(&w,&h);
779
// DC for text extents test
785
dc.GetTextExtent(_T("0000"), &fw, &fh, NULL, NULL, &font);
786
int marginLen = fw + 10;
787
dc.GetTextExtent(wxString::Format(_T("%i"),GetRows()), &fw, &fh, NULL, NULL, &font);
788
int labelLen = fw + 10;
793
dc.GetTextExtent(time.GetASSFormated(), &fw, &fh, NULL, NULL, &font);
800
showMargin[0] = showMargin[1] = showMargin[2] = false;
801
bool showLayer = false;
808
AssDialogue *curDiag;
809
for (int i=0;i<GetRows();i++) {
810
curDiag = GetDialogue(i);
813
if (curDiag->Layer > maxLayer) {
814
maxLayer = curDiag->Layer;
819
if (!curDiag->Actor.IsEmpty()) {
820
dc.GetTextExtent(curDiag->Actor, &fw, &fh, NULL, NULL, &font);
821
if (fw > actorLen) actorLen = fw;
825
if (!curDiag->Style.IsEmpty()) {
826
dc.GetTextExtent(curDiag->Style, &fw, &fh, NULL, NULL, &font);
827
if (fw > styleLen) styleLen = fw;
831
if (!curDiag->Effect.IsEmpty()) {
832
dc.GetTextExtent(curDiag->Effect, &fw, &fh, NULL, NULL, &font);
833
if (fw > effectLen) effectLen = fw;
837
for (int j=0;j<3;j++) {
838
if (curDiag->Margin[j] != 0) showMargin[j] = true;
843
int tmp = VFR_Output.GetFrameAtTime(curDiag->Start.GetMS(),true);
844
if (tmp > maxStart) maxStart = tmp;
845
tmp = VFR_Output.GetFrameAtTime(curDiag->End.GetMS(),true);
846
if (tmp > maxEnd) maxEnd = tmp;
852
dc.GetTextExtent(wxString::Format(_T("%i"),maxLayer), &fw, &fh, NULL, NULL, &font);
853
int layerLen = fw + 10;
857
dc.GetTextExtent(wxString::Format(_T("%i"),maxStart), &fw, &fh, NULL, NULL, &font);
859
dc.GetTextExtent(wxString::Format(_T("%i"),maxEnd), &fw, &fh, NULL, NULL, &font);
864
if (false && AssFile::top) {
866
for (entryIter curIter=AssFile::top->Line.begin();curIter!=AssFile::top->Line.end();curIter++) {
867
curStyle = AssEntry::GetAsStyle(*curIter);
869
dc.GetTextExtent(curStyle->name, &fw, &fh, NULL, NULL, &font);
870
if (fw > styleLen) styleLen = fw;
875
// Finish actor/effect/style
876
if (actorLen) actorLen += 10;
877
if (effectLen) effectLen += 10;
878
if (styleLen) styleLen += 10;
881
colWidth[0] = labelLen;
882
colWidth[1] = showLayer ? layerLen : 0;
883
colWidth[2] = startLen;
884
colWidth[3] = endLen;
885
colWidth[4] = styleLen;
886
colWidth[5] = actorLen;
887
colWidth[6] = effectLen;
888
for (int i=0;i<3;i++) colWidth[i+7] = showMargin[i] ? marginLen : 0;
890
// Take header text widths into account
891
for (int i = 0; i < GetColumnCount(); i++) {
892
wxString headerText = GetColumnHeaderText(i);
893
dc.GetTextExtent(headerText, &fw, &fh, NULL, NULL, &font);
895
if (colWidth[i] > 0 && fw > colWidth[i])
900
for (int i=0;i<10;i++) {
901
if (showCol[i] == false) colWidth[i] = 0;
906
for (int i=0;i<10;i++) total+= colWidth[i];
907
colWidth[10] = w-total;
911
//////////////////////////
912
// Gets dialogue from map
913
AssDialogue *BaseGrid::GetDialogue(int n) {
915
if (n < 0) return NULL;
916
AssEntry *e = *diagMap.at(n);
917
if (e->GetType() != ENTRY_DIALOGUE) return NULL;
918
return AssEntry::GetAsDialogue(e);
926
////////////////////////////////////
927
// Check if line is being displayed
928
bool BaseGrid::IsDisplayed(AssDialogue *line) {
929
if (!VideoContext::Get()->IsLoaded()) return false;
930
int f1 = VFR_Output.GetFrameAtTime(line->Start.GetMS(),true);
931
int f2 = VFR_Output.GetFrameAtTime(line->End.GetMS(),false);
932
if (f1 <= VideoContext::Get()->GetFrameN() && f2 >= VideoContext::Get()->GetFrameN()) return true;
939
void BaseGrid::UpdateMaps() {
941
int len = diagMap.size();
942
std::vector<AssDialogue *> tmpDiagPtrMap;
943
std::vector<bool> tmpSelMap;
944
for (int i=0;i<len;i++) {
945
tmpDiagPtrMap.push_back(diagPtrMap[i]);
946
tmpSelMap.push_back(selMap[i]);
956
AssDialogue *curdiag;
957
for (entryIter cur=AssFile::top->Line.begin();cur != AssFile::top->Line.end();cur++) {
958
curdiag = AssEntry::GetAsDialogue(*cur);
962
for (int i=0;i<len;i++) {
963
if (tmpDiagPtrMap[i] == curdiag) {
970
diagMap.push_back(cur);
971
diagPtrMap.push_back(curdiag);
972
selMap.push_back(sel);
985
void BaseGrid::OnKeyPress(wxKeyEvent &event) {
988
GetClientSize(&w,&h);
991
int key = event.GetKeyCode();
993
bool ctrl = event.m_metaDown;
995
bool ctrl = event.m_controlDown;
997
bool alt = event.m_altDown;
998
bool shift = event.m_shiftDown;
1000
// The "menu" key, simulate a right-click
1001
if (key == WXK_MENU || key == WXK_WINDOWS_MENU) {
1003
pos.x = colWidth[0];
1005
pos.y = lineHeight/2;
1006
OnPopupMenu(true, pos);
1009
pos.y = (editBox->linen+1-yPos) * lineHeight + lineHeight/2;
1010
OnPopupMenu(false, pos);
1015
// Left/right, forward to seek bar if video is loaded
1016
if (key == WXK_LEFT || key == WXK_RIGHT) {
1017
if (VideoContext::Get()->IsLoaded()) {
1018
parentFrame->videoBox->videoSlider->SetFocus();
1019
#if wxCHECK_VERSION(2,9,0)
1020
parentFrame->videoBox->videoSlider->GetEventHandler()->ProcessEvent(event);
1022
parentFrame->videoBox->videoSlider->AddPendingEvent(event);
1031
if (key == 'A' && ctrl && !alt && !shift) {
1032
int rows = GetRows();
1033
for (int i=0;i<rows;i++) SelectRow(i,true);
1039
if (key == WXK_UP) dir = -1;
1040
if (key == WXK_DOWN) dir = 1;
1041
if (key == WXK_PAGEUP) {
1043
step = h/lineHeight - 2;
1045
if (key == WXK_PAGEDOWN) {
1047
step = h/lineHeight - 2;
1049
if (key == WXK_HOME) {
1053
if (key == WXK_END) {
1061
if (!ctrl && !shift && !alt) {
1062
// Move to extent first
1063
int curLine = editBox->linen;
1064
if (extendRow != -1) {
1065
curLine = extendRow;
1069
int next = MID(0,curLine+dir*step,GetRows()-1);
1070
editBox->SetToLine(next);
1072
MakeCellVisible(next,0,false);
1077
if (alt && !shift && !ctrl) {
1079
int next = MID(0,editBox->linen+dir*step,GetRows()-1);
1080
editBox->SetToLine(next);
1082
MakeCellVisible(next,0,false);
1087
if (shift && !ctrl && !alt) {
1089
if (extendRow == -1) extendRow = editBox->linen;
1090
extendRow = MID(0,extendRow+dir*step,GetRows()-1);
1093
int i1 = editBox->linen;
1103
for (int i=i1;i<=i2;i++) {
1107
MakeCellVisible(extendRow,0,false);
1112
// Other events, send to audio display
1113
if (VideoContext::Get()->audio->loaded) {
1114
#if wxCHECK_VERSION(2,9,0)
1115
VideoContext::Get()->audio->GetEventHandler()->ProcessEvent(event);
1117
VideoContext::Get()->audio->AddPendingEvent(event);
1124
////////////////////////////////
1125
// Sets display by frame or not
1126
void BaseGrid::SetByFrame (bool state) {
1127
// Check if it's already the same
1128
if (byFrame == state) return;
1135
///////////////////////////////////////////////
1136
// Generates an array covering inclusive range
1137
wxArrayInt BaseGrid::GetRangeArray(int n1,int n2) {
1138
// Swap if in wrong order
1147
for (int i=n1;i<=n2;i++) {