View Javadoc

1   /**********************************************
2    * Copyright (C) 2009 Lukas Laag
3    * This file is part of Vectomatic.
4    * 
5    * Vectomatic is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    * 
10   * Vectomatic is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   * 
15   * You should have received a copy of the GNU General Public License
16   * along with Vectomatic.  If not, see http://www.gnu.org/licenses/
17   **********************************************/
18  package org.vectomatic.client.rep.view;
19  
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  import org.vectomatic.client.rep.controller.ColorEditor;
24  import org.vectomatic.common.events.IPaletteListener;
25  import org.vectomatic.common.model.style.Color;
26  import org.vectomatic.common.model.style.Palette;
27  
28  import com.google.gwt.user.client.DOM;
29  import com.google.gwt.user.client.Element;
30  import com.google.gwt.user.client.Event;
31  import com.google.gwt.user.client.ui.ChangeListener;
32  import com.google.gwt.user.client.ui.ChangeListenerCollection;
33  import com.google.gwt.user.client.ui.SourcesChangeEvents;
34  import com.google.gwt.user.client.ui.Widget;
35  
36  /**
37   * Widget class to represent a palette
38   */
39  public class PaletteWidget extends Widget implements IPaletteListener, ChangeListener, SourcesChangeEvents {
40  	private Palette _palette;
41  	private int _selectedColorIndex;
42  	private int _columnCount;
43  	private int _divWidth;
44  	private int _divHeight;
45  	private int _margin;
46  	private List<Element> _subdivs;
47  	private ColorEditor _colorEditor;
48  	private ChangeListenerCollection _changeListeners;
49  
50  	PaletteWidget(Palette palette, ColorEditor colorEditor) {
51  		super();
52  		_colorEditor = colorEditor;
53  		Element div = DOM.createDiv();
54  		setElement(div);
55  		sinkEvents(Event.ONMOUSEDOWN | Event.ONDBLCLICK);
56  		_subdivs = new ArrayList<Element>();
57  		_divWidth = 12;
58  		_divHeight = 12;
59  		_margin = 5;
60  		_columnCount = 10;
61  		_selectedColorIndex = -1;
62  		setPalette(palette);
63  	}
64  	
65  	public Palette getPalette() {
66  		return _palette;
67  	}
68  	
69  	public void paletteHasChanged(Palette palette) {
70  		refresh();
71  	}
72  	
73  	public void setPalette(Palette palette) {
74  		if (_palette != null) {
75  			_palette.removePaletteListener(this);
76  		}
77  		_palette = palette;
78  		if (_palette != null) {
79  			_palette.addPaletteListener(this);
80  		}
81  		refresh();
82  		if (_selectedColorIndex == -1) {
83  			selectColor(0);
84  		}
85  	}
86  	
87  	private void refresh() {
88  
89  		Element div = getElement();
90  		
91  		// Adjust the number of subdivs so that it matches the number
92  		// of colors in the palette.
93  		int subdivCount = _subdivs.size();
94  		int colorCount = (_palette == null) ? 0 : _palette.getSize();
95  		
96  		if (subdivCount > colorCount) {
97  			for (int i = subdivCount - 1; i >= colorCount; i--) {
98  				Element subdiv = _subdivs.get(i);
99  				DOM.removeChild(div, subdiv);
100 				_subdivs.remove(i);
101 			}
102 		} else if (subdivCount < colorCount) {
103 			for (int i = subdivCount; i < colorCount; i++) {
104 				int row = i / _columnCount;
105 				int col = i % _columnCount;
106 				int x = _margin + (col * (_divWidth + _margin));
107 				int y = _margin + (row * (_divHeight + _margin));
108 				Element subdiv = DOM.createDiv();
109 				DOM.setStyleAttribute(subdiv, "position", "absolute");
110 				DOM.setStyleAttribute(subdiv, "width", _divWidth + "px");
111 				DOM.setStyleAttribute(subdiv, "height", _divHeight + "px");
112 				DOM.setStyleAttribute(subdiv, "left", x + "px");
113 				DOM.setStyleAttribute(subdiv, "top",  y + "px");
114 				DOM.setElementAttribute(subdiv, "class", "palette");
115 				DOM.appendChild(div, subdiv);
116 				_subdivs.add(subdiv);
117 			}			
118 		}
119 
120 		// Set the subdiv color according to the palette
121 		for (int i = 0; i < colorCount; i++) {
122 			Color color = _palette.getColor(i);
123 			Element subdiv = _subdivs.get(i);
124 			DOM.setStyleAttribute(subdiv, "backgroundColor", color.toString());
125 		}
126 		DOM.setStyleAttribute(div, "position", "relative");
127 		DOM.setStyleAttribute(div, "width", _margin + _columnCount * (_divWidth + _margin) + "px");
128 		DOM.setStyleAttribute(div, "height", _margin + ((colorCount / _columnCount) + ((colorCount % _columnCount != 0) ? 1 : 0)) * (_divHeight + _margin) + "px");
129 	}
130 
131 	@Override
132 	public void onBrowserEvent(Event event) {
133 		Element div = getElement();
134 		super.onBrowserEvent(event);
135 		switch (DOM.eventGetType(event)) {
136 			case Event.ONMOUSEDOWN:
137 				int x = DOM.eventGetClientX(event) - getAbsoluteLeft(div);
138 				int col = x / (_divWidth + _margin);
139 				int y = DOM.eventGetClientY(event) - getAbsoluteTop(div);
140 				int row = y / (_divHeight + _margin);
141 				if (col < _columnCount) {
142 					int index = _selectedColorIndex;
143 					selectColor(row * _columnCount + col);
144 					if ((index != _selectedColorIndex) && (_changeListeners != null)) {
145 						_changeListeners.fireChange(this);
146 					}
147 				}
148 				break;
149 			case Event.ONDBLCLICK:
150 				if (_palette != null && _selectedColorIndex != -1 && _colorEditor != null) {
151 					_colorEditor.setColor(_palette.getColor(_selectedColorIndex), this);
152 					_colorEditor.show();
153 				}
154 				break;
155 		}
156 	}
157 	
158 	public void selectColor(int index) {
159 		if (index != _selectedColorIndex) {
160 			if ((0 <= index) && (index < _subdivs.size())) {
161 				// Reset border of previously selected color
162 				if ((0 <= _selectedColorIndex) && (_selectedColorIndex < _subdivs.size())) {
163 					Element subdiv = _subdivs.get(_selectedColorIndex);
164 					DOM.setElementAttribute(subdiv, "class", "palette");
165 				}
166 				// Set border of newly selected color
167 				Element subdiv = _subdivs.get(index);
168 				DOM.setElementAttribute(subdiv, "class", "palette-selected");
169 				_selectedColorIndex = index;
170 			}
171 		}
172 	}
173 	
174 	public int getSelectedColorIndex() {
175 		return _selectedColorIndex;
176 	}
177 	
178 	public Color getSelectedColor() {
179 		return (_selectedColorIndex == -1) ? null : _palette.getColor(_selectedColorIndex);
180 	}
181 	
182 	
183 	public static native int getAbsoluteTop(Element elem) /*-{
184 	    var top = 0;
185 	    var curr = elem;
186 	    // This intentionally excludes body which has a null offsetParent.    
187 	    while (curr) {
188 	      top -= curr.scrollTop;
189 	      curr = curr.offsetParent;
190 	    }
191 	    while (elem) {
192 	      top += elem.offsetTop;
193 	      elem = elem.offsetParent;
194 	    }
195 	    return top;
196 	}-*/;
197   
198 	public static native int getAbsoluteLeft(Element elem) /*-{
199 	    var left = 0;
200 	    var curr = elem;
201 	    // This intentionally excludes body which has a null offsetParent.    
202 	    while (curr) {
203 	      left -= curr.scrollLeft;
204 	      curr = curr.offsetParent;
205 	    }
206 	    while (elem) {
207 	      left += elem.offsetLeft;
208 	      elem = elem.offsetParent;
209 	    }
210 	    return left;
211 	}-*/;
212 
213 	public void onChange(Widget sender) {
214 		_colorEditor.getColor(_palette.getColor(_selectedColorIndex));
215 		_palette.setColor(_selectedColorIndex, _palette.getColor(_selectedColorIndex));
216 	}
217 
218 	public void addChangeListener(ChangeListener listener) {
219 		if (_changeListeners == null) {
220 			_changeListeners = new ChangeListenerCollection();
221 		}
222 		_changeListeners.add(listener);
223 	}
224 
225 	public void removeChangeListener(ChangeListener listener) {
226 		if (_changeListeners != null) {
227 			_changeListeners.remove(listener);
228 		}
229 	}
230 }