You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AbstractColorPicker.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.ui;
  17. import java.io.Serializable;
  18. import java.util.Collection;
  19. import java.util.Objects;
  20. import org.jsoup.nodes.Attributes;
  21. import org.jsoup.nodes.Element;
  22. import com.vaadin.shared.ui.colorpicker.AbstractColorPickerState;
  23. import com.vaadin.shared.ui.colorpicker.Color;
  24. import com.vaadin.shared.ui.colorpicker.ColorPickerServerRpc;
  25. import com.vaadin.ui.components.colorpicker.ColorPickerPopup;
  26. import com.vaadin.ui.declarative.DesignAttributeHandler;
  27. import com.vaadin.ui.declarative.DesignContext;
  28. /**
  29. * An abstract class that defines default implementation for a color picker
  30. * component.
  31. *
  32. * @since 7.0.0
  33. */
  34. public abstract class AbstractColorPicker extends AbstractField<Color> {
  35. /**
  36. * Interface for converting 2d-coordinates to a Color.
  37. */
  38. public interface Coordinates2Color extends Serializable {
  39. /**
  40. * Calculates a color from coordinates.
  41. *
  42. * @param x
  43. * the x-coordinate
  44. * @param y
  45. * the y-coordinate
  46. *
  47. * @return the color
  48. */
  49. public Color calculate(int x, int y);
  50. /**
  51. * Calculates coordinates from a color.
  52. *
  53. * @param c
  54. * the c
  55. *
  56. * @return the integer array with the coordinates
  57. */
  58. public int[] calculate(Color c);
  59. }
  60. /**
  61. * The style of the color picker popup.
  62. */
  63. public enum PopupStyle {
  64. /** A full popup with all tabs visible. */
  65. POPUP_NORMAL("normal"),
  66. /** A simple popup with only the swatches (palette) tab. */
  67. POPUP_SIMPLE("simple");
  68. private final String style;
  69. PopupStyle(String styleName) {
  70. style = styleName;
  71. }
  72. @Override
  73. public String toString() {
  74. return style;
  75. }
  76. }
  77. private ColorPickerServerRpc rpc = this::showPopup;
  78. protected static final String STYLENAME_DEFAULT = "v-colorpicker";
  79. protected static final String STYLENAME_BUTTON = "v-button";
  80. protected static final String STYLENAME_AREA = "v-colorpicker-area";
  81. protected PopupStyle popupStyle = PopupStyle.POPUP_NORMAL;
  82. private ColorPickerPopup window;
  83. /** The currently selected color. */
  84. protected Color color;
  85. private UI parent;
  86. private String popupCaption = null;
  87. private int positionX = 0;
  88. private int positionY = 0;
  89. protected boolean rgbVisible = true;
  90. protected boolean hsvVisible = true;
  91. protected boolean swatchesVisible = true;
  92. protected boolean historyVisible = true;
  93. protected boolean textfieldVisible = true;
  94. /**
  95. * Instantiates a new color picker.
  96. */
  97. public AbstractColorPicker() {
  98. this("Colors", Color.WHITE);
  99. }
  100. /**
  101. * Instantiates a new color picker.
  102. *
  103. * @param popupCaption
  104. * the caption of the popup window
  105. */
  106. public AbstractColorPicker(String popupCaption) {
  107. this(popupCaption, Color.WHITE);
  108. }
  109. /**
  110. * Instantiates a new color picker.
  111. *
  112. * @param popupCaption
  113. * the caption of the popup window
  114. * @param initialColor
  115. * the initial color
  116. */
  117. public AbstractColorPicker(String popupCaption, Color initialColor) {
  118. super();
  119. registerRpc(rpc);
  120. setValue(initialColor);
  121. this.popupCaption = popupCaption;
  122. setDefaultStyles();
  123. setCaption("");
  124. }
  125. /**
  126. * Returns the current selected color of this color picker.
  127. *
  128. * @return the selected color, not null
  129. */
  130. @Override
  131. public Color getValue() {
  132. return color;
  133. }
  134. /**
  135. * Sets the selected color of this color picker. If the new color is not
  136. * equal to getValue(), fires a {@link ValueChangeEvent}.
  137. *
  138. * @param color
  139. * the new selected color, not null
  140. * @throws NullPointerException
  141. * if {@code color} is {@code null}
  142. */
  143. @Override
  144. public void setValue(Color color) {
  145. Objects.requireNonNull(color, "color cannot be null");
  146. super.setValue(color);
  147. }
  148. /**
  149. * Set true if the component should show a default caption (css-code for the
  150. * currently selected color, e.g. #ffffff) when no other caption is
  151. * available.
  152. *
  153. * @param enabled
  154. * {@code true} to enable the default caption, {@code false} to
  155. * disable
  156. */
  157. public void setDefaultCaptionEnabled(boolean enabled) {
  158. getState().showDefaultCaption = enabled;
  159. }
  160. /**
  161. * Returns true if the component shows the default caption (css-code for the
  162. * currently selected color, e.g. #ffffff) if no other caption is available.
  163. *
  164. * @return {@code true} if the default caption is enabled, {@code false}
  165. * otherwise
  166. */
  167. public boolean isDefaultCaptionEnabled() {
  168. return getState(false).showDefaultCaption;
  169. }
  170. /**
  171. * Sets the position of the popup window.
  172. *
  173. * @param x
  174. * the x-coordinate
  175. * @param y
  176. * the y-coordinate
  177. */
  178. public void setPosition(int x, int y) {
  179. positionX = x;
  180. positionY = y;
  181. if (window != null) {
  182. window.setPositionX(x);
  183. window.setPositionY(y);
  184. }
  185. }
  186. /**
  187. * Sets the style of the popup window.
  188. *
  189. * @param style
  190. * the popup window style
  191. */
  192. public void setPopupStyle(PopupStyle style) {
  193. popupStyle = style;
  194. switch (style) {
  195. case POPUP_NORMAL:
  196. setRGBVisibility(true);
  197. setHSVVisibility(true);
  198. setSwatchesVisibility(true);
  199. setHistoryVisibility(true);
  200. setTextfieldVisibility(true);
  201. break;
  202. case POPUP_SIMPLE:
  203. setRGBVisibility(false);
  204. setHSVVisibility(false);
  205. setSwatchesVisibility(true);
  206. setHistoryVisibility(false);
  207. setTextfieldVisibility(false);
  208. break;
  209. default:
  210. assert false : "Unknown popup style " + style;
  211. }
  212. }
  213. /**
  214. * Gets the style for the popup window.
  215. *
  216. * @since 7.5.0
  217. * @return popup window style
  218. */
  219. public PopupStyle getPopupStyle() {
  220. return popupStyle;
  221. }
  222. /**
  223. * Sets the visibility of the RGB tab.
  224. *
  225. * @param visible
  226. * {@code true} to display the RGB tab, {@code false} to hide it
  227. */
  228. public void setRGBVisibility(boolean visible) {
  229. if (!visible && !hsvVisible && !swatchesVisible) {
  230. throw new IllegalArgumentException("Cannot hide all tabs.");
  231. }
  232. rgbVisible = visible;
  233. if (window != null) {
  234. window.setRGBTabVisible(visible);
  235. }
  236. }
  237. /**
  238. * Gets the visibility of the RGB Tab.
  239. *
  240. * @since 7.5.0
  241. * @return visibility of the RGB tab
  242. */
  243. public boolean getRGBVisibility() {
  244. return rgbVisible;
  245. }
  246. /**
  247. * Sets the visibility of the HSV Tab.
  248. *
  249. * @param visible
  250. * {@code true} to display the HSV tab, {@code false} to hide it
  251. */
  252. public void setHSVVisibility(boolean visible) {
  253. if (!visible && !rgbVisible && !swatchesVisible) {
  254. throw new IllegalArgumentException("Cannot hide all tabs.");
  255. }
  256. hsvVisible = visible;
  257. if (window != null) {
  258. window.setHSVTabVisible(visible);
  259. }
  260. }
  261. /**
  262. * Gets the visibility of the HSV tab.
  263. *
  264. * @since 7.5.0
  265. * @return {@code true} if the HSV tab is currently displayed, {@code false}
  266. * otherwise
  267. */
  268. public boolean getHSVVisibility() {
  269. return hsvVisible;
  270. }
  271. /**
  272. * Sets the visibility of the Swatches (palette) tab.
  273. *
  274. * @param visible
  275. * {@code true} to display the Swatches tab, {@code false} to
  276. * hide it
  277. */
  278. public void setSwatchesVisibility(boolean visible) {
  279. if (!visible && !hsvVisible && !rgbVisible) {
  280. throw new IllegalArgumentException("Cannot hide all tabs.");
  281. }
  282. swatchesVisible = visible;
  283. if (window != null) {
  284. window.setSwatchesTabVisible(visible);
  285. }
  286. }
  287. /**
  288. * Gets the visibility of the Swatches (palette) tab.
  289. *
  290. * @since 7.5.0
  291. * @return {@code true} if the Swatches tab is currently displayed,
  292. * {@code false} otherwise
  293. */
  294. public boolean getSwatchesVisibility() {
  295. return swatchesVisible;
  296. }
  297. /**
  298. * Sets the visibility of the color history, displaying recently picked
  299. * colors.
  300. *
  301. * @param visible
  302. * {@code true} to display the history, {@code false} to hide it
  303. */
  304. public void setHistoryVisibility(boolean visible) {
  305. historyVisible = visible;
  306. if (window != null) {
  307. window.setHistoryVisible(visible);
  308. }
  309. }
  310. /**
  311. * Gets the visibility of the Color history.
  312. *
  313. * @since 7.5.0
  314. * @return {@code true} if the history is currently displayed, {@code false}
  315. * otherwise
  316. */
  317. public boolean getHistoryVisibility() {
  318. return historyVisible;
  319. }
  320. /**
  321. * Sets the visibility of the CSS color code text field.
  322. *
  323. * @param visible
  324. * {@code true} to display the CSS text field, {@code false} to
  325. * hide it
  326. */
  327. public void setTextfieldVisibility(boolean visible) {
  328. textfieldVisible = visible;
  329. if (window != null) {
  330. window.setPreviewVisible(visible);
  331. }
  332. }
  333. /**
  334. * Gets the visibility of CSS color code text field.
  335. *
  336. * @since 7.5.0
  337. * @return {@code true} if the CSS text field is currently displayed,
  338. * {@code false} otherwise
  339. */
  340. public boolean getTextfieldVisibility() {
  341. return textfieldVisible;
  342. }
  343. @Override
  344. protected AbstractColorPickerState getState() {
  345. return (AbstractColorPickerState) super.getState();
  346. }
  347. @Override
  348. protected AbstractColorPickerState getState(boolean markAsDirty) {
  349. return (AbstractColorPickerState) super.getState(markAsDirty);
  350. }
  351. /**
  352. * Sets the default styles of the component.
  353. */
  354. protected abstract void setDefaultStyles();
  355. /**
  356. * Shows a popup-window for color selection.
  357. */
  358. public void showPopup() {
  359. showPopup(true);
  360. }
  361. /**
  362. * Hides a popup-window for color selection.
  363. */
  364. public void hidePopup() {
  365. showPopup(false);
  366. }
  367. /**
  368. * Shows or hides the popup window depending on the given parameter. If
  369. * there is no such window yet, one is created.
  370. *
  371. * @param open
  372. * {@code true} to display the popup, {@code false} to hide it
  373. */
  374. protected void showPopup(boolean open) {
  375. if (open && !isReadOnly()) {
  376. if (parent == null) {
  377. parent = getUI();
  378. }
  379. Color color = getValue();
  380. if (window == null) {
  381. window = new ColorPickerPopup(color);
  382. window.setCaption(popupCaption);
  383. window.setRGBTabVisible(rgbVisible);
  384. window.setHSVTabVisible(hsvVisible);
  385. window.setSwatchesTabVisible(swatchesVisible);
  386. window.setHistoryVisible(historyVisible);
  387. window.setPreviewVisible(textfieldVisible);
  388. window.addCloseListener(
  389. event -> getState().popupVisible = false);
  390. window.addValueChangeListener(
  391. event -> setValue(event.getValue()));
  392. window.getHistory().setValue(color);
  393. window.setPositionX(positionX);
  394. window.setPositionY(positionY);
  395. window.setVisible(true);
  396. parent.addWindow(window);
  397. window.focus();
  398. } else if (!parent.equals(window.getParent())) {
  399. window.setRGBTabVisible(rgbVisible);
  400. window.setHSVTabVisible(hsvVisible);
  401. window.setSwatchesTabVisible(swatchesVisible);
  402. window.setHistoryVisible(historyVisible);
  403. window.setPreviewVisible(textfieldVisible);
  404. window.setValue(color);
  405. window.getHistory().setValue(color);
  406. window.setVisible(true);
  407. parent.addWindow(window);
  408. window.focus();
  409. }
  410. } else if (window != null) {
  411. window.setVisible(false);
  412. parent.removeWindow(window);
  413. }
  414. getState().popupVisible = open;
  415. }
  416. @Override
  417. public void readDesign(Element design, DesignContext designContext) {
  418. super.readDesign(design, designContext);
  419. Attributes attributes = design.attributes();
  420. if (design.hasAttr("color")) {
  421. // Ignore the # character
  422. String hexColor = DesignAttributeHandler
  423. .readAttribute("color", attributes, String.class)
  424. .substring(1);
  425. doSetValue(new Color(Integer.parseInt(hexColor, 16)));
  426. }
  427. if (design.hasAttr("popup-style")) {
  428. setPopupStyle(PopupStyle.valueOf(
  429. "POPUP_" + attributes.get("popup-style").toUpperCase()));
  430. }
  431. if (design.hasAttr("position")) {
  432. String[] position = attributes.get("position").split(",");
  433. setPosition(Integer.parseInt(position[0]),
  434. Integer.parseInt(position[1]));
  435. }
  436. }
  437. @Override
  438. public void writeDesign(Element design, DesignContext designContext) {
  439. super.writeDesign(design, designContext);
  440. Attributes attribute = design.attributes();
  441. DesignAttributeHandler.writeAttribute("color", attribute,
  442. getValue().getCSS(), Color.WHITE.getCSS(), String.class,
  443. designContext);
  444. DesignAttributeHandler.writeAttribute("popup-style", attribute,
  445. popupStyle == PopupStyle.POPUP_NORMAL ? "normal" : "simple",
  446. "normal", String.class, designContext);
  447. DesignAttributeHandler.writeAttribute("position", attribute,
  448. positionX + "," + positionY, "0,0", String.class,
  449. designContext);
  450. }
  451. @Override
  452. protected Collection<String> getCustomAttributes() {
  453. Collection<String> result = super.getCustomAttributes();
  454. result.add("color");
  455. result.add("position");
  456. result.add("popup-style");
  457. return result;
  458. }
  459. @Override
  460. protected void doSetValue(Color color) {
  461. this.color = color;
  462. getState().color = color.getCSS();
  463. }
  464. @Override
  465. public Color getEmptyValue() {
  466. return Color.WHITE;
  467. }
  468. }