Mostly rewrite the screen dropper code

Eliminate a lot of the platform-specific code by just using the portable
versions everywhere, and use CoreGraphics rather than wxScreenDC to grab
an image of the screen on OS X as wxScreenDC doesn't actually work on
10.6+.

Originally committed to SVN as r6898.
This commit is contained in:
Thomas Goyne 2012-06-12 03:13:55 +00:00
parent 82d955ba96
commit 2db20778fc
1 changed files with 43 additions and 52 deletions

View File

@ -75,6 +75,10 @@
#include "persist_location.h" #include "persist_location.h"
#include "utils.h" #include "utils.h"
#ifdef __WXMAC__
#include <ApplicationServices/ApplicationServices.h>
#endif
/// DOCME /// DOCME
/// @class ColorPickerSpectrum /// @class ColorPickerSpectrum
/// @brief DOCME /// @brief DOCME
@ -541,6 +545,7 @@ void ColorPickerRecent::OnSize(wxSizeEvent &)
ColorPickerScreenDropper::ColorPickerScreenDropper(wxWindow *parent, int resx, int resy, int magnification) ColorPickerScreenDropper::ColorPickerScreenDropper(wxWindow *parent, int resx, int resy, int magnification)
: wxControl(parent, -1, wxDefaultPosition, wxDefaultSize, STATIC_BORDER_FLAG) : wxControl(parent, -1, wxDefaultPosition, wxDefaultSize, STATIC_BORDER_FLAG)
, capture(resx * magnification, resy * magnification)
, resx(resx) , resx(resx)
, resy(resy) , resy(resy)
, magnification(magnification) , magnification(magnification)
@ -550,12 +555,10 @@ ColorPickerScreenDropper::ColorPickerScreenDropper(wxWindow *parent, int resx, i
SetMaxSize(GetSize()); SetMaxSize(GetSize());
SetCursor(*wxCROSS_CURSOR); SetCursor(*wxCROSS_CURSOR);
capture = wxBitmap(resx, resy); wxMemoryDC capdc(capture);
wxMemoryDC capdc;
capdc.SelectObject(capture);
capdc.SetPen(*wxTRANSPARENT_PEN); capdc.SetPen(*wxTRANSPARENT_PEN);
capdc.SetBrush(*wxWHITE_BRUSH); capdc.SetBrush(*wxWHITE_BRUSH);
capdc.DrawRectangle(0, 0, resx, resy); capdc.DrawRectangle(0, 0, capture.GetWidth(), capture.GetHeight());
Bind(wxEVT_PAINT, &ColorPickerScreenDropper::OnPaint, this); Bind(wxEVT_PAINT, &ColorPickerScreenDropper::OnPaint, this);
Bind(wxEVT_LEFT_DOWN, &ColorPickerScreenDropper::OnMouse, this); Bind(wxEVT_LEFT_DOWN, &ColorPickerScreenDropper::OnMouse, this);
@ -565,23 +568,14 @@ wxDEFINE_EVENT(EVT_DROPPER_SELECT, wxCommandEvent);
void ColorPickerScreenDropper::OnMouse(wxMouseEvent &evt) void ColorPickerScreenDropper::OnMouse(wxMouseEvent &evt)
{ {
int x = evt.GetX() / magnification; int x = evt.GetX();
int y = evt.GetY() / magnification; int y = evt.GetY();
if (x >= 0 && x < capture.GetWidth() && y >= 0 && y < capture.GetHeight()) {
wxNativePixelData pd(capture, wxRect(x, y, 1, 1));
wxNativePixelData::Iterator pdi(pd.GetPixels());
wxColour color(pdi.Red(), pdi.Green(), pdi.Blue(), wxALPHA_OPAQUE);
if (x >= 0 && y >= 0 && x < resx && y < resy) {
wxColour color;
#ifdef __WXMAC__
// wxMemoryDC::GetPixel() isn't implemented on OS X
// Work around it by reading pixel data from the bitmap instead
wxAlphaPixelData cappd(capture);
wxAlphaPixelData::Iterator cappdi(cappd);
cappdi.MoveTo(cappd, x, y);
color.Set(cappdi.Red(), cappdi.Green(), cappdi.Blue());
#else
wxMemoryDC capdc(capture);
capdc.GetPixel(x, y, &color);
#endif
color = wxColour(color.Red(), color.Green(), color.Blue(), wxALPHA_OPAQUE);
wxCommandEvent evnt(EVT_DROPPER_SELECT, GetId()); wxCommandEvent evnt(EVT_DROPPER_SELECT, GetId());
evnt.SetString(AssColor(color).GetASSFormatted(false, false, false)); evnt.SetString(AssColor(color).GetASSFormatted(false, false, false));
AddPendingEvent(evnt); AddPendingEvent(evnt);
@ -590,45 +584,42 @@ void ColorPickerScreenDropper::OnMouse(wxMouseEvent &evt)
void ColorPickerScreenDropper::OnPaint(wxPaintEvent &) void ColorPickerScreenDropper::OnPaint(wxPaintEvent &)
{ {
wxPaintDC pdc(this); wxPaintDC(this).DrawBitmap(capture, 0, 0);
#ifdef __WXMAC__
// See OnMouse() above
wxAlphaPixelData cappd(capture);
wxAlphaPixelData::Iterator cappdi(cappd);
#else
wxMemoryDC capdc(capture);
#endif
pdc.SetPen(*wxTRANSPARENT_PEN);
for (int x = 0; x < resx; x++) {
for (int y = 0; y < resy; y++) {
wxColour color;
#ifdef __WXMAC__
cappdi.MoveTo(cappd, x, y);
color.Set(cappdi.Red(), cappdi.Green(), cappdi.Blue());
#else
capdc.GetPixel(x, y, &color);
#endif
pdc.SetBrush(wxBrush(color));
pdc.DrawRectangle(x*magnification, y*magnification, magnification, magnification);
}
}
} }
void ColorPickerScreenDropper::DropFromScreenXY(int x, int y) void ColorPickerScreenDropper::DropFromScreenXY(int x, int y)
{ {
wxMemoryDC capdc(capture); wxMemoryDC capdc(capture);
capdc.SetPen(*wxTRANSPARENT_PEN);
#ifndef __WXMAC__
wxScreenDC screen; wxScreenDC screen;
capdc.StretchBlit(0, 0, resx * magnification, resy * magnification,
#ifdef __WXMAC__ &screen, x - resx / 2, y - resy / 2, resx, resy);
wxBitmap screenbmp = screen.GetAsBitmap().GetSubBitmap(wxRect(x-resx/2, y-resy/2, resx, resy));
capdc.DrawBitmap(screenbmp, 0, 0);
#else #else
screen.StartDrawingOnTop(); // wxScreenDC doesn't work on recent versions of OS X so do it manually
capdc.Blit(0, 0, resx, resy, &screen, x-resx/2, y-resy/2);
screen.EndDrawingOnTop(); // Doesn't bother handling the case where the rect overlaps two monitors
CGDirectDisplayID display_id;
uint32_t display_count;
CGGetDisplaysWithPoint(CGPointMake(x, y), 1, &display_id, &display_count);
agi::scoped_holder<CGImageRef> img(CGDisplayCreateImageForRect(display_id, CGRectMake(x - resx / 2, y - resy / 2, resx, resy)), CGImageRelease);
NSUInteger width = CGImageGetWidth(img);
NSUInteger height = CGImageGetHeight(img);
std::vector<uint8_t> imgdata(height * width * 4);
agi::scoped_holder<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB(), CGColorSpaceRelease);
agi::scoped_holder<CGContextRef> bmp_context(CGBitmapContextCreate(&imgdata[0], width, height, 8, 4 * width, colorspace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big), CGContextRelease);
CGContextDrawImage(bmp_context, CGRectMake(0, 0, width, height), img);
for (int x = 0; x < resx; x++) {
for (int y = 0; y < resy; y++) {
uint8_t *pixel = &imgdata[y * width * 4 + x * 4];
capdc.SetBrush(wxBrush(wxColour(pixel[0], pixel[1], pixel[2])));
capdc.DrawRectangle(x * magnification, y * magnification, magnification, magnification);
}
}
#endif #endif
Refresh(false); Refresh(false);