Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Button.cpp
Go to the documentation of this file.
1 /* Project nGenEx
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: nGenEx.lib
6  FILE: Button.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Button class
13 */
14 
15 #include "MemDebug.h"
16 #include "Button.h"
17 #include "Video.h"
18 #include "Bitmap.h"
19 #include "Font.h"
20 #include "Sound.h"
21 #include "DataLoader.h"
22 
23 // +--------------------------------------------------------------------+
24 
25 static Sound* button_sound = 0;
26 static Sound* click_sound = 0;
27 static Sound* swish_sound = 0;
28 static Sound* chirp_sound = 0;
29 static Sound* accept_sound = 0;
30 static Sound* reject_sound = 0;
31 static Sound* confirm_sound = 0;
32 static Sound* list_select_sound = 0;
33 static Sound* list_scroll_sound = 0;
34 static Sound* list_drop_sound = 0;
35 static Sound* combo_open_sound = 0;
36 static Sound* combo_close_sound = 0;
37 static Sound* combo_hilite_sound = 0;
38 static Sound* combo_select_sound = 0;
39 static Sound* menu_open_sound = 0;
40 static Sound* menu_close_sound = 0;
41 static Sound* menu_select_sound = 0;
42 static Sound* menu_hilite_sound = 0;
43 
44 static int gui_volume = 0;
45 
46 // +--------------------------------------------------------------------+
47 
48 Button::Button(Screen* s, int ax, int ay, int aw, int ah, DWORD aid)
49 : ActiveWindow(s, ax, ay, aw, ah, aid)
50 {
51  animated = true;
52  bevel_width = 5;
53  border = false;
54  button_state = 0;
55  drop_shadow = false;
56  sticky = false;
57  picture_loc = 1;
58  captured = 0;
59  pre_state = 0;
60  text_align = DT_CENTER;
61 
62  standard_image = 0;
63  activated_image = 0;
64  transition_image = 0;
65 
66  char buf[32];
67  sprintf_s(buf, "Button %d", id);
68  desc = buf;
69 }
70 
71 Button::Button(ActiveWindow* p, int ax, int ay, int aw, int ah, DWORD aid)
72 : ActiveWindow(p->GetScreen(), ax, ay, aw, ah, aid, 0, p)
73 {
74  animated = true;
75  bevel_width = 5;
76  border = false;
77  button_state = 0;
78  drop_shadow = false;
79  sticky = false;
80  picture_loc = 1;
81  captured = 0;
82  pre_state = 0;
83  text_align = DT_CENTER;
84 
85  standard_image = 0;
86  activated_image = 0;
87  transition_image = 0;
88 
89  char buf[32];
90  sprintf_s(buf, "Button %d", id);
91  desc = buf;
92 }
93 
94 // +--------------------------------------------------------------------+
95 
97 {
98 }
99 
100 // +--------------------------------------------------------------------+
101 
102 static void LoadInterfaceSound(DataLoader* loader, const char* wave, Sound*& s)
103 {
104  loader->LoadSound(wave, s, 0, true); // optional sound effect
105 
106  if (s)
108 }
109 
110 void
112 {
113  DataLoader* loader = DataLoader::GetLoader();
114  loader->SetDataPath("Sounds/");
115 
116  LoadInterfaceSound(loader, "button.wav", button_sound);
117  LoadInterfaceSound(loader, "click.wav", click_sound);
118  LoadInterfaceSound(loader, "swish.wav", swish_sound);
119  LoadInterfaceSound(loader, "chirp.wav", chirp_sound);
120  LoadInterfaceSound(loader, "accept.wav", accept_sound);
121  LoadInterfaceSound(loader, "reject.wav", reject_sound);
122  LoadInterfaceSound(loader, "confirm.wav", confirm_sound);
123  LoadInterfaceSound(loader, "list_select.wav", list_select_sound);
124  LoadInterfaceSound(loader, "list_scroll.wav", list_scroll_sound);
125  LoadInterfaceSound(loader, "list_drop.wav", list_drop_sound);
126  LoadInterfaceSound(loader, "combo_open.wav", combo_open_sound);
127  LoadInterfaceSound(loader, "combo_close.wav", combo_close_sound);
128  LoadInterfaceSound(loader, "combo_hilite.wav", combo_hilite_sound);
129  LoadInterfaceSound(loader, "combo_select.wav", combo_select_sound);
130  LoadInterfaceSound(loader, "menu_open.wav", menu_open_sound);
131  LoadInterfaceSound(loader, "menu_close.wav", menu_close_sound);
132  LoadInterfaceSound(loader, "menu_select.wav", menu_select_sound);
133  LoadInterfaceSound(loader, "menu_hilite.wav", menu_hilite_sound);
134 
135  loader->SetDataPath(0);
136 }
137 
138 // +--------------------------------------------------------------------+
139 
140 void
142 {
143  delete button_sound;
144  delete click_sound;
145  delete swish_sound;
146  delete chirp_sound;
147  delete accept_sound;
148  delete reject_sound;
149  delete confirm_sound;
150  delete list_select_sound;
151  delete list_scroll_sound;
152  delete list_drop_sound;
153  delete combo_open_sound;
154  delete combo_close_sound;
155  delete combo_hilite_sound;
156  delete combo_select_sound;
157  delete menu_open_sound;
158  delete menu_close_sound;
159  delete menu_select_sound;
160  delete menu_hilite_sound;
161 }
162 
163 // +--------------------------------------------------------------------+
164 
165 void
167 {
168  if (!IsShown()) return;
169 
170  int x = 0;
171  int y = 0;
172  int w = rect.w;
173  int h = rect.h;
174  int img_w = picture.Width();
175  int img_h = picture.Height();
176 
177  float old_alpha = alpha;
178 
179  if (!enabled)
180  SetAlpha(0.35);
181 
182  Rect btn_rect(x,y,w,h);
183 
184  if (!transparent) {
185  if (standard_image) {
186  if (!enabled) {
188  }
189 
190  else {
191  switch (button_state) {
192  case -1:
194  break;
195 
196  default:
197  case 0:
199  break;
200 
201  case 1:
202  if (sticky)
204  else
206  break;
207 
208  case 2:
210  break;
211  }
212  }
213 
214  if (!texture)
216 
217  DrawTextureGrid();
218  }
219 
220  else {
221  FillRect(0, 0, w, h, ShadeColor(back_color, 1.0));
222  DrawStyleRect(0, 0, w, h, style);
223  }
224  }
225 
226  // draw the picture (if any)
227  if (picture.Width()) {
228  Rect irect = CalcPictureRect();
229  DrawImage(&picture, irect);
230  }
231 
232  // draw text here:
233  if (font && text.length()) {
234  Rect label_rect = CalcLabelRect(img_w,img_h);
235  int vert_space = label_rect.h;
236  int horz_space = label_rect.w;
237  int align = DT_WORDBREAK | text_align;
238 
239  DrawText(text.data(), 0, label_rect, DT_CALCRECT | align);
240  vert_space = (vert_space - label_rect.h)/2;
241 
242  label_rect.w = horz_space;
243 
244  if (vert_space > 0)
245  label_rect.y += vert_space;
246 
247  if (animated && button_state > 0) {
248  label_rect.x += button_state;
249  label_rect.y += button_state;
250  }
251 
252  if (drop_shadow) {
253  label_rect.x++;
254  label_rect.y++;
255 
257  DrawText(text.data(), text.length(), label_rect, align);
258 
259  label_rect.x--;
260  label_rect.y--;
261  }
262 
264  DrawText(text.data(), text.length(), label_rect, align);
265  }
266 
267  if (!enabled)
268  SetAlpha(old_alpha);
269 }
270 
271 Rect Button::CalcLabelRect(int img_w, int img_h)
272 {
273  // fit the text in the bevel:
274  Rect label_rect;
275  label_rect.x = 0;
276  label_rect.y = 0;
277  label_rect.w = rect.w;
278  label_rect.h = rect.h;
279 
280  if (text_align == DT_LEFT)
281  label_rect.Deflate(bevel_width + 8, bevel_width + 1);
282  else
283  label_rect.Deflate(bevel_width + 1, bevel_width + 1);
284 
285  // and around the picture, if any:
286  if (img_h != 0)
287  {
288  switch (picture_loc)
289  {
290  default:
291  case 0: // the four corner positions
292  case 2: // and the center position
293  case 4: // don't affect the text position
294  case 6:
295  case 8:
296  break;
297 
298  case 1: // north
299  label_rect.y += img_h;
300  label_rect.h -= img_h;
301  break;
302 
303  case 3: // west
304  label_rect.x += img_w;
305  label_rect.w -= img_w;
306  break;
307 
308  case 5: // east
309  label_rect.w -= img_w;
310  break;
311 
312  case 7: // south
313  label_rect.h -= img_h;
314  break;
315  }
316  }
317 
318  return label_rect;
319 }
320 
321 // +--------------------------------------------------------------------+
322 
323 Rect
325 {
326  int w = rect.w;
327  int h = rect.h;
328  int img_w = picture.Width();
329  int img_h = picture.Height();
330 
331  if (img_h > h) img_h = h-2;
332  if (img_w > w) img_w = w-2;
333 
334  int img_x_offset = bevel_width;
335  int img_y_offset = bevel_width;
336 
337  switch (picture_loc)
338  {
339  default:
340  // TOP ROW:
341  case 0: break;
342 
343  case 1: img_x_offset = (w/2-img_w/2);
344  break;
345 
346  case 2: img_x_offset = w - img_w - bevel_width;
347  break;
348 
349  // MIDDLE ROW:
350  case 3: img_y_offset = (h/2-img_h/2);
351  break;
352  case 4: img_x_offset = (w/2-img_w/2);
353  img_y_offset = (h/2-img_h/2);
354  break;
355  case 5: img_x_offset = w - img_w - bevel_width;
356  img_y_offset = (h/2-img_h/2);
357  break;
358 
359  // BOTTOM ROW:
360  case 6:
361  img_y_offset = h - img_h - bevel_width;
362  break;
363  case 7: img_x_offset = (w/2-img_w/2);
364  img_y_offset = h - img_h - bevel_width;
365  break;
366  case 8: img_x_offset = w - img_w - bevel_width;
367  img_y_offset = h - img_h - bevel_width;
368  break;
369  }
370 
371  Rect img_rect;
372  img_rect.x = img_x_offset;
373  img_rect.y = img_y_offset;
374 
375  if (animated && button_state > 0) {
376  img_rect.x += button_state;
377  img_rect.y += button_state;
378  }
379 
380  img_rect.w = img_w;
381  img_rect.h = img_h;
382 
383  return img_rect;
384 }
385 
386 // +--------------------------------------------------------------------+
387 
388 void
389 Button::DrawImage(Bitmap* bmp, const Rect& irect)
390 {
391  if (bmp) {
392  DrawBitmap(irect.x,
393  irect.y,
394  irect.x + irect.w,
395  irect.y + irect.h,
396  bmp,
398  }
399 }
400 
401 // +--------------------------------------------------------------------+
402 
403 int Button::OnMouseMove(int x, int y)
404 {
405  bool dirty = false;
406 
407  if (captured)
408  {
409  ActiveWindow* test = GetCapture();
410 
411  if (test != this)
412  {
413  captured = false;
415  dirty = true;
416  }
417 
418  else if (sticky)
419  {
420  if (button_state == 2)
421  {
422  if (!rect.Contains(x,y))
423  {
425  dirty = true;
426  }
427  }
428  else
429  {
430  if (rect.Contains(x,y))
431  {
432  button_state = 2;
433  dirty = true;
434  }
435  }
436  }
437  else
438  {
439  if (button_state == 1)
440  {
441  if (!rect.Contains(x,y))
442  {
443  button_state = 0;
444  dirty = true;
445  }
446  }
447  else
448  {
449  if (rect.Contains(x,y))
450  {
451  button_state = 1;
452  dirty = true;
453  }
454  }
455  }
456  }
457 
458  return ActiveWindow::OnMouseMove(x,y);
459 }
460 
461 int Button::OnLButtonDown(int x, int y)
462 {
463  if (!captured)
464  captured = SetCapture();
465 
466  if (sticky)
467  button_state = 2;
468  else
469  button_state = 1;
470 
471  return ActiveWindow::OnLButtonDown(x,y);
472 }
473 
474 int Button::OnLButtonUp(int x, int y)
475 {
476  if (captured) {
477  ReleaseCapture();
478  captured = 0;
479  }
480 
482  return ActiveWindow::OnLButtonUp(x,y);
483 }
484 
485 void Button::SetVolume(int vol)
486 {
487  if (vol >= -10000 && vol <= 0)
488  gui_volume = vol;
489 }
490 
491 void Button::PlaySound(int n)
492 {
493  Sound* sound = 0;
494 
495  switch (n) {
496  default:
497  case SND_BUTTON: if (button_sound) sound = button_sound->Duplicate(); break;
498  case SND_CLICK: if (click_sound) sound = click_sound->Duplicate(); break;
499  case SND_SWISH: if (swish_sound) sound = swish_sound->Duplicate(); break;
500  case SND_CHIRP: if (chirp_sound) sound = chirp_sound->Duplicate(); break;
501  case SND_ACCEPT: if (accept_sound) sound = accept_sound->Duplicate(); break;
502  case SND_REJECT: if (reject_sound) sound = reject_sound->Duplicate(); break;
503  case SND_CONFIRM: if (confirm_sound) sound = confirm_sound->Duplicate(); break;
504  case SND_LIST_SELECT: if (list_select_sound) sound = list_select_sound->Duplicate(); break;
505  case SND_LIST_SCROLL: if (list_scroll_sound) sound = list_scroll_sound->Duplicate(); break;
506  case SND_LIST_DROP: if (list_drop_sound) sound = list_drop_sound->Duplicate(); break;
507  case SND_COMBO_OPEN: if (combo_open_sound) sound = combo_open_sound->Duplicate(); break;
508  case SND_COMBO_CLOSE: if (combo_close_sound) sound = combo_close_sound->Duplicate(); break;
509  case SND_COMBO_HILITE: if (combo_hilite_sound) sound = combo_hilite_sound->Duplicate(); break;
510  case SND_COMBO_SELECT: if (combo_select_sound) sound = combo_select_sound->Duplicate(); break;
511  case SND_MENU_OPEN: if (menu_open_sound) sound = menu_open_sound->Duplicate(); break;
512  case SND_MENU_CLOSE: if (menu_close_sound) sound = menu_close_sound->Duplicate(); break;
513  case SND_MENU_SELECT: if (menu_select_sound) sound = menu_select_sound->Duplicate(); break;
514  case SND_MENU_HILITE: if (menu_hilite_sound) sound = menu_hilite_sound->Duplicate(); break;
515  }
516 
517  if (sound) {
518  sound->SetVolume(gui_volume);
519  sound->Play();
520  }
521 }
522 
524 {
526 
527  if (sticky)
529 
531 
532  return ActiveWindow::OnClick();
533 }
534 
535 int Button::OnMouseEnter(int mx, int my)
536 {
537  if (button_state >= 0)
539 
540  if (button_state == 0)
541  button_state = -1;
542 
543  if (IsEnabled() && IsShown())
545 
546  return ActiveWindow::OnMouseEnter(mx, my);
547 }
548 
549 int Button::OnMouseExit(int mx, int my)
550 {
551  if (button_state == -1)
553 
554  return ActiveWindow::OnMouseExit(mx, my);
555 }
556 
557 // +--------------------------------------------------------------------+
558 
560 {
561  standard_image = img;
563 }
564 
566 {
567  activated_image = img;
568 }
569 
571 {
572  transition_image = img;
573 }
574 
575 // +--------------------------------------------------------------------+
576 
578 {
579  return bevel_width;
580 }
581 
582 void Button::SetBevelWidth(short nNewValue)
583 {
584  if (nNewValue < 0) nNewValue = 0;
585  if (nNewValue > rect.w/2) nNewValue = rect.w/2;
586  bevel_width = nNewValue;
587 }
588 
590 {
591  return border;
592 }
593 
594 void Button::SetBorder(bool bNewValue)
595 {
596  border = bNewValue;
597 }
598 
600 {
601  return border_color;
602 }
603 
605 {
606  border_color = newValue;
607 }
608 
610 {
611  return active_color;
612 }
613 
615 {
616  active_color = newValue;
617 }
618 
620 {
621  return animated;
622 }
623 
624 void Button::SetAnimated(bool bNewValue)
625 {
626  animated = bNewValue;
627 }
628 
630 {
631  return drop_shadow;
632 }
633 
634 void Button::SetDropShadow(bool bNewValue)
635 {
636  drop_shadow = bNewValue;
637 }
638 
639 // +--------------------------------------------------------------------+
640 
642 {
643  return button_state;
644 }
645 
647 {
648  if (button_state != n && n >= -2 && n <= 2) {
649  button_state = n;
650  pre_state = n;
651  }
652 }
653 
655 {
656  img.CopyBitmap(picture);
657 }
658 
659 void Button::SetPicture(const Bitmap& img)
660 {
661  picture.CopyBitmap(img);
662  picture.AutoMask();
663 }
664 
666 {
667  return picture_loc;
668 }
669 
671 {
672  if (picture_loc != n && n >= 0 && n <= 8) {
673  picture_loc = n;
674  }
675 }
676 
678 {
679  return sticky;
680 }
681 
682 void Button::SetSticky(bool n)
683 {
684  if (sticky != n)
685  sticky = n;
686 }
687