color_picker.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079
  1. /*************************************************************************/
  2. /* color_picker.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "color_picker.h"
  31. #include "core/os/input.h"
  32. #include "core/os/keyboard.h"
  33. #include "core/os/os.h"
  34. #ifdef TOOLS_ENABLED
  35. #include "editor/editor_scale.h"
  36. #include "editor/editor_settings.h"
  37. #endif
  38. #include "scene/main/viewport.h"
  39. List<Color> ColorPicker::preset_cache;
  40. void ColorPicker::_notification(int p_what) {
  41. switch (p_what) {
  42. case NOTIFICATION_THEME_CHANGED: {
  43. btn_pick->set_icon(get_icon("screen_picker", "ColorPicker"));
  44. bt_add_preset->set_icon(get_icon("add_preset"));
  45. _update_controls();
  46. } break;
  47. case NOTIFICATION_ENTER_TREE: {
  48. btn_pick->set_icon(get_icon("screen_picker", "ColorPicker"));
  49. bt_add_preset->set_icon(get_icon("add_preset"));
  50. _update_controls();
  51. _update_color();
  52. #ifdef TOOLS_ENABLED
  53. if (Engine::get_singleton()->is_editor_hint()) {
  54. if (preset_cache.empty()) {
  55. PoolColorArray saved_presets = EditorSettings::get_singleton()->get_project_metadata("color_picker", "presets", PoolColorArray());
  56. for (int i = 0; i < saved_presets.size(); i++) {
  57. preset_cache.push_back(saved_presets[i]);
  58. }
  59. }
  60. for (int i = 0; i < preset_cache.size(); i++) {
  61. presets.push_back(preset_cache[i]);
  62. }
  63. preset->update();
  64. }
  65. #endif
  66. } break;
  67. case NOTIFICATION_PARENTED: {
  68. for (int i = 0; i < 4; i++) {
  69. set_margin((Margin)i, get_margin((Margin)i) + get_constant("margin"));
  70. }
  71. } break;
  72. case NOTIFICATION_VISIBILITY_CHANGED: {
  73. Popup *p = Object::cast_to<Popup>(get_parent());
  74. if (p) {
  75. p->set_size(Size2(get_combined_minimum_size().width + get_constant("margin") * 2, get_combined_minimum_size().height + get_constant("margin") * 2));
  76. }
  77. } break;
  78. case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: {
  79. if (screen != nullptr && screen->is_visible()) {
  80. screen->hide();
  81. }
  82. } break;
  83. }
  84. }
  85. void ColorPicker::set_focus_on_line_edit() {
  86. c_text->call_deferred("grab_focus");
  87. }
  88. void ColorPicker::_update_controls() {
  89. const char *rgb[3] = { "R", "G", "B" };
  90. const char *hsv[3] = { "H", "S", "V" };
  91. if (hsv_mode_enabled) {
  92. for (int i = 0; i < 3; i++) {
  93. labels[i]->set_text(hsv[i]);
  94. }
  95. } else {
  96. for (int i = 0; i < 3; i++) {
  97. labels[i]->set_text(rgb[i]);
  98. }
  99. }
  100. if (hsv_mode_enabled) {
  101. set_raw_mode(false);
  102. btn_raw->set_disabled(true);
  103. } else if (raw_mode_enabled) {
  104. set_hsv_mode(false);
  105. btn_hsv->set_disabled(true);
  106. } else {
  107. btn_raw->set_disabled(false);
  108. btn_hsv->set_disabled(false);
  109. }
  110. if (edit_alpha) {
  111. values[3]->show();
  112. scroll[3]->show();
  113. labels[3]->show();
  114. } else {
  115. values[3]->hide();
  116. scroll[3]->hide();
  117. labels[3]->hide();
  118. }
  119. }
  120. void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) {
  121. color = p_color;
  122. if (color != last_hsv) {
  123. h = color.get_h();
  124. s = color.get_s();
  125. v = color.get_v();
  126. last_hsv = color;
  127. }
  128. if (!is_inside_tree()) {
  129. return;
  130. }
  131. _update_color(p_update_sliders);
  132. }
  133. void ColorPicker::set_pick_color(const Color &p_color) {
  134. _set_pick_color(p_color, true); //because setters can't have more arguments
  135. }
  136. void ColorPicker::set_edit_alpha(bool p_show) {
  137. edit_alpha = p_show;
  138. _update_controls();
  139. if (!is_inside_tree()) {
  140. return;
  141. }
  142. _update_color();
  143. sample->update();
  144. }
  145. bool ColorPicker::is_editing_alpha() const {
  146. return edit_alpha;
  147. }
  148. void ColorPicker::_value_changed(double) {
  149. if (updating) {
  150. return;
  151. }
  152. if (hsv_mode_enabled) {
  153. h = scroll[0]->get_value() / 360.0;
  154. s = scroll[1]->get_value() / 100.0;
  155. v = scroll[2]->get_value() / 100.0;
  156. color.set_hsv(h, s, v, scroll[3]->get_value() / 255.0);
  157. last_hsv = color;
  158. } else {
  159. for (int i = 0; i < 4; i++) {
  160. color.components[i] = scroll[i]->get_value() / (raw_mode_enabled ? 1.0 : 255.0);
  161. }
  162. }
  163. _set_pick_color(color, false);
  164. emit_signal("color_changed", color);
  165. }
  166. void ColorPicker::_html_entered(const String &p_html) {
  167. if (updating || text_is_constructor || !c_text->is_visible()) {
  168. return;
  169. }
  170. float last_alpha = color.a;
  171. color = Color::html(p_html);
  172. if (!is_editing_alpha()) {
  173. color.a = last_alpha;
  174. }
  175. if (!is_inside_tree()) {
  176. return;
  177. }
  178. set_pick_color(color);
  179. emit_signal("color_changed", color);
  180. }
  181. void ColorPicker::_update_color(bool p_update_sliders) {
  182. updating = true;
  183. if (p_update_sliders) {
  184. if (hsv_mode_enabled) {
  185. for (int i = 0; i < 4; i++) {
  186. scroll[i]->set_step(1.0);
  187. }
  188. scroll[0]->set_max(359);
  189. scroll[0]->set_value(h * 360.0);
  190. scroll[1]->set_max(100);
  191. scroll[1]->set_value(s * 100.0);
  192. scroll[2]->set_max(100);
  193. scroll[2]->set_value(v * 100.0);
  194. scroll[3]->set_max(255);
  195. scroll[3]->set_value(color.components[3] * 255.0);
  196. } else {
  197. for (int i = 0; i < 4; i++) {
  198. if (raw_mode_enabled) {
  199. scroll[i]->set_step(0.01);
  200. scroll[i]->set_max(100);
  201. if (i == 3) {
  202. scroll[i]->set_max(1);
  203. }
  204. scroll[i]->set_value(color.components[i]);
  205. } else {
  206. scroll[i]->set_step(1);
  207. const float byte_value = color.components[i] * 255.0;
  208. scroll[i]->set_max(next_power_of_2(MAX(255, byte_value)) - 1);
  209. scroll[i]->set_value(byte_value);
  210. }
  211. }
  212. }
  213. }
  214. _update_text_value();
  215. sample->update();
  216. uv_edit->update();
  217. w_edit->update();
  218. updating = false;
  219. }
  220. void ColorPicker::_update_presets() {
  221. presets_per_row = 10;
  222. Size2 size = bt_add_preset->get_size();
  223. Size2 preset_size = Size2(MIN(size.width * presets.size(), presets_per_row * size.width), size.height * (Math::ceil((float)presets.size() / presets_per_row)));
  224. preset->set_custom_minimum_size(preset_size);
  225. preset_container->set_custom_minimum_size(preset_size);
  226. preset->draw_rect(Rect2(Point2(), preset_size), Color(1, 1, 1, 0));
  227. for (int i = 0; i < presets.size(); i++) {
  228. int x = (i % presets_per_row) * size.width;
  229. int y = (Math::floor((float)i / presets_per_row)) * size.height;
  230. preset->draw_rect(Rect2(Point2(x, y), size), presets[i]);
  231. }
  232. _notification(NOTIFICATION_VISIBILITY_CHANGED);
  233. }
  234. void ColorPicker::_text_type_toggled() {
  235. text_is_constructor = !text_is_constructor;
  236. if (text_is_constructor) {
  237. text_type->set_text("");
  238. text_type->set_icon(get_icon("Script", "EditorIcons"));
  239. c_text->set_editable(false);
  240. } else {
  241. text_type->set_text("#");
  242. text_type->set_icon(nullptr);
  243. c_text->set_editable(true);
  244. }
  245. _update_color();
  246. }
  247. Color ColorPicker::get_pick_color() const {
  248. return color;
  249. }
  250. void ColorPicker::add_preset(const Color &p_color) {
  251. if (presets.find(p_color)) {
  252. presets.move_to_back(presets.find(p_color));
  253. } else {
  254. presets.push_back(p_color);
  255. preset_cache.push_back(p_color);
  256. }
  257. preset->update();
  258. #ifdef TOOLS_ENABLED
  259. if (Engine::get_singleton()->is_editor_hint()) {
  260. PoolColorArray arr_to_save = get_presets();
  261. EditorSettings::get_singleton()->set_project_metadata("color_picker", "presets", arr_to_save);
  262. }
  263. #endif
  264. }
  265. void ColorPicker::erase_preset(const Color &p_color) {
  266. if (presets.find(p_color)) {
  267. presets.erase(presets.find(p_color));
  268. preset_cache.erase(preset_cache.find(p_color));
  269. preset->update();
  270. #ifdef TOOLS_ENABLED
  271. if (Engine::get_singleton()->is_editor_hint()) {
  272. PoolColorArray arr_to_save = get_presets();
  273. EditorSettings::get_singleton()->set_project_metadata("color_picker", "presets", arr_to_save);
  274. }
  275. #endif
  276. }
  277. }
  278. PoolColorArray ColorPicker::get_presets() const {
  279. PoolColorArray arr;
  280. arr.resize(presets.size());
  281. for (int i = 0; i < presets.size(); i++) {
  282. arr.set(i, presets[i]);
  283. }
  284. return arr;
  285. }
  286. void ColorPicker::set_hsv_mode(bool p_enabled) {
  287. if (hsv_mode_enabled == p_enabled || raw_mode_enabled) {
  288. return;
  289. }
  290. hsv_mode_enabled = p_enabled;
  291. if (btn_hsv->is_pressed() != p_enabled) {
  292. btn_hsv->set_pressed(p_enabled);
  293. }
  294. if (!is_inside_tree()) {
  295. return;
  296. }
  297. _update_controls();
  298. _update_color();
  299. }
  300. bool ColorPicker::is_hsv_mode() const {
  301. return hsv_mode_enabled;
  302. }
  303. void ColorPicker::set_raw_mode(bool p_enabled) {
  304. if (raw_mode_enabled == p_enabled || hsv_mode_enabled) {
  305. return;
  306. }
  307. raw_mode_enabled = p_enabled;
  308. if (btn_raw->is_pressed() != p_enabled) {
  309. btn_raw->set_pressed(p_enabled);
  310. }
  311. if (!is_inside_tree()) {
  312. return;
  313. }
  314. _update_controls();
  315. _update_color();
  316. }
  317. bool ColorPicker::is_raw_mode() const {
  318. return raw_mode_enabled;
  319. }
  320. void ColorPicker::set_deferred_mode(bool p_enabled) {
  321. deferred_mode_enabled = p_enabled;
  322. }
  323. bool ColorPicker::is_deferred_mode() const {
  324. return deferred_mode_enabled;
  325. }
  326. void ColorPicker::_update_text_value() {
  327. bool visible = true;
  328. if (text_is_constructor) {
  329. String t = "Color(" + String::num(color.r) + ", " + String::num(color.g) + ", " + String::num(color.b);
  330. if (edit_alpha && color.a < 1) {
  331. t += ", " + String::num(color.a) + ")";
  332. } else {
  333. t += ")";
  334. }
  335. c_text->set_text(t);
  336. }
  337. if (color.r > 1 || color.g > 1 || color.b > 1 || color.r < 0 || color.g < 0 || color.b < 0) {
  338. visible = false;
  339. } else if (!text_is_constructor) {
  340. c_text->set_text(color.to_html(edit_alpha && color.a < 1));
  341. }
  342. text_type->set_visible(visible);
  343. c_text->set_visible(visible);
  344. }
  345. void ColorPicker::_sample_input(const Ref<InputEvent> &p_event) {
  346. const Ref<InputEventMouseButton> mb = p_event;
  347. if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
  348. if (display_old_color) {
  349. const Rect2 rect_old = Rect2(Point2(), Size2(uv_edit->get_size().width * 0.5, sample->get_size().height * 0.95));
  350. if (rect_old.has_point(mb->get_position())) {
  351. // Revert to the old color when left-clicking the old color sample.
  352. set_pick_color(old_color);
  353. //_update_color();
  354. emit_signal("color_changed", color);
  355. }
  356. }
  357. }
  358. }
  359. void ColorPicker::_sample_draw() {
  360. // Covers the right half of the sample if the old color is being displayed,
  361. // or the whole sample if it's not being displayed.
  362. Rect2 rect_new;
  363. if (display_old_color) {
  364. rect_new = Rect2(Point2(uv_edit->get_size().width * 0.5, 0), Size2(uv_edit->get_size().width * 0.5, sample->get_size().height * 0.95));
  365. // Draw both old and new colors for easier comparison (only if spawned from a ColorPickerButton).
  366. const Rect2 rect_old = Rect2(Point2(), Size2(uv_edit->get_size().width * 0.5, sample->get_size().height * 0.95));
  367. if (display_old_color && old_color.a < 1.0) {
  368. sample->draw_texture_rect(get_icon("preset_bg", "ColorPicker"), rect_old, true);
  369. }
  370. sample->draw_rect(rect_old, old_color);
  371. if (old_color.r > 1 || old_color.g > 1 || old_color.b > 1) {
  372. // Draw an indicator to denote that the old color is "overbright" and can't be displayed accurately in the preview.
  373. sample->draw_texture(get_icon("overbright_indicator", "ColorPicker"), Point2());
  374. }
  375. } else {
  376. rect_new = Rect2(Point2(), Size2(uv_edit->get_size().width, sample->get_size().height * 0.95));
  377. }
  378. if (color.a < 1.0) {
  379. sample->draw_texture_rect(get_icon("preset_bg", "ColorPicker"), rect_new, true);
  380. }
  381. sample->draw_rect(rect_new, color);
  382. if (color.r > 1 || color.g > 1 || color.b > 1) {
  383. // Draw an indicator to denote that the new color is "overbright" and can't be displayed accurately in the preview
  384. sample->draw_texture(get_icon("overbright_indicator", "ColorPicker"), Point2(uv_edit->get_size().width * 0.5, 0));
  385. }
  386. }
  387. void ColorPicker::_hsv_draw(int p_which, Control *c) {
  388. if (!c) {
  389. return;
  390. }
  391. if (p_which == 0) {
  392. Vector<Point2> points;
  393. points.push_back(Vector2());
  394. points.push_back(Vector2(c->get_size().x, 0));
  395. points.push_back(c->get_size());
  396. points.push_back(Vector2(0, c->get_size().y));
  397. Vector<Color> colors;
  398. colors.push_back(Color(1, 1, 1, 1));
  399. colors.push_back(Color(1, 1, 1, 1));
  400. colors.push_back(Color(0, 0, 0, 1));
  401. colors.push_back(Color(0, 0, 0, 1));
  402. c->draw_polygon(points, colors);
  403. Vector<Color> colors2;
  404. Color col = color;
  405. col.set_hsv(h, 1, 1);
  406. col.a = 0;
  407. colors2.push_back(col);
  408. col.a = 1;
  409. colors2.push_back(col);
  410. col.set_hsv(h, 1, 0);
  411. colors2.push_back(col);
  412. col.a = 0;
  413. colors2.push_back(col);
  414. c->draw_polygon(points, colors2);
  415. int x = CLAMP(c->get_size().x * s, 0, c->get_size().x);
  416. int y = CLAMP(c->get_size().y - c->get_size().y * v, 0, c->get_size().y);
  417. col = color;
  418. col.a = 1;
  419. c->draw_line(Point2(x, 0), Point2(x, c->get_size().y), col.inverted());
  420. c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted());
  421. c->draw_line(Point2(x, y), Point2(x, y), Color(1, 1, 1), 2);
  422. } else if (p_which == 1) {
  423. Ref<Texture> hue = get_icon("color_hue", "ColorPicker");
  424. c->draw_texture_rect(hue, Rect2(Point2(), c->get_size()));
  425. int y = c->get_size().y - c->get_size().y * (1.0 - h);
  426. Color col = Color();
  427. col.set_hsv(h, 1, 1);
  428. c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted());
  429. }
  430. }
  431. void ColorPicker::_uv_input(const Ref<InputEvent> &p_event) {
  432. Ref<InputEventMouseButton> bev = p_event;
  433. if (bev.is_valid()) {
  434. if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
  435. changing_color = true;
  436. float x = CLAMP((float)bev->get_position().x, 0, uv_edit->get_size().width);
  437. float y = CLAMP((float)bev->get_position().y, 0, uv_edit->get_size().height);
  438. s = x / uv_edit->get_size().width;
  439. v = 1.0 - y / uv_edit->get_size().height;
  440. color.set_hsv(h, s, v, color.a);
  441. last_hsv = color;
  442. set_pick_color(color);
  443. _update_color();
  444. if (!deferred_mode_enabled) {
  445. emit_signal("color_changed", color);
  446. }
  447. } else if (deferred_mode_enabled && !bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
  448. emit_signal("color_changed", color);
  449. changing_color = false;
  450. } else {
  451. changing_color = false;
  452. }
  453. }
  454. Ref<InputEventMouseMotion> mev = p_event;
  455. if (mev.is_valid()) {
  456. if (!changing_color) {
  457. return;
  458. }
  459. float x = CLAMP((float)mev->get_position().x, 0, uv_edit->get_size().width);
  460. float y = CLAMP((float)mev->get_position().y, 0, uv_edit->get_size().height);
  461. s = x / uv_edit->get_size().width;
  462. v = 1.0 - y / uv_edit->get_size().height;
  463. color.set_hsv(h, s, v, color.a);
  464. last_hsv = color;
  465. set_pick_color(color);
  466. _update_color();
  467. if (!deferred_mode_enabled) {
  468. emit_signal("color_changed", color);
  469. }
  470. }
  471. }
  472. void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
  473. Ref<InputEventMouseButton> bev = p_event;
  474. if (bev.is_valid()) {
  475. if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
  476. changing_color = true;
  477. float y = CLAMP((float)bev->get_position().y, 0, w_edit->get_size().height);
  478. h = y / w_edit->get_size().height;
  479. } else {
  480. changing_color = false;
  481. }
  482. color.set_hsv(h, s, v, color.a);
  483. last_hsv = color;
  484. set_pick_color(color);
  485. _update_color();
  486. if (!deferred_mode_enabled) {
  487. emit_signal("color_changed", color);
  488. } else if (!bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
  489. emit_signal("color_changed", color);
  490. }
  491. }
  492. Ref<InputEventMouseMotion> mev = p_event;
  493. if (mev.is_valid()) {
  494. if (!changing_color) {
  495. return;
  496. }
  497. float y = CLAMP((float)mev->get_position().y, 0, w_edit->get_size().height);
  498. h = y / w_edit->get_size().height;
  499. color.set_hsv(h, s, v, color.a);
  500. last_hsv = color;
  501. set_pick_color(color);
  502. _update_color();
  503. if (!deferred_mode_enabled) {
  504. emit_signal("color_changed", color);
  505. }
  506. }
  507. }
  508. void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) {
  509. Ref<InputEventMouseButton> bev = p_event;
  510. if (bev.is_valid()) {
  511. int index = 0;
  512. if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) {
  513. for (int i = 0; i < presets.size(); i++) {
  514. int x = (i % presets_per_row) * bt_add_preset->get_size().x;
  515. int y = (Math::floor((float)i / presets_per_row)) * bt_add_preset->get_size().y;
  516. if (bev->get_position().x > x && bev->get_position().x < x + preset->get_size().x && bev->get_position().y > y && bev->get_position().y < y + preset->get_size().y) {
  517. index = i;
  518. }
  519. }
  520. set_pick_color(presets[index]);
  521. _update_color();
  522. emit_signal("color_changed", color);
  523. } else if (bev->is_pressed() && bev->get_button_index() == BUTTON_RIGHT && presets_enabled) {
  524. index = bev->get_position().x / (preset->get_size().x / presets.size());
  525. Color clicked_preset = presets[index];
  526. erase_preset(clicked_preset);
  527. emit_signal("preset_removed", clicked_preset);
  528. bt_add_preset->show();
  529. }
  530. }
  531. Ref<InputEventMouseMotion> mev = p_event;
  532. if (mev.is_valid()) {
  533. int index = mev->get_position().x * presets.size();
  534. if (preset->get_size().x != 0) {
  535. index /= preset->get_size().x;
  536. }
  537. if (index < 0 || index >= presets.size()) {
  538. return;
  539. }
  540. preset->set_tooltip(vformat(RTR("Color: #%s\nLMB: Set color\nRMB: Remove preset"), presets[index].to_html(presets[index].a < 1)));
  541. }
  542. }
  543. void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) {
  544. if (!is_inside_tree()) {
  545. return;
  546. }
  547. Ref<InputEventMouseButton> bev = p_event;
  548. if (bev.is_valid() && bev->get_button_index() == BUTTON_LEFT && !bev->is_pressed()) {
  549. emit_signal("color_changed", color);
  550. screen->hide();
  551. }
  552. Ref<InputEventMouseMotion> mev = p_event;
  553. if (mev.is_valid()) {
  554. Viewport *r = get_tree()->get_root();
  555. if (!r->get_visible_rect().has_point(Point2(mev->get_global_position().x, mev->get_global_position().y))) {
  556. return;
  557. }
  558. Ref<Image> img = r->get_texture()->get_data();
  559. if (img.is_valid() && !img->empty()) {
  560. img->lock();
  561. Vector2 ofs = mev->get_global_position() - r->get_visible_rect().get_position();
  562. Color c = img->get_pixel(ofs.x, r->get_visible_rect().size.height - ofs.y);
  563. img->unlock();
  564. set_pick_color(c);
  565. }
  566. }
  567. }
  568. void ColorPicker::_add_preset_pressed() {
  569. add_preset(color);
  570. emit_signal("preset_added", color);
  571. }
  572. void ColorPicker::_screen_pick_pressed() {
  573. if (!is_inside_tree()) {
  574. return;
  575. }
  576. Viewport *r = get_tree()->get_root();
  577. if (!screen) {
  578. screen = memnew(Control);
  579. r->add_child(screen);
  580. screen->set_as_toplevel(true);
  581. screen->set_anchors_and_margins_preset(Control::PRESET_WIDE);
  582. screen->set_default_cursor_shape(CURSOR_POINTING_HAND);
  583. screen->connect("gui_input", this, "_screen_input");
  584. // It immediately toggles off in the first press otherwise.
  585. screen->call_deferred("connect", "hide", btn_pick, "set_pressed", varray(false));
  586. }
  587. screen->raise();
  588. screen->show_modal();
  589. }
  590. void ColorPicker::_focus_enter() {
  591. bool has_ctext_focus = c_text->has_focus();
  592. if (has_ctext_focus) {
  593. c_text->select_all();
  594. } else {
  595. c_text->select(0, 0);
  596. }
  597. for (int i = 0; i < 4; i++) {
  598. if (values[i]->get_line_edit()->has_focus() && !has_ctext_focus) {
  599. values[i]->get_line_edit()->select_all();
  600. } else {
  601. values[i]->get_line_edit()->select(0, 0);
  602. }
  603. }
  604. }
  605. void ColorPicker::_focus_exit() {
  606. for (int i = 0; i < 4; i++) {
  607. if (!values[i]->get_line_edit()->get_menu()->is_visible()) {
  608. values[i]->get_line_edit()->select(0, 0);
  609. }
  610. }
  611. c_text->select(0, 0);
  612. }
  613. void ColorPicker::_html_focus_exit() {
  614. if (c_text->get_menu()->is_visible()) {
  615. return;
  616. }
  617. _html_entered(c_text->get_text());
  618. _focus_exit();
  619. }
  620. void ColorPicker::set_presets_enabled(bool p_enabled) {
  621. presets_enabled = p_enabled;
  622. if (!p_enabled) {
  623. bt_add_preset->set_disabled(true);
  624. bt_add_preset->set_focus_mode(FOCUS_NONE);
  625. } else {
  626. bt_add_preset->set_disabled(false);
  627. bt_add_preset->set_focus_mode(FOCUS_ALL);
  628. }
  629. }
  630. bool ColorPicker::are_presets_enabled() const {
  631. return presets_enabled;
  632. }
  633. void ColorPicker::set_presets_visible(bool p_visible) {
  634. presets_visible = p_visible;
  635. preset_separator->set_visible(p_visible);
  636. preset_container->set_visible(p_visible);
  637. preset_container2->set_visible(p_visible);
  638. }
  639. bool ColorPicker::are_presets_visible() const {
  640. return presets_visible;
  641. }
  642. void ColorPicker::_bind_methods() {
  643. ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPicker::set_pick_color);
  644. ClassDB::bind_method(D_METHOD("get_pick_color"), &ColorPicker::get_pick_color);
  645. ClassDB::bind_method(D_METHOD("set_hsv_mode", "mode"), &ColorPicker::set_hsv_mode);
  646. ClassDB::bind_method(D_METHOD("is_hsv_mode"), &ColorPicker::is_hsv_mode);
  647. ClassDB::bind_method(D_METHOD("set_raw_mode", "mode"), &ColorPicker::set_raw_mode);
  648. ClassDB::bind_method(D_METHOD("is_raw_mode"), &ColorPicker::is_raw_mode);
  649. ClassDB::bind_method(D_METHOD("set_deferred_mode", "mode"), &ColorPicker::set_deferred_mode);
  650. ClassDB::bind_method(D_METHOD("is_deferred_mode"), &ColorPicker::is_deferred_mode);
  651. ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPicker::set_edit_alpha);
  652. ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPicker::is_editing_alpha);
  653. ClassDB::bind_method(D_METHOD("set_presets_enabled", "enabled"), &ColorPicker::set_presets_enabled);
  654. ClassDB::bind_method(D_METHOD("are_presets_enabled"), &ColorPicker::are_presets_enabled);
  655. ClassDB::bind_method(D_METHOD("set_presets_visible", "visible"), &ColorPicker::set_presets_visible);
  656. ClassDB::bind_method(D_METHOD("are_presets_visible"), &ColorPicker::are_presets_visible);
  657. ClassDB::bind_method(D_METHOD("add_preset", "color"), &ColorPicker::add_preset);
  658. ClassDB::bind_method(D_METHOD("erase_preset", "color"), &ColorPicker::erase_preset);
  659. ClassDB::bind_method(D_METHOD("get_presets"), &ColorPicker::get_presets);
  660. ClassDB::bind_method(D_METHOD("_value_changed"), &ColorPicker::_value_changed);
  661. ClassDB::bind_method(D_METHOD("_html_entered"), &ColorPicker::_html_entered);
  662. ClassDB::bind_method(D_METHOD("_text_type_toggled"), &ColorPicker::_text_type_toggled);
  663. ClassDB::bind_method(D_METHOD("_add_preset_pressed"), &ColorPicker::_add_preset_pressed);
  664. ClassDB::bind_method(D_METHOD("_screen_pick_pressed"), &ColorPicker::_screen_pick_pressed);
  665. ClassDB::bind_method(D_METHOD("_sample_input"), &ColorPicker::_sample_input);
  666. ClassDB::bind_method(D_METHOD("_sample_draw"), &ColorPicker::_sample_draw);
  667. ClassDB::bind_method(D_METHOD("_update_presets"), &ColorPicker::_update_presets);
  668. ClassDB::bind_method(D_METHOD("_hsv_draw"), &ColorPicker::_hsv_draw);
  669. ClassDB::bind_method(D_METHOD("_uv_input"), &ColorPicker::_uv_input);
  670. ClassDB::bind_method(D_METHOD("_w_input"), &ColorPicker::_w_input);
  671. ClassDB::bind_method(D_METHOD("_preset_input"), &ColorPicker::_preset_input);
  672. ClassDB::bind_method(D_METHOD("_screen_input"), &ColorPicker::_screen_input);
  673. ClassDB::bind_method(D_METHOD("_focus_enter"), &ColorPicker::_focus_enter);
  674. ClassDB::bind_method(D_METHOD("_focus_exit"), &ColorPicker::_focus_exit);
  675. ClassDB::bind_method(D_METHOD("_html_focus_exit"), &ColorPicker::_html_focus_exit);
  676. ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color");
  677. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha");
  678. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hsv_mode"), "set_hsv_mode", "is_hsv_mode");
  679. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "raw_mode"), "set_raw_mode", "is_raw_mode");
  680. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode"), "set_deferred_mode", "is_deferred_mode");
  681. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_enabled"), "set_presets_enabled", "are_presets_enabled");
  682. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_visible"), "set_presets_visible", "are_presets_visible");
  683. ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color")));
  684. ADD_SIGNAL(MethodInfo("preset_added", PropertyInfo(Variant::COLOR, "color")));
  685. ADD_SIGNAL(MethodInfo("preset_removed", PropertyInfo(Variant::COLOR, "color")));
  686. }
  687. ColorPicker::ColorPicker() :
  688. BoxContainer(true) {
  689. updating = true;
  690. edit_alpha = true;
  691. text_is_constructor = false;
  692. hsv_mode_enabled = false;
  693. raw_mode_enabled = false;
  694. deferred_mode_enabled = false;
  695. changing_color = false;
  696. presets_enabled = true;
  697. presets_visible = true;
  698. screen = nullptr;
  699. HBoxContainer *hb_edit = memnew(HBoxContainer);
  700. add_child(hb_edit);
  701. hb_edit->set_v_size_flags(SIZE_EXPAND_FILL);
  702. uv_edit = memnew(Control);
  703. hb_edit->add_child(uv_edit);
  704. uv_edit->connect("gui_input", this, "_uv_input");
  705. uv_edit->set_mouse_filter(MOUSE_FILTER_PASS);
  706. uv_edit->set_h_size_flags(SIZE_EXPAND_FILL);
  707. uv_edit->set_v_size_flags(SIZE_EXPAND_FILL);
  708. uv_edit->set_custom_minimum_size(Size2(get_constant("sv_width"), get_constant("sv_height")));
  709. uv_edit->connect("draw", this, "_hsv_draw", make_binds(0, uv_edit));
  710. w_edit = memnew(Control);
  711. hb_edit->add_child(w_edit);
  712. w_edit->set_custom_minimum_size(Size2(get_constant("h_width"), 0));
  713. w_edit->set_h_size_flags(SIZE_FILL);
  714. w_edit->set_v_size_flags(SIZE_EXPAND_FILL);
  715. w_edit->connect("gui_input", this, "_w_input");
  716. w_edit->connect("draw", this, "_hsv_draw", make_binds(1, w_edit));
  717. HBoxContainer *hb_smpl = memnew(HBoxContainer);
  718. add_child(hb_smpl);
  719. sample = memnew(TextureRect);
  720. hb_smpl->add_child(sample);
  721. sample->set_h_size_flags(SIZE_EXPAND_FILL);
  722. sample->connect("gui_input", this, "_sample_input");
  723. sample->connect("draw", this, "_sample_draw");
  724. btn_pick = memnew(ToolButton);
  725. hb_smpl->add_child(btn_pick);
  726. btn_pick->set_toggle_mode(true);
  727. btn_pick->set_tooltip(RTR("Pick a color from the editor window."));
  728. btn_pick->connect("pressed", this, "_screen_pick_pressed");
  729. VBoxContainer *vbl = memnew(VBoxContainer);
  730. add_child(vbl);
  731. add_child(memnew(HSeparator));
  732. VBoxContainer *vbr = memnew(VBoxContainer);
  733. add_child(vbr);
  734. vbr->set_h_size_flags(SIZE_EXPAND_FILL);
  735. for (int i = 0; i < 4; i++) {
  736. HBoxContainer *hbc = memnew(HBoxContainer);
  737. labels[i] = memnew(Label());
  738. labels[i]->set_custom_minimum_size(Size2(get_constant("label_width"), 0));
  739. labels[i]->set_v_size_flags(SIZE_SHRINK_CENTER);
  740. hbc->add_child(labels[i]);
  741. scroll[i] = memnew(HSlider);
  742. scroll[i]->set_v_size_flags(SIZE_SHRINK_CENTER);
  743. scroll[i]->set_focus_mode(FOCUS_NONE);
  744. hbc->add_child(scroll[i]);
  745. values[i] = memnew(SpinBox);
  746. scroll[i]->share(values[i]);
  747. hbc->add_child(values[i]);
  748. values[i]->get_line_edit()->connect("focus_entered", this, "_focus_enter");
  749. values[i]->get_line_edit()->connect("focus_exited", this, "_focus_exit");
  750. scroll[i]->set_min(0);
  751. scroll[i]->set_page(0);
  752. scroll[i]->set_h_size_flags(SIZE_EXPAND_FILL);
  753. scroll[i]->connect("value_changed", this, "_value_changed");
  754. vbr->add_child(hbc);
  755. }
  756. labels[3]->set_text("A");
  757. HBoxContainer *hhb = memnew(HBoxContainer);
  758. vbr->add_child(hhb);
  759. btn_hsv = memnew(CheckButton);
  760. hhb->add_child(btn_hsv);
  761. btn_hsv->set_text(RTR("HSV"));
  762. btn_hsv->connect("toggled", this, "set_hsv_mode");
  763. btn_raw = memnew(CheckButton);
  764. hhb->add_child(btn_raw);
  765. btn_raw->set_text(RTR("Raw"));
  766. btn_raw->connect("toggled", this, "set_raw_mode");
  767. text_type = memnew(Button);
  768. hhb->add_child(text_type);
  769. text_type->set_text("#");
  770. text_type->set_tooltip(TTR("Switch between hexadecimal and code values."));
  771. if (Engine::get_singleton()->is_editor_hint()) {
  772. #ifdef TOOLS_ENABLED
  773. text_type->set_custom_minimum_size(Size2(28 * EDSCALE, 0)); // Adjust for the width of the "Script" icon.
  774. #endif
  775. text_type->connect("pressed", this, "_text_type_toggled");
  776. } else {
  777. text_type->set_flat(true);
  778. text_type->set_mouse_filter(MOUSE_FILTER_IGNORE);
  779. }
  780. c_text = memnew(LineEdit);
  781. hhb->add_child(c_text);
  782. c_text->set_h_size_flags(SIZE_EXPAND_FILL);
  783. c_text->connect("text_entered", this, "_html_entered");
  784. c_text->connect("focus_entered", this, "_focus_enter");
  785. c_text->connect("focus_exited", this, "_html_focus_exit");
  786. _update_controls();
  787. updating = false;
  788. set_pick_color(Color(1, 1, 1));
  789. preset_separator = memnew(HSeparator);
  790. add_child(preset_separator);
  791. preset_container = memnew(HBoxContainer);
  792. preset_container->set_h_size_flags(SIZE_EXPAND_FILL);
  793. add_child(preset_container);
  794. preset = memnew(TextureRect);
  795. preset_container->add_child(preset);
  796. preset->connect("gui_input", this, "_preset_input");
  797. preset->connect("draw", this, "_update_presets");
  798. preset_container2 = memnew(HBoxContainer);
  799. preset_container2->set_h_size_flags(SIZE_EXPAND_FILL);
  800. add_child(preset_container2);
  801. bt_add_preset = memnew(Button);
  802. preset_container2->add_child(bt_add_preset);
  803. bt_add_preset->set_tooltip(RTR("Add current color as a preset."));
  804. bt_add_preset->connect("pressed", this, "_add_preset_pressed");
  805. }
  806. /////////////////
  807. void ColorPickerButton::_about_to_show() {
  808. set_pressed(true);
  809. if (picker) {
  810. picker->set_old_color(color);
  811. }
  812. }
  813. void ColorPickerButton::_color_changed(const Color &p_color) {
  814. color = p_color;
  815. update();
  816. emit_signal("color_changed", color);
  817. }
  818. void ColorPickerButton::_modal_closed() {
  819. emit_signal("popup_closed");
  820. }
  821. void ColorPickerButton::pressed() {
  822. _update_picker();
  823. popup->set_position(get_global_position() - picker->get_combined_minimum_size() * get_global_transform().get_scale());
  824. popup->set_scale(get_global_transform().get_scale());
  825. popup->popup();
  826. picker->set_focus_on_line_edit();
  827. }
  828. void ColorPickerButton::_notification(int p_what) {
  829. switch (p_what) {
  830. case NOTIFICATION_DRAW: {
  831. const Ref<StyleBox> normal = get_stylebox("normal");
  832. const Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size());
  833. draw_texture_rect(Control::get_icon("bg", "ColorPickerButton"), r, true);
  834. draw_rect(r, color);
  835. if (color.r > 1 || color.g > 1 || color.b > 1) {
  836. // Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview
  837. draw_texture(Control::get_icon("overbright_indicator", "ColorPicker"), normal->get_offset());
  838. }
  839. } break;
  840. case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: {
  841. if (popup) {
  842. popup->hide();
  843. }
  844. } break;
  845. }
  846. if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
  847. if (popup && !is_visible_in_tree()) {
  848. popup->hide();
  849. }
  850. }
  851. }
  852. void ColorPickerButton::set_pick_color(const Color &p_color) {
  853. color = p_color;
  854. if (picker) {
  855. picker->set_pick_color(p_color);
  856. }
  857. update();
  858. }
  859. Color ColorPickerButton::get_pick_color() const {
  860. return color;
  861. }
  862. void ColorPicker::set_old_color(const Color &p_color) {
  863. old_color = p_color;
  864. }
  865. void ColorPicker::set_display_old_color(bool p_enabled) {
  866. display_old_color = p_enabled;
  867. }
  868. bool ColorPicker::is_displaying_old_color() const {
  869. return display_old_color;
  870. }
  871. void ColorPickerButton::set_edit_alpha(bool p_show) {
  872. edit_alpha = p_show;
  873. if (picker) {
  874. picker->set_edit_alpha(p_show);
  875. }
  876. }
  877. bool ColorPickerButton::is_editing_alpha() const {
  878. return edit_alpha;
  879. }
  880. ColorPicker *ColorPickerButton::get_picker() {
  881. _update_picker();
  882. return picker;
  883. }
  884. PopupPanel *ColorPickerButton::get_popup() {
  885. _update_picker();
  886. return popup;
  887. }
  888. void ColorPickerButton::_update_picker() {
  889. if (!picker) {
  890. popup = memnew(PopupPanel);
  891. picker = memnew(ColorPicker);
  892. popup->add_child(picker);
  893. add_child(popup);
  894. picker->connect("color_changed", this, "_color_changed");
  895. popup->connect("modal_closed", this, "_modal_closed");
  896. popup->connect("about_to_show", this, "_about_to_show");
  897. popup->connect("popup_hide", this, "set_pressed", varray(false));
  898. picker->set_pick_color(color);
  899. picker->set_edit_alpha(edit_alpha);
  900. picker->set_display_old_color(true);
  901. emit_signal("picker_created");
  902. }
  903. }
  904. void ColorPickerButton::_bind_methods() {
  905. ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPickerButton::set_pick_color);
  906. ClassDB::bind_method(D_METHOD("get_pick_color"), &ColorPickerButton::get_pick_color);
  907. ClassDB::bind_method(D_METHOD("get_picker"), &ColorPickerButton::get_picker);
  908. ClassDB::bind_method(D_METHOD("get_popup"), &ColorPickerButton::get_popup);
  909. ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPickerButton::set_edit_alpha);
  910. ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPickerButton::is_editing_alpha);
  911. ClassDB::bind_method(D_METHOD("_about_to_show"), &ColorPickerButton::_about_to_show);
  912. ClassDB::bind_method(D_METHOD("_color_changed"), &ColorPickerButton::_color_changed);
  913. ClassDB::bind_method(D_METHOD("_modal_closed"), &ColorPickerButton::_modal_closed);
  914. ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color")));
  915. ADD_SIGNAL(MethodInfo("popup_closed"));
  916. ADD_SIGNAL(MethodInfo("picker_created"));
  917. ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color");
  918. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha");
  919. }
  920. ColorPickerButton::ColorPickerButton() {
  921. // Initialization is now done deferred,
  922. // this improves performance in the inspector as the color picker
  923. // can be expensive to initialize.
  924. picker = nullptr;
  925. popup = nullptr;
  926. edit_alpha = true;
  927. set_toggle_mode(true);
  928. }