michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #import michael@0: michael@0: #include "nsColorPicker.h" michael@0: #include "nsCocoaUtils.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: static unsigned int michael@0: HexStrToInt(NSString* str) michael@0: { michael@0: unsigned int result = 0; michael@0: michael@0: for (unsigned int i = 0; i < [str length]; ++i) { michael@0: char c = [str characterAtIndex:i]; michael@0: result *= 16; michael@0: if (c >= '0' && c <= '9') { michael@0: result += c - '0'; michael@0: } else if (c >= 'A' && c <= 'F') { michael@0: result += 10 + (c - 'A'); michael@0: } else { michael@0: result += 10 + (c - 'a'); michael@0: } michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: @interface NSColorPanelWrapper : NSObject michael@0: { michael@0: NSColorPanel* mColorPanel; michael@0: nsColorPicker* mColorPicker; michael@0: } michael@0: - (id)initWithPicker:(nsColorPicker*)aPicker; michael@0: - (void)open:(NSColor*)aInitialColor title:(NSString*)aTitle; michael@0: - (void)retarget:(nsColorPicker*)aPicker; michael@0: - (void)colorChanged:(NSColorPanel*)aPanel; michael@0: @end michael@0: michael@0: @implementation NSColorPanelWrapper michael@0: - (id)initWithPicker:(nsColorPicker*)aPicker michael@0: { michael@0: mColorPicker = aPicker; michael@0: mColorPanel = [NSColorPanel sharedColorPanel]; michael@0: michael@0: self = [super init]; michael@0: return self; michael@0: } michael@0: michael@0: - (void)open:(NSColor*)aInitialColor title:(NSString*)aTitle michael@0: { michael@0: [mColorPanel setTitle:aTitle]; michael@0: [mColorPanel setColor:aInitialColor]; michael@0: [mColorPanel setTarget:self]; michael@0: [mColorPanel setAction:@selector(colorChanged:)]; michael@0: [mColorPanel setDelegate:self]; michael@0: [mColorPanel makeKeyAndOrderFront:nil]; michael@0: } michael@0: michael@0: - (void)colorChanged:(NSColorPanel*)aPanel michael@0: { michael@0: mColorPicker->Update([mColorPanel color]); michael@0: } michael@0: michael@0: - (void)windowWillClose:(NSNotification*)aNotification michael@0: { michael@0: mColorPicker->Done(); michael@0: } michael@0: michael@0: - (void)retarget:(nsColorPicker*)aPicker michael@0: { michael@0: mColorPicker->DoneWithRetarget(); michael@0: mColorPicker = aPicker; michael@0: } michael@0: michael@0: - (void)dealloc michael@0: { michael@0: if ([mColorPanel delegate] == self) { michael@0: [mColorPanel setTarget:nil]; michael@0: [mColorPanel setAction:nil]; michael@0: [mColorPanel setDelegate:nil]; michael@0: } michael@0: michael@0: mColorPanel = nil; michael@0: mColorPicker = nullptr; michael@0: michael@0: [super dealloc]; michael@0: } michael@0: @end michael@0: michael@0: NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker) michael@0: michael@0: NSColorPanelWrapper* nsColorPicker::sColorPanelWrapper = nullptr; michael@0: michael@0: NS_IMETHODIMP michael@0: nsColorPicker::Init(nsIDOMWindow* aParent, const nsAString& aTitle, michael@0: const nsAString& aInitialColor) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), michael@0: "Color pickers can only be opened from main thread currently"); michael@0: mTitle = aTitle; michael@0: mColor = aInitialColor; michael@0: michael@0: if (sColorPanelWrapper) { michael@0: // Update current wrapper to target the new input instead michael@0: [sColorPanelWrapper retarget:this]; michael@0: } else { michael@0: // Create a brand new color panel wrapper michael@0: sColorPanelWrapper = [[NSColorPanelWrapper alloc] initWithPicker:this]; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* static */ NSColor* michael@0: nsColorPicker::GetNSColorFromHexString(const nsAString& aColor) michael@0: { michael@0: NSString* str = nsCocoaUtils::ToNSString(aColor); michael@0: michael@0: double red = HexStrToInt([str substringWithRange:NSMakeRange(1, 2)]) / 255.0; michael@0: double green = HexStrToInt([str substringWithRange:NSMakeRange(3, 2)]) / 255.0; michael@0: double blue = HexStrToInt([str substringWithRange:NSMakeRange(5, 2)]) / 255.0; michael@0: michael@0: return [NSColor colorWithDeviceRed: red green: green blue: blue alpha: 1.0]; michael@0: } michael@0: michael@0: /* static */ void michael@0: nsColorPicker::GetHexStringFromNSColor(NSColor* aColor, nsAString& aResult) michael@0: { michael@0: CGFloat redFloat, greenFloat, blueFloat; michael@0: [aColor getRed: &redFloat green: &greenFloat blue: &blueFloat alpha: nil]; michael@0: michael@0: nsCocoaUtils::GetStringForNSString([NSString stringWithFormat:@"#%02x%02x%02x", michael@0: (int)(redFloat * 255), michael@0: (int)(greenFloat * 255), michael@0: (int)(blueFloat * 255)], michael@0: aResult); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsColorPicker::Open(nsIColorPickerShownCallback* aCallback) michael@0: { michael@0: MOZ_ASSERT(aCallback); michael@0: mCallback = aCallback; michael@0: michael@0: [sColorPanelWrapper open:GetNSColorFromHexString(mColor) michael@0: title:nsCocoaUtils::ToNSString(mTitle)]; michael@0: michael@0: NS_ADDREF_THIS(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsColorPicker::Update(NSColor* aColor) michael@0: { michael@0: GetHexStringFromNSColor(aColor, mColor); michael@0: mCallback->Update(mColor); michael@0: } michael@0: michael@0: void michael@0: nsColorPicker::DoneWithRetarget() michael@0: { michael@0: mCallback->Done(EmptyString()); michael@0: mCallback = nullptr; michael@0: NS_RELEASE_THIS(); michael@0: } michael@0: michael@0: void michael@0: nsColorPicker::Done() michael@0: { michael@0: [sColorPanelWrapper release]; michael@0: sColorPanelWrapper = nullptr; michael@0: DoneWithRetarget(); michael@0: }