Atrinik Client  4.0
color_picker.c
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
31 #include <global.h>
32 #include <toolkit/colorspace.h>
33 
42 void color_picker_create(color_picker_struct *color_picker, int size)
43 {
44  size_t i;
45 
46  memset(color_picker, 0, sizeof(*color_picker));
47 
48  color_picker->border_thickness = 1;
49 
50  for (i = 0; i < COLOR_PICKER_ELEM_NUM; i++) {
51  color_picker->elements[i].coords.w = color_picker->border_thickness * 2;
52  color_picker->elements[i].coords.h = color_picker->border_thickness * 2;
53  }
54 
55  color_picker->elements[0].coords.x = 0;
56  color_picker->elements[0].coords.y = 0;
57  color_picker->elements[0].coords.w += size + 1;
58  color_picker->elements[0].coords.h += size + 1;
59 
60  color_picker->elements[1].coords.x = color_picker->elements[0].coords.w;
61  color_picker->elements[1].coords.y = 0;
62  color_picker->elements[1].coords.w += size / 10 + 1;
63  color_picker->elements[1].coords.h += size + 1;
64 }
65 
75 void color_picker_set_parent(color_picker_struct *color_picker, int px, int py)
76 {
77  color_picker->px = px;
78  color_picker->py = py;
79 }
80 
88 void color_picker_set_notation(color_picker_struct *color_picker, const char *color_notation)
89 {
90  SDL_Color color;
91  double rgb[3];
92 
93  if (!text_color_parse(color_notation, &color)) {
94  LOG(BUG, "Invalid color: %s", color_notation);
95  return;
96  }
97 
98  rgb[0] = 1.0 * ((double) color.r / 255.0);
99  rgb[1] = 1.0 * ((double) color.g / 255.0);
100  rgb[2] = 1.0 * ((double) color.b / 255.0);
101  colorspace_rgb2hsv(rgb, color_picker->hsv);
102 }
103 
112 void color_picker_get_rgb(color_picker_struct *color_picker, uint8_t *r, uint8_t *g, uint8_t *b)
113 {
114  double rgb[3];
115 
116  colorspace_hsv2rgb(color_picker->hsv, rgb);
117 
118  *r = 255 * rgb[0];
119  *g = 255 * rgb[1];
120  *b = 255 * rgb[2];
121 }
122 
139 static int color_picker_element_show(SDL_Surface *surface, color_picker_struct *color_picker, size_t type, SDL_Event *event)
140 {
141  SDL_Rect box;
142  int x, y, mx, my;
143  double hsv[3], rgb[3];
144  SDL_Rect dest;
145  uint8_t r, g, b;
146 
147  box.x = color_picker->x + color_picker->elements[type].coords.x;
148  box.y = color_picker->y + color_picker->elements[type].coords.y;
149  box.w = color_picker->elements[type].coords.w;
150  box.h = color_picker->elements[type].coords.h;
151 
152  mx = my = 0;
153 
154  /* Create the border, if applicable. */
155  if (color_picker->border_thickness) {
156  if (surface) {
157  border_create_color(surface, &box, color_picker->border_thickness, "303030");
158  }
159 
160  box.x += color_picker->border_thickness;
161  box.y += color_picker->border_thickness;
162  box.w -= color_picker->border_thickness * 2;
163  box.h -= color_picker->border_thickness * 2;
164  }
165 
166  /* Check for events. */
167  if (event) {
168  mx = event->motion.x - color_picker->px;
169  my = event->motion.y - color_picker->py;
170 
171  /* If the element is being dragged, clamp the mouse x/y positions
172  * to the element's dimensions. */
173  if (color_picker->elements[type].dragging && event->type == SDL_MOUSEMOTION) {
174  if (mx < box.x) {
175  mx = box.x;
176  }
177 
178  if (my < box.y) {
179  my = box.y;
180  }
181 
182  if (mx >= box.x + box.w) {
183  mx = box.x + box.w - 1;
184  }
185 
186  if (my >= box.y + box.h) {
187  my = box.y + box.h - 1;
188  }
189  } else if (event->type == SDL_MOUSEMOTION) {
190  return 0;
191  }
192  } else if (color_picker->elements[type].dragging && SDL_GetMouseState(NULL, NULL) != SDL_BUTTON_LEFT) {
193  /* If the element says it's being dragged, but the mouse state says
194  * otherwise, stop dragging. */
195  color_picker->elements[type].dragging = 0;
196  }
197 
198  if (type == COLOR_PICKER_ELEM_COLOR) {
199  int selx, sely;
200  uint32_t pixel;
201 
202  selx = 0;
203  sely = 0;
204  hsv[0] = color_picker->hsv[0];
205 
206  for (x = 0; x < box.w; x++) {
207  hsv[2] = 1.0 * ((double) x / (box.w - 1));
208 
209  /* If this is the currently selected value, store the X coordinate.
210  * */
211  if (color_picker->hsv[2] >= hsv[2] && color_picker->hsv[2] < hsv[2] + (1.0 * (1.0 / (double) box.w))) {
212  selx = x;
213  }
214 
215  for (y = 0; y < box.h; y++) {
216  hsv[1] = fabs(1.0 * ((double) y / (box.h - 1)) - 1.0);
217 
218  /* If this is the currently selected saturation, store the Y
219  * coordinate. */
220  if (color_picker->hsv[1] >= hsv[1] && color_picker->hsv[1] < hsv[1] + (1.0 * (1.0 / (double) box.h))) {
221  sely = y;
222  }
223 
224  colorspace_hsv2rgb(hsv, rgb);
225 
226  dest.x = box.x + x;
227  dest.y = box.y + y;
228  dest.w = 1;
229  dest.h = 1;
230 
231  if (event) {
232  if (mx >= dest.x && my >= dest.y && mx < dest.x + dest.w && my < dest.y + dest.h) {
233  color_picker->hsv[1] = hsv[1];
234  color_picker->hsv[2] = hsv[2];
235  return 1;
236  }
237 
238  continue;
239  }
240 
241  putpixel(surface, dest.x, dest.y, SDL_MapRGB(surface->format, 255 * rgb[0], 255 * rgb[1], 255 * rgb[2]));
242  }
243  }
244 
245  /* Draw the crosshair for saturation/value. */
246  if (surface) {
247  for (x = 0; x < box.w; x++) {
248  pixel = getpixel(surface, box.x + x, box.y + sely);
249  SDL_GetRGB(pixel, surface->format, &r, &g, &b);
250  putpixel(surface, box.x + x, box.y + sely, SDL_MapRGB(surface->format, 255 - r, 255 - g, 255 - b));
251  }
252 
253  for (y = 0; y < box.h; y++) {
254  pixel = getpixel(surface, box.x + selx, box.y + y);
255  SDL_GetRGB(pixel, surface->format, &r, &g, &b);
256  putpixel(surface, box.x + selx, box.y + y, SDL_MapRGB(surface->format, 255 - r, 255 - g, 255 - b));
257  }
258  }
259  } else if (type == COLOR_PICKER_ELEM_HUE) {
260  hsv[1] = hsv[2] = 1.0;
261 
262  for (y = 0; y < box.h; y++) {
263  hsv[0] = fabs(1.0 * ((double) y / (double) (box.h - 1)) - 1.0);
264  colorspace_hsv2rgb(hsv, rgb);
265 
266  dest.x = box.x;
267  dest.y = box.y + y;
268  dest.w = box.w;
269  dest.h = 1;
270 
271  if (event) {
272  if (mx >= dest.x && my >= dest.y && mx < dest.x + dest.w && my < dest.y + dest.h) {
273  color_picker->hsv[0] = hsv[0];
274  return 1;
275  }
276 
277  continue;
278  }
279 
280  r = 255 * rgb[0];
281  g = 255 * rgb[1];
282  b = 255 * rgb[2];
283 
284  /* If this is the currently selected hue, invert the colors. */
285  if (color_picker->hsv[0] >= hsv[0] && color_picker->hsv[0] < hsv[0] + (1.0 * (1.0 / (double) box.h))) {
286  r = 255 - r;
287  g = 255 - g;
288  b = 255 - b;
289  }
290 
291  SDL_FillRect(surface, &dest, SDL_MapRGB(surface->format, r, g, b));
292  }
293  }
294 
295  return 0;
296 }
297 
305 void color_picker_show(SDL_Surface *surface, color_picker_struct *color_picker)
306 {
307  size_t i;
308 
309  for (i = 0; i < COLOR_PICKER_ELEM_NUM; i++) {
310  color_picker_element_show(surface, color_picker, i, NULL);
311  }
312 }
313 
323 int color_picker_event(color_picker_struct *color_picker, SDL_Event *event)
324 {
325  if ((event->type == SDL_MOUSEBUTTONDOWN || event->type == SDL_MOUSEMOTION) && event->button.button == SDL_BUTTON_LEFT) {
326  size_t i;
327 
328  for (i = 0; i < COLOR_PICKER_ELEM_NUM; i++) {
329  if (color_picker_element_show(NULL, color_picker, i, event)) {
330  if (color_picker->callback_func) {
331  color_picker->callback_func(color_picker);
332  }
333 
334  color_picker->elements[i].dragging = 1;
335  return 1;
336  }
337  }
338  }
339 
340  return 0;
341 }
342 
354 int color_picker_mouse_over(color_picker_struct *color_picker, int mx, int my)
355 {
356  size_t i;
357  int x, y;
358 
359  mx -= color_picker->px;
360  my -= color_picker->py;
361 
362  for (i = 0; i < COLOR_PICKER_ELEM_NUM; i++) {
363  x = color_picker->x + color_picker->elements[i].coords.x;
364  y = color_picker->y + color_picker->elements[i].coords.y;
365 
366  if (mx >= x && my >= y && mx < x + color_picker->elements[i].coords.w && my < y + color_picker->elements[i].coords.h) {
367  return 1;
368  }
369  }
370 
371  return 0;
372 }
int text_color_parse(const char *color_notation, SDL_Color *color)
Definition: text.c:603
void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
Definition: sprite.c:950
Uint32 getpixel(SDL_Surface *surface, int x, int y)
Definition: sprite.c:910
color_picker_element_struct elements[COLOR_PICKER_ELEM_NUM]
Definition: color_picker.h:93
uint8_t border_thickness
Definition: color_picker.h:98
void border_create_color(SDL_Surface *surface, SDL_Rect *coords, int thickness, const char *color_notation)
Definition: sprite.c:1359