~ubuntu-branches/ubuntu/trusty/aegisub/trusty

« back to all changes in this revision

Viewing changes to src/base_grid.cpp

  • Committer: Package Import Robot
  • Author(s): Sebastian Reichel
  • Date: 2012-03-16 22:58:00 UTC
  • Revision ID: package-import@ubuntu.com-20120316225800-yfb8h9e5n04rk46a
Tags: upstream-2.1.9
ImportĀ upstreamĀ versionĀ 2.1.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) 2006, Rodrigo Braz Monteiro
 
2
// All rights reserved.
 
3
//
 
4
// Redistribution and use in source and binary forms, with or without
 
5
// modification, are permitted provided that the following conditions are met:
 
6
//
 
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.
 
15
//
 
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.
 
27
//
 
28
// -----------------------------------------------------------------------------
 
29
//
 
30
// AEGISUB
 
31
//
 
32
// Website: http://aegisub.cellosoft.com
 
33
// Contact: mailto:zeratul@cellosoft.com
 
34
//
 
35
 
 
36
 
 
37
////////////
 
38
// Includes
 
39
#include "config.h"
 
40
 
 
41
#include "base_grid.h"
 
42
#include "utils.h"
 
43
#include "ass_file.h"
 
44
#include "ass_dialogue.h"
 
45
#include "ass_style.h"
 
46
#include "options.h"
 
47
#include "vfr.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"
 
54
 
 
55
 
 
56
///////////////
 
57
// Constructor
 
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)
 
60
{
 
61
        // Misc variables
 
62
        lastRow = -1;
 
63
        yPos = 0;
 
64
        extendRow = -1;
 
65
        bmp = NULL;
 
66
        holding = false;
 
67
        byFrame = false;
 
68
 
 
69
        // Set scrollbar
 
70
        scrollBar = new wxScrollBar(this,GRID_SCROLLBAR,wxDefaultPosition,wxDefaultSize,wxSB_VERTICAL);
 
71
        scrollBar->SetScrollbar(0,10,100,10);
 
72
 
 
73
        // Set style
 
74
        UpdateStyle();
 
75
}
 
76
 
 
77
 
 
78
//////////////
 
79
// Destructor
 
80
BaseGrid::~BaseGrid() {
 
81
        delete bmp;
 
82
}
 
83
 
 
84
 
 
85
////////////////
 
86
// Update style
 
87
void BaseGrid::UpdateStyle() {
 
88
        // Set font
 
89
        wxString fontname = Options.AsText(_T("Grid Font Face"));
 
90
        if (fontname.IsEmpty()) fontname = _T("Tahoma");
 
91
        font.SetFaceName(fontname);
 
92
        if (!font.IsOk())
 
93
                font.SetFamily(wxFONTFAMILY_SWISS );
 
94
        font.SetWeight(wxFONTWEIGHT_NORMAL);
 
95
        font.SetPointSize(Options.AsInt(_T("Grid font size")));
 
96
 
 
97
        // Set line height
 
98
        {
 
99
                wxClientDC dc(this);
 
100
                dc.SetFont(font);
 
101
                int fw,fh;
 
102
                dc.GetTextExtent(_T("#TWFfgGhH"), &fw, &fh, NULL, NULL, &font);
 
103
                lineHeight = fh+4;
 
104
        }
 
105
 
 
106
        // Set column widths
 
107
        for (int i=0;i<10;i++) showCol[i] = Options.AsBool(_T("Grid show column ") + AegiIntegerToString(i));
 
108
        SetColumnWidths();
 
109
 
 
110
        // Update
 
111
        AdjustScrollbar();
 
112
        Refresh();
 
113
}
 
114
 
 
115
 
 
116
///////////////
 
117
// Clears grid
 
118
void BaseGrid::Clear () {
 
119
        diagMap.clear();
 
120
        diagPtrMap.clear();
 
121
        selMap.clear();
 
122
        yPos = 0;
 
123
        AdjustScrollbar();
 
124
}
 
125
 
 
126
 
 
127
///////////////
 
128
// Begin batch
 
129
void BaseGrid::BeginBatch() {
 
130
        //Freeze();
 
131
}
 
132
 
 
133
 
 
134
/////////////
 
135
// End batch
 
136
void BaseGrid::EndBatch() {
 
137
        //Thaw();
 
138
        AdjustScrollbar();
 
139
}
 
140
 
 
141
 
 
142
//////////////////////
 
143
// Makes cell visible
 
144
void BaseGrid::MakeCellVisible(int row, int col,bool center) {
 
145
        // Update last row selection
 
146
        lastRow = row;
 
147
 
 
148
        // Get size
 
149
        int w = 0;
 
150
        int h = 0;
 
151
        GetClientSize(&w,&h);
 
152
        bool forceCenter = !center;
 
153
 
 
154
        // Get min and max visible
 
155
        int minVis = yPos+1;
 
156
        int maxVis = yPos+h/lineHeight-3;
 
157
 
 
158
        // Make visible
 
159
        if (forceCenter || row < minVis || row > maxVis) {
 
160
                if (center) {
 
161
                        ScrollTo(row - h/lineHeight/2 + 1);
 
162
                }
 
163
 
 
164
                else {
 
165
                        if (row < minVis) ScrollTo(row - 1);
 
166
                        if (row > maxVis) ScrollTo(row - h/lineHeight + 3);
 
167
                }
 
168
        }
 
169
}
 
170
 
 
171
 
 
172
////////////////
 
173
// Select a row
 
174
void BaseGrid::SelectRow(int row, bool addToSelected, bool select) {
 
175
        // Sanity checking
 
176
        if (row >= GetRows()) row = GetRows()-1;
 
177
        else if (row < 0) row = 0;
 
178
 
 
179
        if (!addToSelected) ClearSelection();
 
180
        try {
 
181
                bool cur = selMap.at(row);
 
182
                if (select != cur) {
 
183
                        selMap.at(row) = select;
 
184
                        
 
185
                        if (!addToSelected) {
 
186
                                Refresh(false);
 
187
                        }
 
188
                        else {
 
189
                                int w = 0;
 
190
                                int h = 0;
 
191
                                GetClientSize(&w,&h);
 
192
                                RefreshRect(wxRect(0,(row+1-yPos)*lineHeight,w,lineHeight),false);
 
193
                        }
 
194
                }
 
195
        }
 
196
        catch (...) {}
 
197
}
 
198
 
 
199
 
 
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))) {
 
207
                        if (!selectedOne) {
 
208
                                SelectRow(i,false);
 
209
                                MakeCellVisible(i,0);
 
210
                                selectedOne = true;
 
211
                        }
 
212
                        else {
 
213
                                SelectRow(i,true);
 
214
                        }
 
215
                }
 
216
        }
 
217
}
 
218
 
 
219
 
 
220
///////////////////////
 
221
// Unselects all cells
 
222
void BaseGrid::ClearSelection() {
 
223
        int rows = selMap.size();
 
224
        for (int i=0;i<rows;i++) {
 
225
                selMap[i] = false;
 
226
        }
 
227
        Refresh(false);
 
228
}
 
229
 
 
230
 
 
231
/////////////////////////
 
232
// Is cell in selection?
 
233
bool BaseGrid::IsInSelection(int row, int col) const {
 
234
        if (row >= GetRows() || row < 0) return false;
 
235
        (void) col;
 
236
        try {
 
237
                return selMap.at(row);
 
238
        }
 
239
        catch (...) {
 
240
                return false;
 
241
        }
 
242
}
 
243
 
 
244
 
 
245
///////////////////////////
 
246
// Number of selected rows
 
247
int BaseGrid::GetNumberSelection() {
 
248
        int count = 0;
 
249
        int rows = selMap.size();
 
250
        for (int i=0;i<rows;i++) {
 
251
                if (selMap[i]) count++;
 
252
        }
 
253
        return count;
 
254
}
 
255
 
 
256
 
 
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)) {
 
263
                        return i;
 
264
                }
 
265
        }
 
266
        return -1;
 
267
}
 
268
 
 
269
 
 
270
/////////////////////////////////////////////////////
 
271
// Gets last selected row from first block selection
 
272
int BaseGrid::GetLastSelRow() {
 
273
        int frow = GetFirstSelRow();
 
274
        while (IsInSelection(frow)) {
 
275
                frow++;
 
276
        }
 
277
        return frow-1;
 
278
}
 
279
 
 
280
 
 
281
//////////////////////////
 
282
// Gets all selected rows
 
283
wxArrayInt BaseGrid::GetSelection(bool *cont) {
 
284
        // Prepare
 
285
        int nrows = GetRows();
 
286
        int last = -1;
 
287
        bool continuous = true;
 
288
        wxArrayInt selections;
 
289
 
 
290
        // Scan
 
291
        for (int i=0;i<nrows;i++) {
 
292
                if (selMap[i]) {
 
293
                        selections.Add(i);
 
294
                        if (last != -1 && i != last+1) continuous = false;
 
295
                        last = i;
 
296
                }
 
297
        }
 
298
 
 
299
        // Return
 
300
        if (cont) *cont = continuous;
 
301
        return selections;
 
302
}
 
303
 
 
304
 
 
305
//////////////////////
 
306
// Get number of rows
 
307
int BaseGrid::GetRows() const {
 
308
        return diagMap.size();
 
309
}
 
310
 
 
311
 
 
312
///////////////
 
313
// Event table
 
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)
 
320
END_EVENT_TABLE()
 
321
 
 
322
 
 
323
///////////////
 
324
// Paint event
 
325
void BaseGrid::OnPaint (wxPaintEvent &event) {
 
326
        // Prepare
 
327
        wxPaintDC dc(this);
 
328
        bool direct = false;
 
329
 
 
330
        if (direct) {
 
331
                DrawImage(dc);
 
332
        }
 
333
 
 
334
        else {
 
335
                // Get size and pos
 
336
                int w = 0;
 
337
                int h = 0;
 
338
                GetClientSize(&w,&h);
 
339
                w -= scrollBar->GetSize().GetWidth();
 
340
 
 
341
                // Prepare bitmap
 
342
                if (bmp) {
 
343
                        if (bmp->GetWidth() < w || bmp->GetHeight() < h) {
 
344
                                delete bmp;
 
345
                                bmp = NULL;
 
346
                        }
 
347
                }
 
348
                if (!bmp) bmp = new wxBitmap(w,h);
 
349
 
 
350
                // Draw bitmap
 
351
                wxMemoryDC bmpDC;
 
352
                bmpDC.SelectObject(*bmp);
 
353
                DrawImage(bmpDC);
 
354
                dc.Blit(0,0,w,h,&bmpDC,0,0);
 
355
        }
 
356
}
 
357
 
 
358
 
 
359
//////////////
 
360
// Draw image
 
361
void BaseGrid::DrawImage(wxDC &dc) {
 
362
        // Get size and pos
 
363
        int w = 0;
 
364
        int h = 0;
 
365
        GetClientSize(&w,&h);
 
366
        w -= scrollBar->GetSize().GetWidth();
 
367
 
 
368
        // Set font
 
369
        dc.SetFont(font);
 
370
 
 
371
        // Clear background
 
372
        dc.SetBackground(wxBrush(Options.AsColour(_T("Grid Background"))));
 
373
        dc.Clear();
 
374
 
 
375
        // Draw labels
 
376
        dc.SetPen(*wxTRANSPARENT_PEN);
 
377
        dc.SetBrush(wxBrush(Options.AsColour(_T("Grid left column"))));
 
378
        dc.DrawRectangle(0,lineHeight,colWidth[0],h-lineHeight);
 
379
 
 
380
        // Visible lines
 
381
        int drawPerScreen = h/lineHeight + 1;
 
382
        int nDraw = MID(0,drawPerScreen,GetRows()-yPos);
 
383
        int maxH = (nDraw+1) * lineHeight;
 
384
 
 
385
        // Row colors
 
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")));
 
400
 
 
401
        // First grid row
 
402
        bool drawGrid = true;
 
403
        if (drawGrid) {
 
404
                dc.SetPen(wxPen(Options.AsColour(_T("Grid lines"))));
 
405
                dc.DrawLine(0,0,w,0);
 
406
                dc.SetPen(*wxTRANSPARENT_PEN);
 
407
        }
 
408
 
 
409
        // Draw rows
 
410
        int dx = 0;
 
411
        int dy = 0;
 
412
        int curColor = 0;
 
413
        AssDialogue *curDiag;
 
414
        for (int i=0;i<nDraw+1;i++) {
 
415
                // Prepare
 
416
                int curRow = i+yPos-1;
 
417
                curDiag = (curRow>=0) ? GetDialogue(curRow) : NULL;
 
418
                dx = 0;
 
419
                dy = i*lineHeight;
 
420
 
 
421
                // Check for collisions
 
422
                bool collides = false;
 
423
                if (curDiag) {
 
424
                        AssDialogue *sel = GetDialogue(editBox->linen);
 
425
                        if (sel && sel != curDiag) {
 
426
                                if (curDiag->CollidesWith(sel)) collides = true;
 
427
                        }
 
428
                }
 
429
 
 
430
                // Text array
 
431
                wxArrayString strings;
 
432
 
 
433
                // Header
 
434
                if (i == 0) {
 
435
                        for (int columnIndex = 0; columnIndex < GetColumnCount(); columnIndex++) {
 
436
                                strings.Add(GetColumnHeaderText(columnIndex));
 
437
                        }
 
438
                        curColor = 1;
 
439
                }
 
440
 
 
441
                // Lines
 
442
                else if (curDiag) {
 
443
                        // Set fields
 
444
                        strings.Add(wxString::Format(_T("%i"),curRow+1));
 
445
                        strings.Add(wxString::Format(_T("%i"),curDiag->Layer));
 
446
                        if (byFrame) {
 
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)));
 
449
                        }
 
450
                        else {
 
451
                                strings.Add(curDiag->Start.GetASSFormated());
 
452
                                strings.Add(curDiag->End.GetASSFormated());
 
453
                        }
 
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));
 
460
 
 
461
                        // Set text
 
462
                        int mode = Options.AsInt(_T("Grid Hide Overrides"));
 
463
                        wxString value = _T("");
 
464
 
 
465
                        // Hidden overrides
 
466
                        if (mode == 1 || mode == 2) {
 
467
                                wxString replaceWith = Options.AsText(_T("Grid hide overrides char"));
 
468
                                int textlen = curDiag->Text.Length();
 
469
                                int depth = 0;
 
470
                                wxChar curChar;
 
471
                                for (int i=0;i<textlen;i++) {
 
472
                                        curChar = curDiag->Text[i];
 
473
                                        if (curChar == _T('{')) depth = 1;
 
474
                                        else if (curChar == _T('}')) {
 
475
                                                depth--;
 
476
                                                if (depth == 0 && mode == 1) value += replaceWith;
 
477
                                                if (depth < 0) depth = 0;
 
478
                                        }
 
479
                                        else if (depth != 1) value += curChar;
 
480
                                }
 
481
                        }
 
482
 
 
483
                        // Show overrides
 
484
                        else value = curDiag->Text;
 
485
 
 
486
                        // Cap length and set text
 
487
                        if (value.Length() > 512) value = value.Left(512) + _T("...");
 
488
                        strings.Add(value);
 
489
 
 
490
                        // Set color
 
491
                        curColor = 0;
 
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;
 
497
                }
 
498
 
 
499
                else {
 
500
                        for (int j=0;j<11;j++) strings.Add(_T("?"));
 
501
                }
 
502
 
 
503
                // Draw row background color
 
504
                if (curColor) {
 
505
                        dc.SetBrush(rowColors[curColor]);
 
506
                        dc.DrawRectangle((curColor == 1) ? 0 : colWidth[0],i*lineHeight+1,w,lineHeight);
 
507
                }
 
508
 
 
509
                // Set text color
 
510
                if (collides) dc.SetTextForeground(Options.AsColour(_T("Grid collision foreground")));
 
511
                else {
 
512
                        dc.SetTextForeground(foreColors[curColor]);
 
513
                }
 
514
 
 
515
                // Draw text
 
516
                wxRect cur;
 
517
                bool isCenter;
 
518
                for (int j=0;j<11;j++) {
 
519
                        // Check width
 
520
                        if (colWidth[j] == 0) continue;
 
521
 
 
522
                        // Is center?
 
523
                        isCenter = !(j == 4 || j == 5 || j == 6 || j == 10);
 
524
 
 
525
                        // Calculate clipping
 
526
                        cur = wxRect(dx+4,dy,colWidth[j]-6,lineHeight);
 
527
 
 
528
                        // Set clipping
 
529
                        dc.DestroyClippingRegion();
 
530
                        dc.SetClippingRegion(cur);
 
531
 
 
532
                        // Draw
 
533
                        dc.DrawLabel(strings[j],cur,isCenter ? wxALIGN_CENTER : (wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT));
 
534
                        dx += colWidth[j];
 
535
                }
 
536
                //if (collides) dc.SetPen(wxPen(wxColour(255,0,0)));
 
537
 
 
538
                // Draw grid
 
539
                dc.DestroyClippingRegion();
 
540
                if (drawGrid) {
 
541
                        dc.SetPen(wxPen(Options.AsColour(_T("Grid lines"))));
 
542
                        dc.DrawLine(0,dy+lineHeight,w,dy+lineHeight);
 
543
                        dc.SetPen(*wxTRANSPARENT_PEN);
 
544
                }
 
545
        }
 
546
 
 
547
        // Draw grid columns
 
548
        dx = 0;
 
549
        if (drawGrid) {
 
550
                dc.SetPen(wxPen(Options.AsColour(_T("Grid lines"))));
 
551
                for (int i=0;i<10;i++) {
 
552
                        dx += colWidth[i];
 
553
                        dc.DrawLine(dx,0,dx,maxH);
 
554
                }
 
555
                dc.DrawLine(0,0,0,maxH);
 
556
                dc.DrawLine(w-1,0,w-1,maxH);
 
557
        }
 
558
 
 
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);
 
564
}
 
565
 
 
566
 
 
567
///////////
 
568
// On size
 
569
void BaseGrid::OnSize(wxSizeEvent &event) {
 
570
        AdjustScrollbar();
 
571
        SetColumnWidths();
 
572
        Refresh(false);
 
573
}
 
574
 
 
575
 
 
576
/////////////
 
577
// On scroll
 
578
void BaseGrid::OnScroll(wxScrollEvent &event) {
 
579
        int newPos = event.GetPosition();
 
580
        if (yPos != newPos) {
 
581
                yPos = newPos;
 
582
                Refresh(false);
 
583
        }
 
584
}
 
585
 
 
586
 
 
587
////////////////
 
588
// Mouse events
 
589
void BaseGrid::OnMouseEvent(wxMouseEvent &event) {
 
590
        // Window size
 
591
        int w,h;
 
592
        GetClientSize(&w,&h);
 
593
 
 
594
        // Modifiers
 
595
        bool shift = event.ShiftDown();
 
596
        bool alt = event.AltDown();
 
597
        bool ctrl = event.CmdDown();
 
598
 
 
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;
 
604
        if (holding) {
 
605
                row = MID(0, row, GetRows() - 1);
 
606
        }
 
607
 
 
608
        // If holding is false the left up event has already been handled
 
609
        if (left_up && !holding) {
 
610
                return;
 
611
        }
 
612
 
 
613
        // Get focus
 
614
        if (event.ButtonDown() && Options.AsBool(L"Grid Allow Focus")) {
 
615
                SetFocus();
 
616
        }
 
617
 
 
618
        // Popup
 
619
        if (event.RightDown()) {
 
620
                OnPopupMenu(row < yPos, event.GetPosition());
 
621
                return;
 
622
        }
 
623
 
 
624
        // Mouse wheel
 
625
        if (event.GetWheelRotation() != 0) {
 
626
                int step = 3 * event.GetWheelRotation() / event.GetWheelDelta();
 
627
                ScrollTo(yPos - step);
 
628
                return;
 
629
        }
 
630
 
 
631
        if (row < 0 || row >= GetRows()) {
 
632
                return;
 
633
        }
 
634
 
 
635
        // Click type
 
636
        if (click) {
 
637
                holding = true;
 
638
                if (!shift && !alt) lastRow = row;
 
639
                CaptureMouse();
 
640
        }
 
641
        if (left_up && holding) {
 
642
                holding = false;
 
643
                ReleaseMouse();
 
644
        }
 
645
 
 
646
        // Scroll to keep visible
 
647
        if (holding) {
 
648
                // Find direction
 
649
                int minVis = yPos+1;
 
650
                int maxVis = yPos+h/lineHeight-3;
 
651
                int delta = 0;
 
652
                if (row < minVis) delta = -3;
 
653
                if (row > maxVis) delta = +3;
 
654
 
 
655
                if (delta) {
 
656
                        ScrollTo(MID(row - (h / lineHeight), yPos + delta, row));
 
657
 
 
658
                        // End the hold if this was a mousedown to avoid accidental
 
659
                        // selection of extra lines
 
660
                        if (click) {
 
661
                                holding = false;
 
662
                                left_up = true;
 
663
                                ReleaseMouse();
 
664
                        }
 
665
                }
 
666
        }
 
667
 
 
668
        // Toggle selected
 
669
        if (left_up && ctrl && !shift && !alt) {
 
670
                SelectRow(row,true,!IsInSelection(row,0));
 
671
                parentFrame->UpdateToolbar();
 
672
                return;
 
673
        }
 
674
 
 
675
        // Normal click
 
676
        if (!shift && !ctrl && !alt) {
 
677
                if (click || dclick) {
 
678
                        SelectRow(row,false);
 
679
                        parentFrame->UpdateToolbar();
 
680
                        extendRow = -1;
 
681
                }
 
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)
 
686
                }
 
687
 
 
688
                if (dclick)
 
689
                        VideoContext::Get()->JumpToFrame(VFR_Output.GetFrameAtTime(GetDialogue(row)->Start.GetMS(),true));
 
690
 
 
691
                if (click || dclick || left_up)
 
692
                        return;
 
693
        }
 
694
 
 
695
        // Keep selection
 
696
        if (left_up && !shift && !ctrl && alt) {
 
697
                editBox->SetToLine(row);
 
698
                return;
 
699
        }
 
700
 
 
701
        // Block select
 
702
        if ((left_up && shift && !alt) || (holding && !ctrl && !alt && !shift)) {
 
703
                if (lastRow != -1) {
 
704
                        // Keyboard selection continues from where the mouse was last used
 
705
                        extendRow = lastRow;
 
706
 
 
707
                        // Set boundaries
 
708
                        int i1 = row;
 
709
                        int i2 = lastRow;
 
710
                        if (i1 > i2) {
 
711
                                int aux = i1;
 
712
                                i1 = i2;
 
713
                                i2 = aux;
 
714
                        }
 
715
 
 
716
                        // Toggle each
 
717
                        bool notFirst = false;
 
718
                        for (int i=i1;i<=i2;i++) {
 
719
                                SelectRow(i,notFirst || ctrl,true);
 
720
                                notFirst = true;
 
721
                        }
 
722
                        parentFrame->UpdateToolbar();
 
723
                }
 
724
                return;
 
725
        }
 
726
}
 
727
 
 
728
 
 
729
/////////////
 
730
// Scroll to
 
731
void BaseGrid::ScrollTo(int y) {
 
732
        int w,h;
 
733
        GetClientSize(&w,&h);
 
734
        int nextY = MID(0,y,GetRows()+2 - h/lineHeight);
 
735
        if (yPos != nextY) {
 
736
                yPos = nextY;
 
737
                if (scrollBar->IsEnabled()) scrollBar->SetThumbPosition(yPos);
 
738
                Refresh(false);
 
739
        }
 
740
}
 
741
 
 
742
 
 
743
////////////////////
 
744
// Adjust scrollbar
 
745
void BaseGrid::AdjustScrollbar() {
 
746
        // Variables
 
747
        int w,h,sw,sh;
 
748
        GetClientSize(&w,&h);
 
749
        int drawPerScreen = h/lineHeight;
 
750
        int rows = GetRows();
 
751
        bool barToEnable = drawPerScreen < rows+2;
 
752
        bool barEnabled = scrollBar->IsEnabled();
 
753
 
 
754
        // Set yPos
 
755
        yPos = MID(0,yPos,rows - drawPerScreen);
 
756
 
 
757
        // Set size
 
758
        scrollBar->Freeze();
 
759
        scrollBar->GetSize(&sw,&sh);
 
760
        scrollBar->SetSize(w-sw,0,sw,h);
 
761
 
 
762
        // Set parameters
 
763
        if (barEnabled) {
 
764
                scrollBar->SetScrollbar(yPos,drawPerScreen,rows+2,drawPerScreen-2,true);
 
765
        }
 
766
        if (barToEnable != barEnabled) scrollBar->Enable(barToEnable);
 
767
        scrollBar->Thaw();
 
768
}
 
769
 
 
770
 
 
771
/////////////////////
 
772
// Set column widths
 
773
void BaseGrid::SetColumnWidths() {
 
774
        // Width/height
 
775
        int w = 0;
 
776
        int h = 0;
 
777
        GetClientSize(&w,&h);
 
778
 
 
779
        // DC for text extents test
 
780
        wxClientDC dc(this);
 
781
        dc.SetFont(font);
 
782
        int fw,fh;
 
783
 
 
784
        // O(1) widths
 
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;
 
789
        int startLen = 0;
 
790
        int endLen = 0;
 
791
        if (!byFrame) {
 
792
                AssTime time;
 
793
                dc.GetTextExtent(time.GetASSFormated(), &fw, &fh, NULL, NULL, &font);
 
794
                startLen = fw + 10;
 
795
                endLen = fw + 10;
 
796
        }
 
797
 
 
798
        // O(n) widths
 
799
        bool showMargin[3];
 
800
        showMargin[0] = showMargin[1] = showMargin[2] = false;
 
801
        bool showLayer = false;
 
802
        int styleLen = 0;
 
803
        int actorLen = 0;
 
804
        int effectLen = 0;
 
805
        int maxLayer = 0;
 
806
        int maxStart = 0;
 
807
        int maxEnd = 0;
 
808
        AssDialogue *curDiag;
 
809
        for (int i=0;i<GetRows();i++) {
 
810
                curDiag = GetDialogue(i);
 
811
                if (curDiag) {
 
812
                        // Layer
 
813
                        if (curDiag->Layer > maxLayer) {
 
814
                                maxLayer = curDiag->Layer;
 
815
                                showLayer = true;
 
816
                        }
 
817
 
 
818
                        // Actor
 
819
                        if (!curDiag->Actor.IsEmpty()) {
 
820
                                dc.GetTextExtent(curDiag->Actor, &fw, &fh, NULL, NULL, &font);
 
821
                                if (fw > actorLen) actorLen = fw;
 
822
                        }
 
823
 
 
824
                        // Style
 
825
                        if (!curDiag->Style.IsEmpty()) {
 
826
                                dc.GetTextExtent(curDiag->Style, &fw, &fh, NULL, NULL, &font);
 
827
                                if (fw > styleLen) styleLen = fw;
 
828
                        }
 
829
 
 
830
                        // Effect
 
831
                        if (!curDiag->Effect.IsEmpty()) {
 
832
                                dc.GetTextExtent(curDiag->Effect, &fw, &fh, NULL, NULL, &font);
 
833
                                if (fw > effectLen) effectLen = fw;
 
834
                        }
 
835
 
 
836
                        // Margins
 
837
                        for (int j=0;j<3;j++) {
 
838
                                if (curDiag->Margin[j] != 0) showMargin[j] = true;
 
839
                        }
 
840
 
 
841
                        // Times
 
842
                        if (byFrame) {
 
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;
 
847
                        }
 
848
                }
 
849
        }
 
850
 
 
851
        // Finish layer
 
852
        dc.GetTextExtent(wxString::Format(_T("%i"),maxLayer), &fw, &fh, NULL, NULL, &font);
 
853
        int layerLen = fw + 10;
 
854
 
 
855
        // Finish times
 
856
        if (byFrame) {
 
857
                dc.GetTextExtent(wxString::Format(_T("%i"),maxStart), &fw, &fh, NULL, NULL, &font);
 
858
                startLen = fw + 10;
 
859
                dc.GetTextExtent(wxString::Format(_T("%i"),maxEnd), &fw, &fh, NULL, NULL, &font);
 
860
                endLen = fw + 10;
 
861
        }
 
862
 
 
863
        // Style length
 
864
        if (false && AssFile::top) {
 
865
                AssStyle *curStyle;
 
866
                for (entryIter curIter=AssFile::top->Line.begin();curIter!=AssFile::top->Line.end();curIter++) {
 
867
                        curStyle = AssEntry::GetAsStyle(*curIter);
 
868
                        if (curStyle) {
 
869
                                dc.GetTextExtent(curStyle->name, &fw, &fh, NULL, NULL, &font);
 
870
                                if (fw > styleLen) styleLen = fw;
 
871
                        }
 
872
                }
 
873
        }
 
874
 
 
875
        // Finish actor/effect/style
 
876
        if (actorLen) actorLen += 10;
 
877
        if (effectLen) effectLen += 10;
 
878
        if (styleLen) styleLen += 10;
 
879
 
 
880
        // Set column widths
 
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;
 
889
 
 
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);
 
894
                fw += 10;
 
895
                if (colWidth[i] > 0 && fw > colWidth[i])
 
896
                        colWidth[i] = fw;
 
897
        }
 
898
 
 
899
        // Hide columns
 
900
        for (int i=0;i<10;i++) {
 
901
                if (showCol[i] == false) colWidth[i] = 0;
 
902
        }
 
903
 
 
904
        // Set size of last
 
905
        int total = 0;
 
906
        for (int i=0;i<10;i++) total+= colWidth[i];
 
907
        colWidth[10] = w-total;
 
908
}
 
909
 
 
910
 
 
911
//////////////////////////
 
912
// Gets dialogue from map
 
913
AssDialogue *BaseGrid::GetDialogue(int n) {
 
914
        try {
 
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);
 
919
        }
 
920
        catch (...) {
 
921
                return NULL;
 
922
        }
 
923
}
 
924
 
 
925
 
 
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;
 
933
        return false;
 
934
}
 
935
 
 
936
 
 
937
///////////////
 
938
// Update maps
 
939
void BaseGrid::UpdateMaps() {
 
940
        // Store old
 
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]);
 
947
        }
 
948
 
 
949
        // Clear old
 
950
        diagPtrMap.clear();
 
951
        diagMap.clear();
 
952
        selMap.clear();
 
953
        
 
954
        // Re-generate lines
 
955
        int n = 0;
 
956
        AssDialogue *curdiag;
 
957
        for (entryIter cur=AssFile::top->Line.begin();cur != AssFile::top->Line.end();cur++) {
 
958
                curdiag = AssEntry::GetAsDialogue(*cur);
 
959
                if (curdiag) {
 
960
                        // Find old pos
 
961
                        bool sel = false;
 
962
                        for (int i=0;i<len;i++) {
 
963
                                if (tmpDiagPtrMap[i] == curdiag) {
 
964
                                        sel = tmpSelMap[i];
 
965
                                        break;
 
966
                                }
 
967
                        }
 
968
 
 
969
                        // Add new
 
970
                        diagMap.push_back(cur);
 
971
                        diagPtrMap.push_back(curdiag);
 
972
                        selMap.push_back(sel);
 
973
 
 
974
                        n++;
 
975
                }
 
976
        }
 
977
 
 
978
        // Refresh
 
979
        Refresh(false);
 
980
}
 
981
 
 
982
 
 
983
/////////////
 
984
// Key press
 
985
void BaseGrid::OnKeyPress(wxKeyEvent &event) {
 
986
        // Get size
 
987
        int w,h;
 
988
        GetClientSize(&w,&h);
 
989
 
 
990
        // Get scan code
 
991
        int key = event.GetKeyCode();
 
992
#ifdef __APPLE__
 
993
        bool ctrl = event.m_metaDown;
 
994
#else
 
995
        bool ctrl = event.m_controlDown;
 
996
#endif
 
997
        bool alt = event.m_altDown;
 
998
        bool shift = event.m_shiftDown;
 
999
 
 
1000
        // The "menu" key, simulate a right-click
 
1001
        if (key == WXK_MENU || key == WXK_WINDOWS_MENU) {
 
1002
                wxPoint pos;
 
1003
                pos.x = colWidth[0];
 
1004
                if (shift) {
 
1005
                        pos.y = lineHeight/2;
 
1006
                        OnPopupMenu(true, pos);
 
1007
                }
 
1008
                else {
 
1009
                        pos.y = (editBox->linen+1-yPos) * lineHeight + lineHeight/2;
 
1010
                        OnPopupMenu(false, pos);
 
1011
                }
 
1012
                return;
 
1013
        }
 
1014
 
 
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);
 
1021
#else 
 
1022
                        parentFrame->videoBox->videoSlider->AddPendingEvent(event);
 
1023
#endif
 
1024
                        return;
 
1025
                }
 
1026
                event.Skip();
 
1027
                return;
 
1028
        }
 
1029
 
 
1030
        // Select all
 
1031
        if (key == 'A' && ctrl && !alt && !shift) {
 
1032
                int rows = GetRows();
 
1033
                for (int i=0;i<rows;i++) SelectRow(i,true);
 
1034
        }
 
1035
 
 
1036
        // Up/down
 
1037
        int dir = 0;
 
1038
        int step = 1;
 
1039
        if (key == WXK_UP) dir = -1;
 
1040
        if (key == WXK_DOWN) dir = 1;
 
1041
        if (key == WXK_PAGEUP) {
 
1042
                dir = -1;
 
1043
                step = h/lineHeight - 2;
 
1044
        }
 
1045
        if (key == WXK_PAGEDOWN) {
 
1046
                dir = 1;
 
1047
                step = h/lineHeight - 2;
 
1048
        }
 
1049
        if (key == WXK_HOME) {
 
1050
                dir = -1;
 
1051
                step = GetRows();
 
1052
        }
 
1053
        if (key == WXK_END) {
 
1054
                dir = 1;
 
1055
                step = GetRows();
 
1056
        }
 
1057
 
 
1058
        // Moving
 
1059
        if (dir) {
 
1060
                // Move selection
 
1061
                if (!ctrl && !shift && !alt) {
 
1062
                        // Move to extent first
 
1063
                        int curLine = editBox->linen;
 
1064
                        if (extendRow != -1) {
 
1065
                                curLine = extendRow;
 
1066
                                extendRow = -1;
 
1067
                        }
 
1068
 
 
1069
                        int next = MID(0,curLine+dir*step,GetRows()-1);
 
1070
                        editBox->SetToLine(next);
 
1071
                        SelectRow(next);
 
1072
                        MakeCellVisible(next,0,false);
 
1073
                        return;
 
1074
                }
 
1075
 
 
1076
                // Move active only
 
1077
                if (alt && !shift && !ctrl) {
 
1078
                        extendRow = -1;
 
1079
                        int next = MID(0,editBox->linen+dir*step,GetRows()-1);
 
1080
                        editBox->SetToLine(next);
 
1081
                        Refresh(false);
 
1082
                        MakeCellVisible(next,0,false);
 
1083
                        return;
 
1084
                }
 
1085
 
 
1086
                // Shift-selection
 
1087
                if (shift && !ctrl && !alt) {
 
1088
                        // Find end
 
1089
                        if (extendRow == -1) extendRow = editBox->linen;
 
1090
                        extendRow = MID(0,extendRow+dir*step,GetRows()-1);
 
1091
 
 
1092
                        // Set range
 
1093
                        int i1 = editBox->linen;
 
1094
                        int i2 = extendRow;
 
1095
                        if (i2 < i1) {
 
1096
                                int aux = i1;
 
1097
                                i1 = i2;
 
1098
                                i2 = aux;
 
1099
                        }
 
1100
 
 
1101
                        // Select range
 
1102
                        ClearSelection();
 
1103
                        for (int i=i1;i<=i2;i++) {
 
1104
                                SelectRow(i,true);
 
1105
                        }
 
1106
 
 
1107
                        MakeCellVisible(extendRow,0,false);
 
1108
                        return;
 
1109
                }
 
1110
        }
 
1111
 
 
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);
 
1116
#else
 
1117
                VideoContext::Get()->audio->AddPendingEvent(event);
 
1118
#endif
 
1119
        }
 
1120
        else event.Skip();
 
1121
}
 
1122
 
 
1123
 
 
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;
 
1129
        byFrame = state;
 
1130
        SetColumnWidths();
 
1131
        Refresh(false);
 
1132
}
 
1133
 
 
1134
 
 
1135
///////////////////////////////////////////////
 
1136
// Generates an array covering inclusive range
 
1137
wxArrayInt BaseGrid::GetRangeArray(int n1,int n2) {
 
1138
        // Swap if in wrong order
 
1139
        if (n2 < n1) {
 
1140
                int aux = n1;
 
1141
                n1 = n2;
 
1142
                n2 = aux;
 
1143
        }
 
1144
 
 
1145
        // Generate array
 
1146
        wxArrayInt target;
 
1147
        for (int i=n1;i<=n2;i++) {
 
1148
                target.Add(i);
 
1149
        }
 
1150
        return target;
 
1151
}