|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include <gtk/gtk.h> |
|
7 |
|
8 #include "nsColor.h" |
|
9 #include "nsColorPicker.h" |
|
10 #include "nsGtkUtils.h" |
|
11 #include "nsIWidget.h" |
|
12 #include "WidgetUtils.h" |
|
13 |
|
14 NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker) |
|
15 |
|
16 int nsColorPicker::convertGdkColorComponent(guint16 color_component) { |
|
17 // GdkColor value is in range [0..65535]. We need something in range [0..255] |
|
18 return (color_component * 255 + 127) / 65535; |
|
19 } |
|
20 |
|
21 guint16 nsColorPicker::convertToGdkColorComponent(int color_component) { |
|
22 return color_component * 65535 / 255; |
|
23 } |
|
24 |
|
25 GdkColor nsColorPicker::convertToGdkColor(nscolor color) { |
|
26 GdkColor result = { 0 /* obsolete, unused 'pixel' value */, |
|
27 convertToGdkColorComponent(NS_GET_R(color)), |
|
28 convertToGdkColorComponent(NS_GET_G(color)), |
|
29 convertToGdkColorComponent(NS_GET_B(color)) }; |
|
30 |
|
31 return result; |
|
32 } |
|
33 |
|
34 GtkColorSelection* nsColorPicker::WidgetGetColorSelection(GtkWidget* widget) |
|
35 { |
|
36 return GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection( |
|
37 GTK_COLOR_SELECTION_DIALOG(widget))); |
|
38 } |
|
39 |
|
40 /* void init (in nsIDOMWindow parent, in AString title, in short mode); */ |
|
41 NS_IMETHODIMP nsColorPicker::Init(nsIDOMWindow *parent, |
|
42 const nsAString& title, |
|
43 const nsAString& initialColor) |
|
44 { |
|
45 mParentWidget = mozilla::widget::WidgetUtils::DOMWindowToWidget(parent); |
|
46 mTitle = title; |
|
47 mInitialColor = initialColor; |
|
48 |
|
49 return NS_OK; |
|
50 } |
|
51 |
|
52 /* void open (in nsIColorPickerShownCallback aColorPickerShownCallback); */ |
|
53 NS_IMETHODIMP nsColorPicker::Open(nsIColorPickerShownCallback *aColorPickerShownCallback) |
|
54 { |
|
55 |
|
56 // Input color string should be 7 length (i.e. a string representing a valid |
|
57 // simple color) |
|
58 if (mInitialColor.Length() != 7) { |
|
59 return NS_ERROR_FAILURE; |
|
60 } |
|
61 |
|
62 const nsAString& withoutHash = StringTail(mInitialColor, 6); |
|
63 nscolor color; |
|
64 if (!NS_HexToRGB(withoutHash, &color)) { |
|
65 return NS_ERROR_FAILURE; |
|
66 } |
|
67 |
|
68 GdkColor color_gdk = convertToGdkColor(color); |
|
69 |
|
70 if (mCallback) { |
|
71 // It means Open has already been called: this is not allowed |
|
72 NS_WARNING("mCallback is already set. Open called twice?"); |
|
73 return NS_ERROR_FAILURE; |
|
74 } |
|
75 mCallback = aColorPickerShownCallback; |
|
76 |
|
77 nsXPIDLCString title; |
|
78 title.Adopt(ToNewUTF8String(mTitle)); |
|
79 GtkWidget *color_chooser = gtk_color_selection_dialog_new(title); |
|
80 |
|
81 GtkWindow *parent_window = GTK_WINDOW(mParentWidget->GetNativeData(NS_NATIVE_SHELLWIDGET)); |
|
82 if (parent_window) { |
|
83 GtkWindow *window = GTK_WINDOW(color_chooser); |
|
84 gtk_window_set_transient_for(window, parent_window); |
|
85 gtk_window_set_destroy_with_parent(window, TRUE); |
|
86 } |
|
87 |
|
88 gtk_color_selection_set_current_color(WidgetGetColorSelection(color_chooser), |
|
89 &color_gdk); |
|
90 |
|
91 NS_ADDREF_THIS(); |
|
92 g_signal_connect(WidgetGetColorSelection(color_chooser), "color-changed", |
|
93 G_CALLBACK(OnColorChanged), this); |
|
94 g_signal_connect(color_chooser, "response", G_CALLBACK(OnResponse), this); |
|
95 g_signal_connect(color_chooser, "destroy", G_CALLBACK(OnDestroy), this); |
|
96 gtk_widget_show(color_chooser); |
|
97 |
|
98 return NS_OK; |
|
99 } |
|
100 |
|
101 /* static */ void |
|
102 nsColorPicker::OnColorChanged(GtkColorSelection* colorselection, |
|
103 gpointer user_data) |
|
104 { |
|
105 static_cast<nsColorPicker*>(user_data)->Update(colorselection); |
|
106 } |
|
107 |
|
108 /* static */ void |
|
109 nsColorPicker::OnResponse(GtkWidget* color_chooser, gint response_id, |
|
110 gpointer user_data) |
|
111 { |
|
112 static_cast<nsColorPicker*>(user_data)-> |
|
113 Done(color_chooser, response_id); |
|
114 } |
|
115 |
|
116 /* static */ void |
|
117 nsColorPicker::OnDestroy(GtkWidget* color_chooser, gpointer user_data) |
|
118 { |
|
119 static_cast<nsColorPicker*>(user_data)-> |
|
120 Done(color_chooser, GTK_RESPONSE_CANCEL); |
|
121 } |
|
122 |
|
123 void |
|
124 nsColorPicker::Update(GtkColorSelection* colorselection) |
|
125 { |
|
126 ReadValueFromColorSelection(colorselection); |
|
127 if (mCallback) { |
|
128 mCallback->Update(mColor); |
|
129 } |
|
130 } |
|
131 |
|
132 void |
|
133 nsColorPicker::Done(GtkWidget* color_chooser, gint response) |
|
134 { |
|
135 switch (response) { |
|
136 case GTK_RESPONSE_OK: |
|
137 case GTK_RESPONSE_ACCEPT: |
|
138 ReadValueFromColorSelection(WidgetGetColorSelection(color_chooser)); |
|
139 break; |
|
140 case GTK_RESPONSE_CANCEL: |
|
141 case GTK_RESPONSE_CLOSE: |
|
142 case GTK_RESPONSE_DELETE_EVENT: |
|
143 mColor = mInitialColor; |
|
144 break; |
|
145 default: |
|
146 NS_WARNING("Unexpected response"); |
|
147 break; |
|
148 } |
|
149 |
|
150 // A "response" signal won't be sent again but "destroy" will be. |
|
151 g_signal_handlers_disconnect_by_func(color_chooser, |
|
152 FuncToGpointer(OnDestroy), this); |
|
153 |
|
154 gtk_widget_destroy(color_chooser); |
|
155 if (mCallback) { |
|
156 mCallback->Done(mColor); |
|
157 mCallback = nullptr; |
|
158 } |
|
159 |
|
160 NS_RELEASE_THIS(); |
|
161 } |
|
162 |
|
163 nsString nsColorPicker::ToHexString(int n) |
|
164 { |
|
165 nsString result; |
|
166 if (n <= 0x0F) { |
|
167 result.Append('0'); |
|
168 } |
|
169 result.AppendInt(n, 16); |
|
170 return result; |
|
171 } |
|
172 |
|
173 void nsColorPicker::ReadValueFromColorSelection(GtkColorSelection* colorselection) |
|
174 { |
|
175 GdkColor rgba; |
|
176 gtk_color_selection_get_current_color(colorselection, &rgba); |
|
177 |
|
178 mColor.AssignLiteral("#"); |
|
179 mColor += ToHexString(convertGdkColorComponent(rgba.red)); |
|
180 mColor += ToHexString(convertGdkColorComponent(rgba.green)); |
|
181 mColor += ToHexString(convertGdkColorComponent(rgba.blue)); |
|
182 } |