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

« back to all changes in this revision

Viewing changes to src/video_display.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) 2005-2007, 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 <wx/glcanvas.h>
 
42
#ifdef __APPLE__
 
43
#include <OpenGL/GL.h>
 
44
#include <OpenGL/glu.h>
 
45
#else
 
46
#include <GL/gl.h>
 
47
#include <GL/glu.h>
 
48
#endif
 
49
#include <wx/image.h>
 
50
#include <string.h>
 
51
#include <wx/clipbrd.h>
 
52
#include <wx/filename.h>
 
53
#include <wx/config.h>
 
54
#include "utils.h"
 
55
#include "video_display.h"
 
56
#include "video_provider_manager.h"
 
57
#include "vfr.h"
 
58
#include "ass_file.h"
 
59
#include "ass_time.h"
 
60
#include "ass_dialogue.h"
 
61
#include "ass_style.h"
 
62
#include "subs_grid.h"
 
63
#include "vfw_wrap.h"
 
64
#include "mkv_wrap.h"
 
65
#include "options.h"
 
66
#include "utils.h"
 
67
#include "video_out_gl.h"
 
68
#include "vfr.h"
 
69
#include "video_box.h"
 
70
#include "gl_wrap.h"
 
71
#include "video_slider.h"
 
72
#include "visual_tool.h"
 
73
#include "visual_tool_cross.h"
 
74
#include "visual_tool_rotatez.h"
 
75
#include "visual_tool_rotatexy.h"
 
76
#include "visual_tool_scale.h"
 
77
#include "visual_tool_clip.h"
 
78
#include "visual_tool_vector_clip.h"
 
79
#include "visual_tool_drag.h"
 
80
 
 
81
 
 
82
///////
 
83
// IDs
 
84
enum {
 
85
        VIDEO_MENU_COPY_COORDS = 1230,
 
86
        VIDEO_MENU_COPY_TO_CLIPBOARD,
 
87
        VIDEO_MENU_COPY_TO_CLIPBOARD_RAW,
 
88
        VIDEO_MENU_SAVE_SNAPSHOT,
 
89
        VIDEO_MENU_SAVE_SNAPSHOT_RAW
 
90
};
 
91
 
 
92
 
 
93
///////////////
 
94
// Event table
 
95
BEGIN_EVENT_TABLE(VideoDisplay, wxGLCanvas)
 
96
        EVT_MOUSE_EVENTS(VideoDisplay::OnMouseEvent)
 
97
        EVT_KEY_DOWN(VideoDisplay::OnKey)
 
98
        EVT_PAINT(VideoDisplay::OnPaint)
 
99
        EVT_SIZE(VideoDisplay::OnSizeEvent)
 
100
        EVT_ERASE_BACKGROUND(VideoDisplay::OnEraseBackground)
 
101
 
 
102
        EVT_MENU(VIDEO_MENU_COPY_COORDS,VideoDisplay::OnCopyCoords)
 
103
        EVT_MENU(VIDEO_MENU_COPY_TO_CLIPBOARD,VideoDisplay::OnCopyToClipboard)
 
104
        EVT_MENU(VIDEO_MENU_SAVE_SNAPSHOT,VideoDisplay::OnSaveSnapshot)
 
105
        EVT_MENU(VIDEO_MENU_COPY_TO_CLIPBOARD_RAW,VideoDisplay::OnCopyToClipboardRaw)
 
106
        EVT_MENU(VIDEO_MENU_SAVE_SNAPSHOT_RAW,VideoDisplay::OnSaveSnapshotRaw)
 
107
END_EVENT_TABLE()
 
108
 
 
109
 
 
110
//////////////
 
111
// Parameters
 
112
int attribList[] = {
 
113
        WX_GL_RGBA,
 
114
        WX_GL_DOUBLEBUFFER,
 
115
        WX_GL_STENCIL_SIZE, 8,  // stencil buffer is needed for the shape overlay drawing stuff
 
116
        WX_GL_MIN_RED,      8,  // wx implementation thing:
 
117
        WX_GL_MIN_GREEN,    8,  // wxMSW sets pfd.cColorBits to 0 if given an attribList
 
118
        WX_GL_MIN_BLUE,     8,  // where none of WX_GL_MIN_(RED|GREEN|BLUE) or WX_GL_BUFFER_SIZE are set.
 
119
        WX_GL_BUFFER_SIZE, 24,  // WX_GL_BUFFER_SIZE must be set last or it will get a nonsense value.
 
120
        0
 
121
};
 
122
 
 
123
///////////////
 
124
// Constructor
 
125
VideoDisplay::VideoDisplay(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
 
126
: wxGLCanvas (parent, id, attribList, pos, size, style, name)
 
127
, videoOut(new VideoOutGL())
 
128
{
 
129
        // Set options
 
130
        box = NULL;
 
131
        locked = false;
 
132
        ControlSlider = NULL;
 
133
        PositionDisplay = NULL;
 
134
        w=h=dx2=dy2=8;
 
135
        dx1=dy1=0;
 
136
        origSize = size;
 
137
        zoomValue = 1.0;
 
138
        freeSize = false;
 
139
        visual = NULL;
 
140
        SetCursor(wxNullCursor);
 
141
        visualMode = -1;
 
142
        SetVisualMode(0);
 
143
}
 
144
 
 
145
 
 
146
//////////////
 
147
// Destructor
 
148
VideoDisplay::~VideoDisplay () {
 
149
        delete visual;
 
150
        visual = NULL;
 
151
        VideoContext::Get()->RemoveDisplay(this);
 
152
}
 
153
 
 
154
 
 
155
///////////////
 
156
// Show cursor
 
157
void VideoDisplay::ShowCursor(bool show) {
 
158
        // Show
 
159
        if (show) SetCursor(wxNullCursor);
 
160
 
 
161
        // Hide
 
162
        else {
 
163
                // Bleeeh! Hate this 'solution':
 
164
                #if __WXGTK__
 
165
                static char cursor_image[] = {0};
 
166
                wxCursor cursor(cursor_image, 8, 1, -1, -1, cursor_image);
 
167
                #else
 
168
                wxCursor cursor(wxCURSOR_BLANK);
 
169
                #endif // __WXGTK__
 
170
                SetCursor(cursor);
 
171
        }
 
172
}
 
173
 
 
174
void VideoDisplay::SetFrame(int frameNumber) {
 
175
        VideoContext *context = VideoContext::Get();
 
176
        ControlSlider->SetValue(frameNumber);
 
177
 
 
178
        // Get time for frame
 
179
        int time = VFR_Output.GetTimeAtFrame(frameNumber, true, true);
 
180
        int h = time / 3600000;
 
181
        int m = time % 3600000 / 60000;
 
182
        int s = time % 60000 / 1000;
 
183
        int ms = time % 1000;
 
184
 
 
185
        // Set the text box for frame number and time
 
186
        PositionDisplay->SetValue(wxString::Format(_T("%01i:%02i:%02i.%03i - %i"), h, m, s, ms, frameNumber));
 
187
        if (context->GetKeyFrames().Index(frameNumber) != wxNOT_FOUND) {
 
188
                // Set the background color to indicate this is a keyframe
 
189
                PositionDisplay->SetBackgroundColour(Options.AsColour(_T("Grid selection background")));
 
190
                PositionDisplay->SetForegroundColour(Options.AsColour(_T("Grid selection foreground")));
 
191
        }
 
192
        else {
 
193
                PositionDisplay->SetBackgroundColour(wxNullColour);
 
194
                PositionDisplay->SetForegroundColour(wxNullColour);
 
195
        }
 
196
 
 
197
        wxString startSign;
 
198
        wxString endSign;
 
199
        int startOff = 0;
 
200
        int endOff = 0;
 
201
 
 
202
        if (AssDialogue *curLine = context->curLine) {
 
203
                startOff = time - curLine->Start.GetMS();
 
204
                endOff = time - curLine->End.GetMS();
 
205
        }
 
206
 
 
207
        // Positive signs
 
208
        if (startOff > 0) startSign = _T("+");
 
209
        if (endOff > 0) endSign = _T("+");
 
210
 
 
211
        // Set the text box for time relative to active subtitle line
 
212
        SubsPosition->SetValue(wxString::Format(_T("%s%ims; %s%ims"), startSign.c_str(), startOff, endSign.c_str(), endOff));
 
213
 
 
214
        if (IsShownOnScreen() && visual) visual->Refresh();
 
215
 
 
216
        // Render the new frame
 
217
        if (context->IsLoaded()) {
 
218
                AegiVideoFrame frame;
 
219
                try {
 
220
                        frame = context->GetFrame(frameNumber);
 
221
                }
 
222
                catch (const wxChar *err) {
 
223
                        wxLogError(
 
224
                                _T("Failed seeking video. The video file may be corrupt or incomplete.\n")
 
225
                                _T("Error message reported: %s"),
 
226
                                err);
 
227
                }
 
228
                catch (wxString err) {
 
229
                        wxLogError(
 
230
                                _T("Failed seeking video. The video file may be corrupt or incomplete.\n")
 
231
                                _T("Error message reported: %s"),
 
232
                                err.c_str());
 
233
                }
 
234
                catch (...) {
 
235
                        wxLogError(
 
236
                                _T("Failed seeking video. The video file may be corrupt or incomplete.\n")
 
237
                                _T("No further error message given."));
 
238
                }
 
239
                try {
 
240
                        videoOut->UploadFrameData(frame);
 
241
                }
 
242
                catch (const VideoOutInitException& err) {
 
243
                        wxLogError(
 
244
                                L"Failed to initialize video display. Closing other running programs and updating your video card drivers may fix this.\n"
 
245
                                L"Error message reported: %s",
 
246
                                err.GetMessage().c_str());
 
247
                        context->Reset();
 
248
                }
 
249
                catch (const VideoOutRenderException& err) {
 
250
                        wxLogError(
 
251
                                L"Could not upload video frame to graphics card.\n"
 
252
                                L"Error message reported: %s",
 
253
                                err.GetMessage().c_str());
 
254
                }
 
255
        }
 
256
        Render();
 
257
 
 
258
        currentFrame = frameNumber;
 
259
}
 
260
 
 
261
//////////
 
262
// Render
 
263
void VideoDisplay::Render() try {
 
264
        if (!IsShownOnScreen()) return;
 
265
        wxASSERT(wxIsMainThread());
 
266
 
 
267
        VideoContext *context = VideoContext::Get();
 
268
        wxASSERT(context);
 
269
        if (!context->IsLoaded()) return;
 
270
 
 
271
        // Set GL context
 
272
        SetCurrent(*context->GetGLContext(this));
 
273
 
 
274
        // Get sizes
 
275
        int w, h, sw, sh, pw, ph;
 
276
        GetClientSize(&w, &h);
 
277
        wxASSERT(w > 0);
 
278
        wxASSERT(h > 0);
 
279
        context->GetScriptSize(sw, sh);
 
280
        pw = context->GetWidth();
 
281
        ph = context->GetHeight();
 
282
        wxASSERT(pw > 0);
 
283
        wxASSERT(ph > 0);
 
284
 
 
285
        // Freesized transform
 
286
        dx1 = 0;
 
287
        dy1 = 0;
 
288
        dx2 = w;
 
289
        dy2 = h;
 
290
        if (freeSize) {
 
291
                // Set aspect ratio
 
292
                float thisAr = float(w)/float(h);
 
293
                float vidAr = context->GetAspectRatioType() == 0 ? float(pw)/float(ph) : context->GetAspectRatioValue();
 
294
 
 
295
                // Window is wider than video, blackbox left/right
 
296
                if (thisAr - vidAr > 0.01f) {
 
297
                        int delta = int(w-vidAr*h);
 
298
                        dx1 += delta/2;
 
299
                        dx2 -= delta;
 
300
                }
 
301
 
 
302
                // Video is wider than window, blackbox top/bottom
 
303
                else if (vidAr - thisAr > 0.01f) {
 
304
                        int delta = int(h-w/vidAr);
 
305
                        dy1 += delta/2;
 
306
                        dy2 -= delta;
 
307
                }
 
308
        }
 
309
 
 
310
        videoOut->SetViewport(dx1, dy1, dx2, dy2);
 
311
        videoOut->Render(sw, sh);
 
312
 
 
313
        DrawTVEffects();
 
314
 
 
315
        if (!context->IsPlaying())
 
316
                visual->Draw();
 
317
        else
 
318
                ShowCursor(true);
 
319
 
 
320
        glFinish();
 
321
        SwapBuffers();
 
322
}
 
323
catch (const VideoOutException &err) {
 
324
        wxLogError(
 
325
                _T("An error occurred trying to render the video frame on the screen.\n")
 
326
                _T("Error message reported: %s"),
 
327
                err.GetMessage().c_str());
 
328
        VideoContext::Get()->Reset();
 
329
}
 
330
catch (...) {
 
331
        wxLogError(
 
332
                _T("An error occurred trying to render the video frame to screen.\n")
 
333
                _T("No further error message given."));
 
334
        VideoContext::Get()->Reset();
 
335
}
 
336
 
 
337
 
 
338
///////////////////////////////////
 
339
// TV effects (overscan and so on)
 
340
void VideoDisplay::DrawTVEffects() {
 
341
        // Get coordinates
 
342
        int sw,sh;
 
343
        VideoContext *context = VideoContext::Get();
 
344
        context->GetScriptSize(sw,sh);
 
345
        bool drawOverscan = Options.AsBool(_T("Show Overscan Mask"));
 
346
 
 
347
        // Draw overscan mask
 
348
        if (drawOverscan) {
 
349
                // Get aspect ration
 
350
                double ar = context->GetAspectRatioValue();
 
351
 
 
352
                // Based on BBC's guidelines: http://www.bbc.co.uk/guidelines/dq/pdf/tv/tv_standards_london.pdf
 
353
                // 16:9 or wider
 
354
                if (ar > 1.75) {
 
355
                        DrawOverscanMask(int(sw * 0.1),int(sh * 0.05),wxColour(30,70,200),0.5);
 
356
                        DrawOverscanMask(int(sw * 0.035),int(sh * 0.035),wxColour(30,70,200),0.5);
 
357
                }
 
358
 
 
359
                // Less wide than 16:9 (use 4:3 standard)
 
360
                else {
 
361
                        DrawOverscanMask(int(sw * 0.067),int(sh * 0.05),wxColour(30,70,200),0.5);
 
362
                        DrawOverscanMask(int(sw * 0.033),int(sh * 0.035),wxColour(30,70,200),0.5);
 
363
                }
 
364
        }
 
365
}
 
366
 
 
367
 
 
368
//////////////////////
 
369
// Draw overscan mask
 
370
void VideoDisplay::DrawOverscanMask(int sizeH,int sizeV,wxColour colour,double alpha) {
 
371
        // Parameters
 
372
        int sw,sh;
 
373
        VideoContext *context = VideoContext::Get();
 
374
        context->GetScriptSize(sw,sh);
 
375
        int rad1 = int(sh * 0.05);
 
376
        int gapH = sizeH+rad1;
 
377
        int gapV = sizeV+rad1;
 
378
        int rad2 = (int)sqrt(double(gapH*gapH + gapV*gapV))+1;
 
379
 
 
380
        // Set up GL wrapper
 
381
        OpenGLWrapper gl;
 
382
        gl.SetFillColour(colour,alpha);
 
383
        gl.SetLineColour(wxColour(0,0,0),0.0,1);
 
384
 
 
385
        // Draw rectangles
 
386
        gl.DrawRectangle(gapH,0,sw-gapH,sizeV);         // Top
 
387
        gl.DrawRectangle(sw-sizeH,gapV,sw,sh-gapV);     // Right
 
388
        gl.DrawRectangle(gapH,sh-sizeV,sw-gapH,sh);     // Bottom
 
389
        gl.DrawRectangle(0,gapV,sizeH,sh-gapV);         // Left
 
390
 
 
391
        // Draw corners
 
392
        gl.DrawRing(gapH,gapV,rad1,rad2,1.0,180.0,270.0);               // Top-left
 
393
        gl.DrawRing(sw-gapH,gapV,rad1,rad2,1.0,90.0,180.0);             // Top-right
 
394
        gl.DrawRing(sw-gapH,sh-gapV,rad1,rad2,1.0,0.0,90.0);    // Bottom-right
 
395
        gl.DrawRing(gapH,sh-gapV,rad1,rad2,1.0,270.0,360.0);    // Bottom-left
 
396
 
 
397
        // Done
 
398
        glDisable(GL_BLEND);
 
399
}
 
400
 
 
401
 
 
402
///////////////
 
403
// Update size
 
404
void VideoDisplay::UpdateSize() {
 
405
        // Don't do anything if it's a free sizing display
 
406
        //if (freeSize) return;
 
407
 
 
408
        VideoContext *con = VideoContext::Get();
 
409
        wxASSERT(con);
 
410
        if (!con->IsLoaded()) return;
 
411
        if (!IsShownOnScreen()) return;
 
412
 
 
413
        if (freeSize) {
 
414
                GetClientSize(&w,&h);
 
415
        }
 
416
        else {
 
417
                if (con->GetAspectRatioType() == 0) w = int(con->GetWidth() * zoomValue);
 
418
                else w = int(con->GetHeight() * zoomValue * con->GetAspectRatioValue());
 
419
                h = int(con->GetHeight() * zoomValue);
 
420
 
 
421
                // Set Min and Max sizes. This sets the outer size, not client size, so it
 
422
                // depends on us not having any borders on the control.
 
423
                wxSize size(w,h);
 
424
                SetMinSize(size);
 
425
                SetMaxSize(size);
 
426
 
 
427
                // Then tell the sizer to re-fit for us.
 
428
                locked = true;
 
429
                box->VideoSizer->Fit(box);
 
430
                box->GetParent()->Layout();
 
431
 
 
432
                // And finally properly resize to the wanted size, to avoid a glitch when
 
433
                // switching between small zoom levels on Windows.
 
434
                SetSize(w,h);
 
435
 
 
436
                locked = false;
 
437
        }
 
438
        Refresh(false);
 
439
}
 
440
 
 
441
 
 
442
//////////
 
443
// Resets
 
444
void VideoDisplay::Reset() {
 
445
        // Only calculate sizes if it's visible
 
446
        if (!IsShownOnScreen()) return;
 
447
        int w = origSize.GetX();
 
448
        int h = origSize.GetY();
 
449
        wxASSERT(w > 0);
 
450
        wxASSERT(h > 0);
 
451
        SetClientSize(w,h);
 
452
        int _w,_h;
 
453
        GetSize(&_w,&_h);
 
454
        wxASSERT(_w > 0);
 
455
        wxASSERT(_h > 0);
 
456
        SetSizeHints(_w,_h,_w,_h);
 
457
}
 
458
 
 
459
 
 
460
///////////////
 
461
// Paint event
 
462
void VideoDisplay::OnPaint(wxPaintEvent& event) {
 
463
        wxPaintDC dc(this);
 
464
        Render();
 
465
}
 
466
 
 
467
 
 
468
//////////////
 
469
// Size Event
 
470
void VideoDisplay::OnSizeEvent(wxSizeEvent &event) {
 
471
        //Refresh(false);
 
472
        if (freeSize) {
 
473
                UpdateSize();
 
474
        }
 
475
        event.Skip();
 
476
}
 
477
 
 
478
 
 
479
///////////////
 
480
// Mouse stuff
 
481
void VideoDisplay::OnMouseEvent(wxMouseEvent& event) {
 
482
        // Locked?
 
483
        if (locked) return;
 
484
 
 
485
        // Mouse coordinates
 
486
        mouse_x = event.GetX();
 
487
        mouse_y = event.GetY();
 
488
 
 
489
        // Disable when playing
 
490
        if (VideoContext::Get()->IsPlaying()) return;
 
491
 
 
492
        // Right click
 
493
        if (event.ButtonUp(wxMOUSE_BTN_RIGHT)) {
 
494
                // Create menu
 
495
                wxMenu menu;
 
496
                menu.Append(VIDEO_MENU_SAVE_SNAPSHOT,_("Save PNG snapshot"));
 
497
                menu.Append(VIDEO_MENU_COPY_TO_CLIPBOARD,_("Copy image to Clipboard"));
 
498
                menu.AppendSeparator();
 
499
                menu.Append(VIDEO_MENU_SAVE_SNAPSHOT_RAW,_("Save PNG snapshot (no subtitles)"));
 
500
                menu.Append(VIDEO_MENU_COPY_TO_CLIPBOARD_RAW,_("Copy image to Clipboard (no subtitles)"));
 
501
                menu.AppendSeparator();
 
502
                menu.Append(VIDEO_MENU_COPY_COORDS,_("Copy coordinates to Clipboard"));
 
503
 
 
504
                // Show cursor and popup
 
505
                ShowCursor(true);
 
506
                PopupMenu(&menu);
 
507
                return;
 
508
        }
 
509
 
 
510
        // Enforce correct cursor display
 
511
        ShowCursor(visualMode != 0);
 
512
 
 
513
        // Click?
 
514
        if (event.ButtonDown(wxMOUSE_BTN_ANY)) {
 
515
                SetFocus();
 
516
        }
 
517
 
 
518
        // Send to visual
 
519
        if (visual) visual->OnMouseEvent(event);
 
520
}
 
521
 
 
522
 
 
523
/////////////
 
524
// Key event
 
525
void VideoDisplay::OnKey(wxKeyEvent &event) {
 
526
        // FIXME: should these be configurable?
 
527
        // Think of the frenchmen and other people not using qwerty layout
 
528
        if (event.GetKeyCode() == 'A') SetVisualMode(0);
 
529
        if (event.GetKeyCode() == 'S') SetVisualMode(1);
 
530
        if (event.GetKeyCode() == 'D') SetVisualMode(2);
 
531
        if (event.GetKeyCode() == 'F') SetVisualMode(3);
 
532
        if (event.GetKeyCode() == 'G') SetVisualMode(4);
 
533
        if (event.GetKeyCode() == 'H') SetVisualMode(5);
 
534
        if (event.GetKeyCode() == 'J') SetVisualMode(6);
 
535
        event.Skip();
 
536
}
 
537
 
 
538
 
 
539
 
 
540
///////////////////
 
541
// Sets zoom level
 
542
void VideoDisplay::SetZoom(double value) {
 
543
        zoomValue = value;
 
544
        UpdateSize();
 
545
}
 
546
 
 
547
 
 
548
//////////////////////
 
549
// Sets zoom position
 
550
void VideoDisplay::SetZoomPos(int value) {
 
551
        if (value < 0) value = 0;
 
552
        if (value > 15) value = 15;
 
553
        SetZoom(double(value+1)/8.0);
 
554
        if (zoomBox->GetSelection() != value) zoomBox->SetSelection(value);
 
555
}
 
556
 
 
557
/////////////////////
 
558
// Copy to clipboard
 
559
void VideoDisplay::OnCopyToClipboard(wxCommandEvent &event) {
 
560
        if (wxTheClipboard->Open()) {
 
561
                wxTheClipboard->SetData(new wxBitmapDataObject(wxBitmap(VideoContext::Get()->GetFrame(-1).GetImage(),24)));
 
562
                wxTheClipboard->Close();
 
563
        }
 
564
}
 
565
 
 
566
 
 
567
//////////////////////////
 
568
// Copy to clipboard (raw)
 
569
void VideoDisplay::OnCopyToClipboardRaw(wxCommandEvent &event) {
 
570
        if (wxTheClipboard->Open()) {
 
571
                wxTheClipboard->SetData(new wxBitmapDataObject(wxBitmap(VideoContext::Get()->GetFrame(-1,true).GetImage(),24)));
 
572
                wxTheClipboard->Close();
 
573
        }
 
574
}
 
575
 
 
576
 
 
577
/////////////////
 
578
// Save snapshot
 
579
void VideoDisplay::OnSaveSnapshot(wxCommandEvent &event) {
 
580
        VideoContext::Get()->SaveSnapshot(false);
 
581
}
 
582
 
 
583
 
 
584
//////////////////////
 
585
// Save snapshot (raw)
 
586
void VideoDisplay::OnSaveSnapshotRaw(wxCommandEvent &event) {
 
587
        VideoContext::Get()->SaveSnapshot(true);
 
588
}
 
589
 
 
590
 
 
591
/////////////////////
 
592
// Copy coordinates
 
593
void VideoDisplay::OnCopyCoords(wxCommandEvent &event) {
 
594
        if (wxTheClipboard->Open()) {
 
595
                int sw,sh;
 
596
                VideoContext::Get()->GetScriptSize(sw,sh);
 
597
                int vx = (sw * mouse_x + w/2) / w;
 
598
                int vy = (sh * mouse_y + h/2) / h;
 
599
                wxTheClipboard->SetData(new wxTextDataObject(wxString::Format(_T("%i,%i"),vx,vy)));
 
600
                wxTheClipboard->Close();
 
601
        }
 
602
}
 
603
 
 
604
 
 
605
/////////////////////////////
 
606
// Convert mouse coordinates
 
607
void VideoDisplay::ConvertMouseCoords(int &x,int &y) {
 
608
        int w,h;
 
609
        GetClientSize(&w,&h);
 
610
        wxASSERT(dx2 > 0);
 
611
        wxASSERT(dy2 > 0);
 
612
        wxASSERT(w > 0);
 
613
        wxASSERT(h > 0);
 
614
        x = (x-dx1)*w/dx2;
 
615
        y = (y-dy1)*h/dy2;
 
616
}
 
617
 
 
618
 
 
619
////////////
 
620
// Set mode
 
621
void VideoDisplay::SetVisualMode(int mode) {
 
622
        // Set visual
 
623
        if (visualMode != mode) {
 
624
                // Get toolbar
 
625
                wxToolBar *toolBar = NULL;
 
626
                if (box) {
 
627
                        toolBar = box->visualSubToolBar;
 
628
                        toolBar->ClearTools();
 
629
                        toolBar->Realize();
 
630
                        toolBar->Show(false);
 
631
                        if (!box->visualToolBar->GetToolState(mode + Video_Mode_Standard)) box->visualToolBar->ToggleTool(mode + Video_Mode_Standard,true);
 
632
                }
 
633
 
 
634
                // Replace mode
 
635
                visualMode = mode;
 
636
                delete visual;
 
637
                switch (mode) {
 
638
                        case 0: visual = new VisualToolCross(this); break;
 
639
                        case 1: visual = new VisualToolDrag(this,toolBar); break;
 
640
                        case 2: visual = new VisualToolRotateZ(this); break;
 
641
                        case 3: visual = new VisualToolRotateXY(this); break;
 
642
                        case 4: visual = new VisualToolScale(this); break;
 
643
                        case 5: visual = new VisualToolClip(this); break;
 
644
                        case 6: visual = new VisualToolVectorClip(this,toolBar); break;
 
645
                        default: visual = NULL;
 
646
                }
 
647
 
 
648
                // Update size to reflect toolbar changes
 
649
                UpdateSize();
 
650
        }
 
651
 
 
652
        // Render
 
653
        Render();
 
654
}