[AD] Exhaustive haptics example program ex_haptic2.cpp

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


I wrote an exhaustive example program for trying and playing haptic effects
using nihgui.cpp. I also had to make some modifications to nihgui to make
the font look pretty in buttons and also to make controls support being set to
"disabled". I checked the other programs that use nihgui and they seem fine.

Oh, and as an aside, I noticed becuse I used valgrind, and it seems the use
of gtk for native dialogs is full of memory leaks?

Kind Regards,

B.
From ccdb87763fac4bc1d9211110129c83fd65531ed2 Mon Sep 17 00:00:00 2001
From: Beoran <beoran@xxxxxxxxx>
Date: Sun, 7 Jul 2013 21:37:58 +0200
Subject: [PATCH 1/8] Starting with exhaustive haptics example program with
 NIHGUI gui.

---
 examples/CMakeLists.txt |    1 +
 1 file changed, 1 insertion(+)

diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index f45c0da..bf6b31d 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -136,6 +136,7 @@ example(ex_fs_window ${IMAGE} ${PRIM} ${FONT})
 example(ex_icon ${IMAGE})
 example(ex_icon2 ${IMAGE})
 example(ex_haptic ${PRIM})
+example(ex_haptic2  ex_haptic2.cpp ${NIHGUI} ${PRIM} ${FONT})
 example(ex_joystick_events ${PRIM} ${FONT})
 example(ex_joystick_hotplugging ${PRIM})
 example(ex_keyboard_events)
-- 
1.7.10.4


From 5235e4f7b68fab9f3a34f4b11521ae5a54005ada Mon Sep 17 00:00:00 2001
From: Beoran <beoran@xxxxxxxxx>
Date: Sun, 7 Jul 2013 23:22:20 +0200
Subject: [PATCH 2/8] A GUI for haptic effect testing.  The program ex_haptic2
 needs tons of sliders and labels.

---
 examples/ex_haptic2.cpp |  383 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 383 insertions(+)
 create mode 100644 examples/ex_haptic2.cpp

diff --git a/examples/ex_haptic2.cpp b/examples/ex_haptic2.cpp
new file mode 100644
index 0000000..1b5598c
--- /dev/null
+++ b/examples/ex_haptic2.cpp
@@ -0,0 +1,383 @@
+/*
+ *    Example program for the Allegro library, by Peter Wang.
+ *
+ *    Compare software blending routines with hardware blending.
+ */
+
+#include <string>
+
+#include "allegro5/allegro.h"
+
+#include "allegro5/allegro_font.h"
+#include "allegro5/allegro_image.h"
+#include <allegro5/allegro_primitives.h>
+
+#include "common.c"
+
+#include "nihgui.hpp"
+
+#define EX_HAPTIC2_MAX_HAPTICS 8
+
+ALLEGRO_HAPTIC      *    haptics[EX_HAPTIC2_MAX_HAPTICS];
+ALLEGRO_HAPTIC_EFFECT    haptic_effects[EX_HAPTIC2_MAX_HAPTICS];
+ALLEGRO_HAPTIC_EFFECT_ID haptic_ids[EX_HAPTIC2_MAX_HAPTICS];
+char                   * haptic_name[EX_HAPTIC2_MAX_HAPTICS];
+int                      num_haptics;
+
+struct CapacityName { 
+  int   value;
+  const char * name; 
+};
+
+CapacityName capname[] = {
+  { ALLEGRO_HAPTIC_RUMBLE   , "rumble"   },  
+  { ALLEGRO_HAPTIC_PERIODIC , "periodic" },
+  { ALLEGRO_HAPTIC_CONSTANT , "constant" }, 
+  { ALLEGRO_HAPTIC_SPRING   , "spring"   },
+  { ALLEGRO_HAPTIC_FRICTION , "friction" },
+  { ALLEGRO_HAPTIC_DAMPER   , "damper"   },
+  { ALLEGRO_HAPTIC_INERTIA  , "inertia"  },
+  { ALLEGRO_HAPTIC_RAMP     , "ramp"     }, 
+  { ALLEGRO_HAPTIC_SQUARE   , "square"   },
+  { ALLEGRO_HAPTIC_TRIANGLE , "triangle" },
+  { ALLEGRO_HAPTIC_SINE     , "sine"     },
+  { ALLEGRO_HAPTIC_SAW_UP   , "saw up"   },
+  { ALLEGRO_HAPTIC_SAW_DOWN , "saw down" },
+  { ALLEGRO_HAPTIC_CUSTOM   , "custom"   },
+  { ALLEGRO_HAPTIC_GAIN     , "gain"     },
+  { ALLEGRO_HAPTIC_ANGLE    , "angle"    },
+  { ALLEGRO_HAPTIC_RADIUS   , "radius"   },
+  { ALLEGRO_HAPTIC_AZIMUTH  , "azimuth"  }
+};
+
+#define EX_HAPTIC2_START_TYPES   0
+#define EX_HAPTIC2_MAX_TYPES     8
+#define EX_HAPTIC2_END_TYPES     8
+
+#define EX_HAPTIC2_START_WAVES   8
+#define EX_HAPTIC2_END_WAVES    13
+#define EX_HAPTIC2_MAX_WAVES     5
+/* Ignore custom waveforms for now... */
+
+#define EX_HAPTIC2_START_COORDS 15
+#define EX_HAPTIC2_MAX_COORDS    3
+#define EX_HAPTIC2_END_COORDS   18
+
+
+
+
+class Prog {
+private:
+   Dialog d;  
+   
+   List  device_list;
+   List  type_list;
+   List  waveform_list;
+   
+   Label device_label;  
+   Label type_label;
+   Label waveform_label;
+   
+   HSlider length_slider, delay_slider, loops_slider;
+   Label replay_label, length_label, delay_label, loops_label;
+   
+   HSlider attack_length_slider, attack_level_slider;
+   HSlider fade_length_slider, fade_level_slider;
+   Label envelope_label, attack_length_label, attack_level_label;
+   Label fade_length_label, fade_level_label;
+   
+   HSlider angle_slider, radius_slider, azimuth_slider;
+   Label   coordinates_label, angle_label , radius_label , azimuth_label;
+   
+   HSlider level_slider;
+   Label   constant_effect_label, level_label;
+   
+   HSlider start_level_slider, end_level_slider;
+   Label ramp_effect_label, start_level_label, end_level_label;
+
+   HSlider right_saturation_slider, right_coeff_slider;
+   HSlider left_saturation_slider , left_coeff_slider;
+   HSlider deadband_slider        , center_slider;
+   
+   Label right_saturation_label, right_coeff_label;
+   Label left_saturation_label , left_coeff_label;
+   Label condition_effect_label, deadband_label, center_label;
+   
+   HSlider period_slider, magnitude_slider, offset_slider, phase_slider;
+   Label periodic_effect_label; 
+   Label period_label, magnitude_label, offset_label, phase_label;
+   
+   HSlider strong_magnitude_slider, weak_magnitude_slider;
+   Label rumble_effect_label, strong_magnitude_label, weak_magnitude_label;
+
+   HSlider gain_slider;
+   Label gain_label;
+   
+   Button play_button;
+   Button stop_button;
+   
+   
+public:
+   Prog(const Theme & theme, ALLEGRO_DISPLAY *display);
+   void run();
+
+private:
+   /*
+    * void play_effect();
+   void stop_effect();};
+   */
+};
+
+
+Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) :
+   d(Dialog(theme, display, 20, 40)),
+   device_list(0),
+   type_list(0),
+   waveform_list(0),
+   device_label("Haptic Device"),
+   type_label("Haptic Effect Type"), 
+   waveform_label("Wave Form Periodic Effect"),
+   length_slider(1, 10),
+   delay_slider(1, 10),
+   loops_slider(1, 10), 
+   replay_label("replay"),
+   length_label("length", false),
+   delay_label("delay", false),
+   loops_label("loops"),   
+   attack_length_slider(1, 10),
+   attack_level_slider(5, 10),
+   fade_length_slider(5, 10),
+   fade_level_slider(1, 10),
+   envelope_label("envelope"),
+   attack_length_label("attack length", false),
+   attack_level_label("attack level", false),
+   fade_length_label("fade length", false),
+   fade_level_label("fade level", false),
+   angle_slider(0, 360), radius_slider(0, 10), azimuth_slider(180, 360),
+   coordinates_label("coordinates"),
+   angle_label("angle", false), 
+   radius_label("radius", false), 
+   azimuth_label("azimuth", false),
+   level_slider(5, 10), 
+   constant_effect_label("constant effect"),
+   level_label("level", false),
+   start_level_slider(3, 10), end_level_slider(7, 10), 
+   ramp_effect_label("ramp effect"),
+   start_level_label("start level", false),
+   end_level_label("end level", false),
+   right_saturation_slider(5, 10) , right_coeff_slider(5, 10),
+   left_saturation_slider(5, 10)  , left_coeff_slider(5, 10),
+   deadband_slider(1, 10)         , center_slider(5,10),
+   right_saturation_label("right saturation", false), 
+   right_coeff_label("right coefficient", false),
+   left_saturation_label("left saturation", false), 
+   left_coeff_label("left coefficient", false),
+   condition_effect_label("condition effect"),
+   deadband_label("deadband", false), 
+   center_label("center", false),
+   period_slider(1, 10), magnitude_slider(5, 10), 
+   offset_slider(0, 10), phase_slider(0, 10),
+   periodic_effect_label("periodic effect"), 
+   period_label("period", false), 
+   magnitude_label("magnitude", false), 
+   offset_label("offset", false), 
+   phase_label("phase", false),
+   strong_magnitude_slider(5, 10), 
+   weak_magnitude_slider(5, 10),
+   rumble_effect_label("rumble effect"),
+   strong_magnitude_label("strong magnitude", false), 
+   weak_magnitude_label("weak magnitude", false),
+   gain_slider(10, 10),
+   gain_label("gain"),
+   play_button("Play"),
+   stop_button("Stop") 
+{
+  for (int i = 0; i < num_haptics; i++) {
+    device_list.append_item(haptic_name[i]);
+  } 
+  d.add(device_label, 0, 1, 7, 1); 
+  d.add(device_list , 0, 2, 7, 8);
+
+  
+   for (int i = EX_HAPTIC2_START_TYPES  ; i < EX_HAPTIC2_END_TYPES  ; i++) {
+     type_list.append_item(capname[i].name);
+   }
+   d.add(type_label, 7, 1, 6, 1);    
+   d.add(type_list , 7, 2, 6, 8);
+   
+   for (int i = EX_HAPTIC2_START_WAVES  ; i < EX_HAPTIC2_END_WAVES  ; i++) {
+     waveform_list.append_item(capname[i].name);
+   }
+   d.add(waveform_label, 13, 1, 7, 1); 
+   d.add(waveform_list , 13, 2, 7, 8);
+   
+   d.add(replay_label , 0, 10 , 7, 1);
+   d.add(length_label , 0, 11 , 2, 1);
+   d.add(length_slider, 2, 11 , 5, 1);
+   d.add(delay_label  , 0, 12 , 2, 1);
+   d.add(delay_slider , 2, 12 , 5, 1);
+   d.add(loops_label  , 0, 13 , 7, 1);
+   d.add(loops_slider , 2, 14 , 5, 1);
+   d.add(gain_label   , 0, 15 , 7, 1);
+   d.add(gain_slider  , 2, 16 , 5, 1);
+   
+   d.add(envelope_label         , 7 , 10, 6, 1);
+   d.add(attack_length_label    , 7 , 11, 3, 1);
+   d.add(attack_length_slider   , 10, 11, 3, 1);
+   d.add(attack_level_label     , 7 , 12, 3, 1);
+   d.add(attack_level_slider    , 10, 12, 3, 1);
+   d.add(fade_length_label      , 7 , 13, 3, 1);
+   d.add(fade_length_slider     , 10, 13, 3, 1);
+   d.add(fade_level_label       , 7 , 14, 3, 1);
+   d.add(fade_level_slider      , 10, 14, 3, 1);
+   
+   d.add(coordinates_label      , 13, 10, 7, 1);
+   d.add(angle_label            , 13, 11, 2, 1);
+   d.add(angle_slider           , 15, 11, 5, 1);
+   d.add(radius_label           , 13, 12, 2, 1);
+   d.add(radius_slider          , 15, 12, 5, 1);
+   d.add(azimuth_label          , 13, 13, 2, 1);
+   d.add(azimuth_slider         , 15, 13, 5, 1);
+  
+   d.add(condition_effect_label ,  0, 18, 7, 1); 
+   d.add(right_coeff_label      ,  0, 19, 4, 1);
+   d.add(right_coeff_slider     ,  4, 19, 3, 1);
+   d.add(right_saturation_label ,  0, 20, 4, 1);
+   d.add(right_saturation_slider,  4, 20, 3, 1);  
+   d.add(left_coeff_label       ,  0, 21, 4, 1);
+   d.add(left_coeff_slider      ,  4, 21, 3, 1);
+   d.add(left_saturation_label  ,  0, 22, 4, 1);
+   d.add(left_saturation_slider ,  4, 22, 3, 1);
+   d.add(deadband_label         ,  0, 23, 4, 1);
+   d.add(deadband_slider        ,  4, 23, 3, 1);
+   d.add(center_label           ,  0, 24, 4, 1);
+   d.add(center_slider          ,  4, 24, 3, 1);
+   
+   d.add(constant_effect_label  ,  7, 18, 6, 1);
+   d.add(level_label            ,  7, 19, 3, 1);
+   d.add(level_slider           , 10, 19, 3, 1);
+   
+   d.add(periodic_effect_label  , 13, 18, 7, 1);
+   d.add(period_label           , 13, 19, 7, 1);
+   d.add(period_slider          , 15, 19, 5, 1);
+   d.add(magnitude_label        , 13, 20, 2, 1);
+   d.add(magnitude_slider       , 15, 20, 5, 1);
+   d.add(offset_label           , 13, 21, 2, 1);
+   d.add(offset_slider          , 15, 21, 5, 1);
+   d.add(phase_label            , 13, 22, 2, 1);
+   d.add(phase_slider           , 15, 22, 5, 1);
+   
+  
+   d.add(play_button  , 6, 38, 3, 1); 
+   d.add(stop_button  , 12, 38, 3, 1); 
+
+   
+   /*
+   rgba_label[0] = Label("Source tint/color RGBA");
+   rgba_label[1] = Label("Dest tint/color RGBA");
+   d.add(rgba_label[0], 1, 34, 5, 1);
+   d.add(rgba_label[1], 7, 34, 5, 1);
+
+   for (int i = 0; i < 2; i++) {
+      r[i] = HSlider(255, 255);
+      g[i] = HSlider(255, 255);
+      b[i] = HSlider(255, 255);
+      a[i] = HSlider(255, 255);
+      d.add(r[i], 1 + i * 6, 35, 5, 1);
+      d.add(g[i], 1 + i * 6, 36, 5, 1);
+      d.add(b[i], 1 + i * 6, 37, 5, 1);
+      d.add(a[i], 1 + i * 6, 38, 5, 1);
+   }
+   */
+}
+
+void Prog::run()
+{
+   d.prepare();
+
+   while (!d.is_quit_requested()) {
+      if (d.is_draw_requested()) {
+         al_clear_to_color(al_map_rgb(128, 128, 128));
+         d.draw();
+         al_flip_display();
+      }
+
+      d.run_step(true);
+   }
+}
+
+
+
+
+int main(int argc, char *argv[])
+{
+   ALLEGRO_DISPLAY *display;
+   ALLEGRO_FONT *font;
+
+   (void)argc;
+   (void)argv;
+
+   if (!al_init()) {
+      abort_example("Could not init Allegro\n");
+   }
+   al_init_primitives_addon();
+   al_install_keyboard();
+   al_install_mouse();
+   al_install_joystick();
+   al_install_haptic();
+
+   al_init_font_addon();
+ 
+   al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS);
+   display = al_create_display(800, 600);
+   if (!display) {
+      abort_example("Unable to create display\n");
+   }
+   
+    
+   font = al_create_builtin_font();
+   if (!font) {
+      abort_example("Failed to create builtin font.\n");
+   }
+   
+   /*
+   font = al_load_font("data/fixed_font.tga", 0, 0);
+   if (!font) {
+      abort_example("Failed to load data/fixed_font.tga\n");
+   }
+   */
+   
+   num_haptics = 0;
+   
+   if(al_is_display_haptic(al_get_current_display())) {
+     haptics[num_haptics]    = al_get_haptic_from_display(al_get_current_display());
+     haptic_name[num_haptics]= (char *)"display";
+     num_haptics++;
+   }
+   
+   for (int i = 0; i < al_get_num_joysticks(); i++) { 
+    ALLEGRO_JOYSTICK * joy = al_get_joystick(i);
+    if(al_is_joystick_haptic(joy)) {
+      haptics[num_haptics]    = al_get_haptic_from_joystick(joy);
+      haptic_name[num_haptics]= (char *)al_get_joystick_name(joy);
+      num_haptics++;
+    }
+   }
+
+   /* Don't remove these braces. */
+   {
+      Theme theme(font);
+      Prog prog(theme, display);
+      prog.run();
+   }
+   
+   for (int i = 0; i < num_haptics; i++) { 
+      al_release_haptic(haptics[i]); 
+   }
+
+   al_destroy_font(font);
+
+   return 0;
+}
+
+/* vim: set sts=3 sw=3 et: */
-- 
1.7.10.4


From 76dad2166b9ee41a28329f5312663062a87be74d Mon Sep 17 00:00:00 2001
From: Beoran <beoran@xxxxxxxxx>
Date: Mon, 8 Jul 2013 00:04:30 +0200
Subject: [PATCH 3/8] All sliders are in and positioned as well as is possible
 for such a huge amount. Now to implement the play and
 stop buttons.

---
 examples/ex_haptic2.cpp |  125 +++++++++++++++++++++++++++--------------------
 1 file changed, 71 insertions(+), 54 deletions(-)

diff --git a/examples/ex_haptic2.cpp b/examples/ex_haptic2.cpp
index 1b5598c..1bb19e8 100644
--- a/examples/ex_haptic2.cpp
+++ b/examples/ex_haptic2.cpp
@@ -211,61 +211,78 @@ Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) :
    d.add(waveform_label, 13, 1, 7, 1); 
    d.add(waveform_list , 13, 2, 7, 8);
    
-   d.add(replay_label , 0, 10 , 7, 1);
-   d.add(length_label , 0, 11 , 2, 1);
-   d.add(length_slider, 2, 11 , 5, 1);
-   d.add(delay_label  , 0, 12 , 2, 1);
-   d.add(delay_slider , 2, 12 , 5, 1);
-   d.add(loops_label  , 0, 13 , 7, 1);
-   d.add(loops_slider , 2, 14 , 5, 1);
-   d.add(gain_label   , 0, 15 , 7, 1);
-   d.add(gain_slider  , 2, 16 , 5, 1);
-   
-   d.add(envelope_label         , 7 , 10, 6, 1);
-   d.add(attack_length_label    , 7 , 11, 3, 1);
-   d.add(attack_length_slider   , 10, 11, 3, 1);
-   d.add(attack_level_label     , 7 , 12, 3, 1);
-   d.add(attack_level_slider    , 10, 12, 3, 1);
-   d.add(fade_length_label      , 7 , 13, 3, 1);
-   d.add(fade_length_slider     , 10, 13, 3, 1);
-   d.add(fade_level_label       , 7 , 14, 3, 1);
-   d.add(fade_level_slider      , 10, 14, 3, 1);
-   
-   d.add(coordinates_label      , 13, 10, 7, 1);
-   d.add(angle_label            , 13, 11, 2, 1);
-   d.add(angle_slider           , 15, 11, 5, 1);
-   d.add(radius_label           , 13, 12, 2, 1);
-   d.add(radius_slider          , 15, 12, 5, 1);
-   d.add(azimuth_label          , 13, 13, 2, 1);
-   d.add(azimuth_slider         , 15, 13, 5, 1);
+   d.add(replay_label , 0, 11 , 7, 1);
+   d.add(length_label , 0, 12 , 2, 1);
+   d.add(length_slider, 2, 12 , 5, 1);
+   d.add(delay_label  , 0, 13 , 2, 1);
+   d.add(delay_slider , 2, 13 , 5, 1);
+   
+   d.add(loops_label            ,  7, 11, 7, 1);
+   d.add(loops_slider           ,  7, 12, 6, 1);
+   d.add(gain_label             , 13, 11, 7, 1);
+   d.add(gain_slider            , 13, 12, 7, 1);
+ 
+   
+   d.add(envelope_label         , 0, 15, 9, 1);
+   d.add(attack_length_label    , 0, 16, 3, 1);
+   d.add(attack_length_slider   , 4, 16, 6, 1);
+   d.add(attack_level_label     , 0, 17, 3, 1);
+   d.add(attack_level_slider    , 4, 17, 6, 1);
+   d.add(fade_length_label      , 0, 18, 3, 1);
+   d.add(fade_length_slider     , 4, 18, 6, 1);
+   d.add(fade_level_label       , 0, 19, 3, 1);
+   d.add(fade_level_slider      , 4, 19, 6, 1);
+   
+   d.add(coordinates_label      , 11, 15, 9, 1);
+   d.add(angle_label            , 11, 16, 2, 1);
+   d.add(angle_slider           , 13, 16, 7, 1);
+   d.add(radius_label           , 11, 17, 2, 1);
+   d.add(radius_slider          , 13, 17, 7, 1);
+   d.add(azimuth_label          , 11, 18, 2, 1);
+   d.add(azimuth_slider         , 13, 18, 7, 1);
   
-   d.add(condition_effect_label ,  0, 18, 7, 1); 
-   d.add(right_coeff_label      ,  0, 19, 4, 1);
-   d.add(right_coeff_slider     ,  4, 19, 3, 1);
-   d.add(right_saturation_label ,  0, 20, 4, 1);
-   d.add(right_saturation_slider,  4, 20, 3, 1);  
-   d.add(left_coeff_label       ,  0, 21, 4, 1);
-   d.add(left_coeff_slider      ,  4, 21, 3, 1);
-   d.add(left_saturation_label  ,  0, 22, 4, 1);
-   d.add(left_saturation_slider ,  4, 22, 3, 1);
-   d.add(deadband_label         ,  0, 23, 4, 1);
-   d.add(deadband_slider        ,  4, 23, 3, 1);
-   d.add(center_label           ,  0, 24, 4, 1);
-   d.add(center_slider          ,  4, 24, 3, 1);
-   
-   d.add(constant_effect_label  ,  7, 18, 6, 1);
-   d.add(level_label            ,  7, 19, 3, 1);
-   d.add(level_slider           , 10, 19, 3, 1);
-   
-   d.add(periodic_effect_label  , 13, 18, 7, 1);
-   d.add(period_label           , 13, 19, 7, 1);
-   d.add(period_slider          , 15, 19, 5, 1);
-   d.add(magnitude_label        , 13, 20, 2, 1);
-   d.add(magnitude_slider       , 15, 20, 5, 1);
-   d.add(offset_label           , 13, 21, 2, 1);
-   d.add(offset_slider          , 15, 21, 5, 1);
-   d.add(phase_label            , 13, 22, 2, 1);
-   d.add(phase_slider           , 15, 22, 5, 1);
+   
+   d.add(condition_effect_label ,  0, 21, 9, 1); 
+   d.add(right_coeff_label      ,  0, 22, 4, 1);
+   d.add(right_coeff_slider     ,  4, 22, 6, 1);
+   d.add(right_saturation_label ,  0, 23, 4, 1);
+   d.add(right_saturation_slider,  4, 23, 6, 1);  
+   d.add(left_coeff_label       ,  0, 24, 4, 1);
+   d.add(left_coeff_slider      ,  4, 24, 6, 1);
+   d.add(left_saturation_label  ,  0, 25, 4, 1);
+   d.add(left_saturation_slider ,  4, 25, 6, 1);
+   d.add(deadband_label         ,  0, 26, 4, 1);
+   d.add(deadband_slider        ,  4, 26, 6, 1);
+   d.add(center_label           ,  0, 27, 4, 1);
+   d.add(center_slider          ,  4, 27, 6, 1);
+   
+
+   
+   d.add(periodic_effect_label  , 11, 21, 9, 1);
+   d.add(period_label           , 11, 22, 2, 1);
+   d.add(period_slider          , 13, 22, 7, 1);
+   d.add(magnitude_label        , 11, 23, 2, 1);
+   d.add(magnitude_slider       , 13, 23, 7, 1);
+   d.add(offset_label           , 11, 24, 2, 1);
+   d.add(offset_slider          , 13, 24, 7, 1);
+   d.add(phase_label            , 11, 25, 2, 1);
+   d.add(phase_slider           , 13, 25, 7, 1);
+   
+   d.add(ramp_effect_label      , 11, 29, 9, 1); 
+   d.add(start_level_label      , 11, 30, 2, 1);
+   d.add(start_level_slider     , 13, 30, 7, 1);
+   d.add(end_level_label        , 11, 31, 2, 1);
+   d.add(end_level_slider       , 13, 31, 7, 1);  
+   
+   d.add(rumble_effect_label    ,  0, 29, 9, 1);
+   d.add(strong_magnitude_label ,  0, 30, 4, 1);
+   d.add(strong_magnitude_slider,  4, 30, 6, 1);
+   d.add(weak_magnitude_label   ,  0, 31, 4, 1);
+   d.add(weak_magnitude_slider  ,  4, 31, 6, 1);
+   
+   d.add(constant_effect_label  ,  0, 33, 9, 1);
+   d.add(level_label            ,  0, 34, 3, 1);
+   d.add(level_slider           ,  4, 34, 6, 1);
    
   
    d.add(play_button  , 6, 38, 3, 1); 
-- 
1.7.10.4


From 95f836ecac056f3c1a004dfb7d7a2d73f1c936c0 Mon Sep 17 00:00:00 2001
From: Beoran <beoran@xxxxxxxxx>
Date: Mon, 8 Jul 2013 00:17:17 +0200
Subject: [PATCH 4/8] PlayButton and Stopbutton classes are there, but still
 need to implement playing.

---
 examples/ex_haptic2.cpp |   32 +++++++++++++++++++++++++++-----
 1 file changed, 27 insertions(+), 5 deletions(-)

diff --git a/examples/ex_haptic2.cpp b/examples/ex_haptic2.cpp
index 1bb19e8..d0492bc 100644
--- a/examples/ex_haptic2.cpp
+++ b/examples/ex_haptic2.cpp
@@ -64,6 +64,30 @@ CapacityName capname[] = {
 #define EX_HAPTIC2_END_COORDS   18
 
 
+class PlayButton : public Button {
+public:
+   PlayButton() : Button("Play") {}
+   void on_click(int mx, int my);
+};
+
+
+void PlayButton::on_click(int, int)
+{
+   log_printf("Start playing...\n");
+}
+
+class StopButton : public Button {
+public:
+   StopButton() : Button("Stop") {}
+   void on_click(int mx, int my);
+};
+
+
+void StopButton::on_click(int, int)
+{
+   log_printf("Stop playing...\n");
+}
+
 
 
 class Prog {
@@ -113,8 +137,8 @@ private:
    HSlider gain_slider;
    Label gain_label;
    
-   Button play_button;
-   Button stop_button;
+   PlayButton play_button;
+   StopButton stop_button;
    
    
 public:
@@ -188,9 +212,7 @@ Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) :
    strong_magnitude_label("strong magnitude", false), 
    weak_magnitude_label("weak magnitude", false),
    gain_slider(10, 10),
-   gain_label("gain"),
-   play_button("Play"),
-   stop_button("Stop") 
+   gain_label("gain")
 {
   for (int i = 0; i < num_haptics; i++) {
     device_list.append_item(haptic_name[i]);
-- 
1.7.10.4


From fd32e826bb6155278af88a66aa85645375a6adc1 Mon Sep 17 00:00:00 2001
From: Beoran <beoran@xxxxxxxxx>
Date: Mon, 8 Jul 2013 18:43:04 +0200
Subject: [PATCH 5/8] A first usable version of ex_haptic_2 with disabled
 co,trols. NIHGUI was also updated to allow disabing.

---
 examples/ex_haptic2.cpp |  528 +++++++++++++++++++++++++++++++++++++++--------
 examples/nihgui.cpp     |   76 ++++++-
 examples/nihgui.hpp     |    7 +
 3 files changed, 516 insertions(+), 95 deletions(-)

diff --git a/examples/ex_haptic2.cpp b/examples/ex_haptic2.cpp
index d0492bc..0850637 100644
--- a/examples/ex_haptic2.cpp
+++ b/examples/ex_haptic2.cpp
@@ -18,36 +18,45 @@
 
 #define EX_HAPTIC2_MAX_HAPTICS 8
 
-ALLEGRO_HAPTIC      *    haptics[EX_HAPTIC2_MAX_HAPTICS];
-ALLEGRO_HAPTIC_EFFECT    haptic_effects[EX_HAPTIC2_MAX_HAPTICS];
-ALLEGRO_HAPTIC_EFFECT_ID haptic_ids[EX_HAPTIC2_MAX_HAPTICS];
-char                   * haptic_name[EX_HAPTIC2_MAX_HAPTICS];
-int                      num_haptics;
+struct Haptic {
+  ALLEGRO_HAPTIC         * haptic;
+  ALLEGRO_HAPTIC_EFFECT    effect;
+  ALLEGRO_HAPTIC_EFFECT_ID id;
+  const char             * name;
+  bool                     playing;
+};
+
+
+
+Haptic                   haptics[EX_HAPTIC2_MAX_HAPTICS];
+int                      num_haptics =  0;
+/* Haptic                 * last_haptic = NULL; */
 
 struct CapacityName { 
   int   value;
   const char * name; 
 };
 
+
 CapacityName capname[] = {
-  { ALLEGRO_HAPTIC_RUMBLE   , "rumble"   },  
-  { ALLEGRO_HAPTIC_PERIODIC , "periodic" },
-  { ALLEGRO_HAPTIC_CONSTANT , "constant" }, 
-  { ALLEGRO_HAPTIC_SPRING   , "spring"   },
-  { ALLEGRO_HAPTIC_FRICTION , "friction" },
-  { ALLEGRO_HAPTIC_DAMPER   , "damper"   },
-  { ALLEGRO_HAPTIC_INERTIA  , "inertia"  },
-  { ALLEGRO_HAPTIC_RAMP     , "ramp"     }, 
-  { ALLEGRO_HAPTIC_SQUARE   , "square"   },
-  { ALLEGRO_HAPTIC_TRIANGLE , "triangle" },
-  { ALLEGRO_HAPTIC_SINE     , "sine"     },
-  { ALLEGRO_HAPTIC_SAW_UP   , "saw up"   },
-  { ALLEGRO_HAPTIC_SAW_DOWN , "saw down" },
-  { ALLEGRO_HAPTIC_CUSTOM   , "custom"   },
-  { ALLEGRO_HAPTIC_GAIN     , "gain"     },
-  { ALLEGRO_HAPTIC_ANGLE    , "angle"    },
-  { ALLEGRO_HAPTIC_RADIUS   , "radius"   },
-  { ALLEGRO_HAPTIC_AZIMUTH  , "azimuth"  }
+  { ALLEGRO_HAPTIC_RUMBLE   , "ALLEGRO_HAPTIC_RUMBLE"   },  
+  { ALLEGRO_HAPTIC_PERIODIC , "ALLEGRO_HAPTIC_PERIODIC" },
+  { ALLEGRO_HAPTIC_CONSTANT , "ALLEGRO_HAPTIC_CONSTANT" }, 
+  { ALLEGRO_HAPTIC_SPRING   , "ALLEGRO_HAPTIC_SPRING"   },
+  { ALLEGRO_HAPTIC_FRICTION , "ALLEGRO_HAPTIC_FRICTION" },
+  { ALLEGRO_HAPTIC_DAMPER   , "ALLEGRO_HAPTIC_DAMPER"   },
+  { ALLEGRO_HAPTIC_INERTIA  , "ALLEGRO_HAPTIC_INERTIA"  },
+  { ALLEGRO_HAPTIC_RAMP     , "ALLEGRO_HAPTIC_RAMP"     }, 
+  { ALLEGRO_HAPTIC_SQUARE   , "ALLEGRO_HAPTIC_SQUARE"   },
+  { ALLEGRO_HAPTIC_TRIANGLE , "ALLEGRO_HAPTIC_TRIANGLE" },
+  { ALLEGRO_HAPTIC_SINE     , "ALLEGRO_HAPTIC_SINE"     },
+  { ALLEGRO_HAPTIC_SAW_UP   , "ALLEGRO_HAPTIC_SAW_UP"   },
+  { ALLEGRO_HAPTIC_SAW_DOWN , "ALLEGRO_HAPTIC_SAW_DOWN" },
+  { ALLEGRO_HAPTIC_CUSTOM   , "ALLEGRO_HAPTIC_CUSTOM"   },
+  { ALLEGRO_HAPTIC_GAIN     , "ALLEGRO_HAPTIC_GAIN"     },
+  { ALLEGRO_HAPTIC_ANGLE    , "ALLEGRO_HAPTIC_ANGLE"    },
+  { ALLEGRO_HAPTIC_RADIUS   , "ALLEGRO_HAPTIC_RADIUS"   },
+  { ALLEGRO_HAPTIC_AZIMUTH  , "ALLEGRO_HAPTIC_AZIMUTH"  }
 };
 
 #define EX_HAPTIC2_START_TYPES   0
@@ -64,34 +73,53 @@ CapacityName capname[] = {
 #define EX_HAPTIC2_END_COORDS   18
 
 
+class CanStopAndPlay {
+   public: 
+   virtual void on_play() = 0;
+   virtual void on_stop() = 0;
+};
+
+
 class PlayButton : public Button {
+protected:
+   CanStopAndPlay * stop_and_play;  
 public:
-   PlayButton() : Button("Play") {}
+   PlayButton(CanStopAndPlay * snp) : Button("Play") , stop_and_play(snp) {}
    void on_click(int mx, int my);
 };
 
 
 void PlayButton::on_click(int, int)
 {
+   if (is_disabled()) return; 
    log_printf("Start playing...\n");
+   if(stop_and_play) {
+      stop_and_play->on_play();
+   }
 }
 
 class StopButton : public Button {
+protected:
+   CanStopAndPlay * stop_and_play;  
 public:
-   StopButton() : Button("Stop") {}
+   StopButton(CanStopAndPlay * snp) : Button("Stop") , stop_and_play(snp) {}
    void on_click(int mx, int my);
 };
 
 
 void StopButton::on_click(int, int)
 {
+   if (is_disabled()) return; 
    log_printf("Stop playing...\n");
+   if(stop_and_play) {
+      stop_and_play->on_stop();
+   }
 }
 
 
 
-class Prog {
-private:
+class Prog : public CanStopAndPlay {
+   private:
    Dialog d;  
    
    List  device_list;
@@ -137,19 +165,22 @@ private:
    HSlider gain_slider;
    Label gain_label;
    
+   Label message_label, message_label_label;
+   
    PlayButton play_button;
    StopButton stop_button;
    
+   Haptic                 * last_haptic;
+   Haptic                 * show_haptic;
+   
    
 public:
    Prog(const Theme & theme, ALLEGRO_DISPLAY *display);
    void run();
-
-private:
-   /*
-    * void play_effect();
-   void stop_effect();};
-   */
+   void update();
+   virtual void on_play();
+   virtual void on_stop();
+   void get_envelope(ALLEGRO_HAPTIC_ENVELOPE * envelope);
 };
 
 
@@ -164,58 +195,64 @@ Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) :
    length_slider(1, 10),
    delay_slider(1, 10),
    loops_slider(1, 10), 
-   replay_label("replay"),
-   length_label("length", false),
-   delay_label("delay", false),
-   loops_label("loops"),   
-   attack_length_slider(1, 10),
-   attack_level_slider(5, 10),
-   fade_length_slider(5, 10),
-   fade_level_slider(1, 10),
-   envelope_label("envelope"),
-   attack_length_label("attack length", false),
-   attack_level_label("attack level", false),
-   fade_length_label("fade length", false),
-   fade_level_label("fade level", false),
+   replay_label("Replay"),
+   length_label("Length", false),
+   delay_label("Delay", false),
+   loops_label("Loops"),   
+   attack_length_slider(2, 10),
+   attack_level_slider(4, 10),
+   fade_length_slider(2, 10),
+   fade_level_slider(4, 10),
+   envelope_label("Envelope"),
+   attack_length_label("Attack Length", false),
+   attack_level_label("Attack Level", false),
+   fade_length_label("Fade Length", false),
+   fade_level_label("Fade Level", false),
    angle_slider(0, 360), radius_slider(0, 10), azimuth_slider(180, 360),
-   coordinates_label("coordinates"),
-   angle_label("angle", false), 
-   radius_label("radius", false), 
-   azimuth_label("azimuth", false),
+   coordinates_label("Coordinates"),
+   angle_label("Angle", false), 
+   radius_label("Radius", false), 
+   azimuth_label("Azimuth", false),
    level_slider(5, 10), 
-   constant_effect_label("constant effect"),
-   level_label("level", false),
+   constant_effect_label("Constant Effect"),
+   level_label("Level", false),
    start_level_slider(3, 10), end_level_slider(7, 10), 
-   ramp_effect_label("ramp effect"),
-   start_level_label("start level", false),
-   end_level_label("end level", false),
+   ramp_effect_label("Ramp Effect"),
+   start_level_label("Start Lvl.", false),
+   end_level_label("End Lvl.", false),
    right_saturation_slider(5, 10) , right_coeff_slider(5, 10),
    left_saturation_slider(5, 10)  , left_coeff_slider(5, 10),
    deadband_slider(1, 10)         , center_slider(5,10),
-   right_saturation_label("right saturation", false), 
-   right_coeff_label("right coefficient", false),
-   left_saturation_label("left saturation", false), 
-   left_coeff_label("left coefficient", false),
-   condition_effect_label("condition effect"),
-   deadband_label("deadband", false), 
-   center_label("center", false),
+   right_saturation_label("Right Saturation", false), 
+   right_coeff_label("Right Coefficient", false),
+   left_saturation_label("Left Saturation", false), 
+   left_coeff_label("Left Coefficient", false),
+   condition_effect_label("Condition Effect"),
+   deadband_label("Deadband", false), 
+   center_label("Center", false),
    period_slider(1, 10), magnitude_slider(5, 10), 
    offset_slider(0, 10), phase_slider(0, 10),
-   periodic_effect_label("periodic effect"), 
-   period_label("period", false), 
-   magnitude_label("magnitude", false), 
-   offset_label("offset", false), 
-   phase_label("phase", false),
+   periodic_effect_label("Periodic Effect"), 
+   period_label("Period", false), 
+   magnitude_label("Magnitude", false), 
+   offset_label("Offset", false), 
+   phase_label("Phase", false),
    strong_magnitude_slider(5, 10), 
    weak_magnitude_slider(5, 10),
-   rumble_effect_label("rumble effect"),
-   strong_magnitude_label("strong magnitude", false), 
-   weak_magnitude_label("weak magnitude", false),
+   rumble_effect_label("Rumble effect"),
+   strong_magnitude_label("Strong Magnitude", false), 
+   weak_magnitude_label("Weak Magnitude", false),
    gain_slider(10, 10),
-   gain_label("gain")
+   gain_label("Gain"),
+   message_label("Ready.", false),
+   message_label_label("Status", false),
+   play_button(this),
+   stop_button(this),
+   last_haptic(NULL),
+   show_haptic(NULL)
 {
   for (int i = 0; i < num_haptics; i++) {
-    device_list.append_item(haptic_name[i]);
+    device_list.append_item(haptics[i].name);
   } 
   d.add(device_label, 0, 1, 7, 1); 
   d.add(device_list , 0, 2, 7, 8);
@@ -306,9 +343,12 @@ Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) :
    d.add(level_label            ,  0, 34, 3, 1);
    d.add(level_slider           ,  4, 34, 6, 1);
    
+   d.add(message_label_label    ,  0, 36,  2, 1);
+   d.add(message_label          ,  2, 36, 12, 1);
+   
   
-   d.add(play_button  , 6, 38, 3, 1); 
-   d.add(stop_button  , 12, 38, 3, 1); 
+   d.add(play_button  , 6, 38,  3, 2); 
+   d.add(stop_button  , 12, 38, 3, 2); 
 
    
    /*
@@ -330,22 +370,337 @@ Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) :
    */
 }
 
+#define TEST_CAP(CAP, FLAG) (((CAP) & (FLAG)) == (FLAG))
+
+void Prog::update() {
+  /* Update playing state and display. */  
+  if(last_haptic && last_haptic->playing) {
+    if(!al_is_haptic_effect_playing(&last_haptic->id)) {
+      last_haptic->playing = false;
+      al_release_haptic_effect(&last_haptic->id);
+      message_label.set_text("Done.");
+      play_button.set_disabled(false);
+      d.request_draw();
+      log_printf("Play done on %s\n", last_haptic->name);
+    }
+  }
+  /* Update availability of controls based on capabilities. */
+  int devno = device_list.get_cur_value();
+  Haptic * dev = haptics + devno;
+  if (dev && dev->haptic) {
+    if ( dev != show_haptic) {
+      /* Take a deep breath , here we go...*/
+      bool condition, envelope, periodic;
+      show_haptic = dev;
+      int cap = al_get_haptic_capabilities(show_haptic->haptic);
+      
+      /* Gain capability */
+      gain_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_GAIN));
+      gain_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_GAIN));
+      
+      
+      /* Envelope related capabilities and sliders. */
+      envelope = TEST_CAP(cap, ALLEGRO_HAPTIC_PERIODIC) ||
+                 TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT) ||
+                 TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP);
+      
+      envelope_label.set_disabled(!envelope); 
+      attack_level_slider.set_disabled(!envelope);
+      attack_length_slider.set_disabled(!envelope);
+      fade_level_slider.set_disabled(!envelope);
+      fade_length_slider.set_disabled(!envelope);
+      attack_level_label.set_disabled(!envelope);
+      attack_length_label.set_disabled(!envelope);
+      fade_level_label.set_disabled(!envelope);
+      fade_length_label.set_disabled(!envelope);
+      
+      /* Coordinate related capabilities. */ 
+      angle_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_ANGLE));
+      angle_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_ANGLE));
+      radius_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RADIUS));
+      radius_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RADIUS));      
+      azimuth_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_AZIMUTH));      
+      azimuth_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_AZIMUTH)); 
+      
+      /* Condition effect related capabilities. */
+      condition  = TEST_CAP(cap, ALLEGRO_HAPTIC_DAMPER) ||
+                 TEST_CAP(cap, ALLEGRO_HAPTIC_FRICTION) ||
+                 TEST_CAP(cap, ALLEGRO_HAPTIC_INERTIA)  ||
+                 TEST_CAP(cap, ALLEGRO_HAPTIC_SPRING);
+      
+      condition_effect_label.set_disabled(!condition);
+      right_coeff_slider.set_disabled(!condition);
+      left_coeff_slider.set_disabled(!condition);
+      right_saturation_slider.set_disabled(!condition);
+      left_saturation_slider.set_disabled(!condition);
+      center_slider.set_disabled(!condition);
+      deadband_slider.set_disabled(!condition);
+      right_coeff_label.set_disabled(!condition);
+      left_coeff_label.set_disabled(!condition);
+      right_saturation_label.set_disabled(!condition);
+      left_saturation_label.set_disabled(!condition);
+      center_label.set_disabled(!condition);
+      deadband_label.set_disabled(!condition);
+      
+      /* Constant effect related capabilities. */
+      constant_effect_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT)); 
+      level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT));
+      level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT)); 
+      
+      /* Ramp effect capabilities. */
+      ramp_effect_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP)); 
+      start_level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP));
+      start_level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP)); 
+      end_level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP));
+      end_level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP)); 
+      
+      /* Period effect capabilities. */
+      periodic = TEST_CAP(cap, ALLEGRO_HAPTIC_PERIODIC);
+      waveform_label.set_disabled(!periodic);
+      waveform_list.set_disabled(!periodic);
+      periodic_effect_label.set_disabled(!periodic);
+      period_slider.set_disabled(!periodic);
+      magnitude_slider.set_disabled(!periodic);
+      offset_slider.set_disabled(!periodic);
+      phase_slider.set_disabled(!periodic);
+      period_label.set_disabled(!periodic);
+      magnitude_label.set_disabled(!periodic);
+      offset_label.set_disabled(!periodic);
+      phase_label.set_disabled(!periodic);
+      
+      /*Change list of supported effect types*/
+      type_list.clear_items();
+      for (int i = EX_HAPTIC2_START_TYPES; i < EX_HAPTIC2_END_TYPES; i ++) {
+        CapacityName * cn = capname + i;
+        if (TEST_CAP(cap, cn->value)) { 
+          type_list.append_item(cn->name);
+        }
+      }
+      
+      /* Change list of supported wave form types. */
+      waveform_list.clear_items();
+      for (int i = EX_HAPTIC2_START_WAVES; i < EX_HAPTIC2_END_WAVES; i ++) {
+        CapacityName * cn = capname + i;
+        if (TEST_CAP(cap, cn->value)) { 
+          waveform_list.append_item(cn->name);
+        }
+      }
+      
+    }
+  } else {
+    play_button.set_disabled(true);
+    message_label.set_text("No Haptic Device.");
+  }
+  
+}
+
+
 void Prog::run()
 {
    d.prepare();
 
    while (!d.is_quit_requested()) {
-      if (d.is_draw_requested()) {
-         al_clear_to_color(al_map_rgb(128, 128, 128));
+      update(); 
+      if (d.is_draw_requested()) {        
+         al_clear_to_color(al_map_rgb(128, 148, 168));
          d.draw();
          al_flip_display();
       }
 
       d.run_step(true);
    }
+   on_stop(); /* Stop playing anything we were still playing. */
+}
+
+int cap_for_name(const std::string& name) {
+  for (int i = 0; i < EX_HAPTIC2_END_WAVES; i++) {
+    if (name == capname[i].name) {
+      return capname[i].value;
+    } 
+  }
+  return -1;
+}
+
+const char * cap_to_name(int cap) {
+  for (int i = 0; i < EX_HAPTIC2_END_WAVES; i++) {
+    if (cap == capname[i].value) {
+      return capname[i].name;
+    } 
+  }
+  return "unknown";
 }
 
 
+double slider_to_magnitude(const HSlider & slider) {
+  double value = (double) slider.get_cur_value();
+  double max   = (double) slider.get_max_value();
+  return value / max;
+}
+
+double slider_to_duration(const HSlider & slider) {
+  double value = (double) slider.get_cur_value();
+  double max   = 1.0;
+  return value / max;
+}
+
+double slider_to_angle(const HSlider & slider) {
+  double value = (double) slider.get_cur_value();
+  double max   = (double) slider.get_max_value();
+  return value / max;
+}
+
+void Prog::get_envelope(ALLEGRO_HAPTIC_ENVELOPE * envelope) {
+  if(!envelope) return;
+  envelope->attack_length = slider_to_duration(attack_length_slider);
+  envelope->fade_length   = slider_to_duration(fade_length_slider);
+  envelope->attack_level  = slider_to_magnitude(attack_level_slider);
+  envelope->fade_level    = slider_to_magnitude(fade_level_slider);
+} 
+
+void Prog::on_play() {
+  int devno  = device_list.get_cur_value();
+  if ((devno < 0) || (devno >= num_haptics)) {
+    message_label.set_text("No Haptic Device!");
+    log_printf("No such device: %d\n", devno); 
+    return;
+  }  
+  Haptic * haptic     = haptics + devno;  
+  
+  if (!haptic || !haptic->haptic) {
+    log_printf("Device is NULL: %d\n", devno);
+    message_label.set_text("Device Is NULL!");
+    return;
+  }  
+  
+  if (!al_get_haptic_active(haptic->haptic)) {
+    message_label.set_text("Device Not Active!");
+    log_printf("Device is not active: %d\n", devno); 
+    return;
+  }
+  
+  /* Stop playing previous effect. */
+  if (haptic->playing) { 
+    al_stop_haptic_effect(&haptic->id);
+    haptic->playing = false;
+    al_release_haptic_effect(&haptic->id);
+  }
+  
+  /* First set gain. */
+  double gain         = slider_to_magnitude(gain_slider);
+  al_set_haptic_gain(haptic->haptic, gain);
+  
+  /* Now fill in the effect struct. */
+  int type            = cap_for_name(type_list.get_selected_item_text());
+  int wavetype        = cap_for_name (waveform_list.get_selected_item_text());
+  
+  if (type < 0)  {
+    message_label.set_text("Unknown Effect Type!");
+    log_printf("Unknown effect type: %d on %s\n", type, haptic->name); 
+    return;
+  }
+  
+  if (wavetype < 0)  {
+    message_label.set_text("Unknown Wave Form!");
+    log_printf("Unknown wave type: %d on %s\n", wavetype, haptic->name); 
+    return;
+  }
+  
+  haptic->effect.type               = type;
+  haptic->effect.replay.delay       = slider_to_duration(delay_slider);
+  haptic->effect.replay.length      = slider_to_duration(length_slider);
+  int loops                         = loops_slider.get_cur_value();
+  haptic->effect.direction.angle    = slider_to_angle(angle_slider);
+  haptic->effect.direction.radius   = slider_to_magnitude(angle_slider);
+  haptic->effect.direction.azimuth  = slider_to_angle(angle_slider);  
+  
+  switch (type) {
+  case ALLEGRO_HAPTIC_RUMBLE:
+     haptic->effect.data.rumble.strong_magnitude = 
+        slider_to_magnitude(strong_magnitude_slider);
+     haptic->effect.data.rumble.weak_magnitude = 
+        slider_to_magnitude(weak_magnitude_slider);    
+  break;
+  case ALLEGRO_HAPTIC_PERIODIC:
+    get_envelope(&haptic->effect.data.periodic.envelope);
+    haptic->effect.data.periodic.waveform   = wavetype;
+    haptic->effect.data.periodic.magnitude  = slider_to_magnitude(magnitude_slider);
+    haptic->effect.data.periodic.period     = slider_to_duration(period_slider);
+    haptic->effect.data.periodic.offset     = slider_to_duration(offset_slider);
+    haptic->effect.data.periodic.phase      = slider_to_duration(phase_slider);
+    haptic->effect.data.periodic.custom_len = 0;
+    haptic->effect.data.periodic.custom_data= NULL;
+  break;
+  case ALLEGRO_HAPTIC_CONSTANT:
+    get_envelope(&haptic->effect.data.constant.envelope);
+    haptic->effect.data.constant.level    = slider_to_magnitude(level_slider);
+  break;
+  case ALLEGRO_HAPTIC_RAMP:
+    get_envelope(&haptic->effect.data.ramp.envelope);
+    haptic->effect.data.ramp.start_level  = slider_to_magnitude(start_level_slider);
+    haptic->effect.data.ramp.end_level    = slider_to_magnitude(end_level_slider);
+  break; 
+  
+  case ALLEGRO_HAPTIC_SPRING:
+  case ALLEGRO_HAPTIC_FRICTION:
+  case ALLEGRO_HAPTIC_DAMPER:
+  case ALLEGRO_HAPTIC_INERTIA: /* fall through. */
+     haptic->effect.data.condition.right_saturation = 
+        slider_to_magnitude(right_saturation_slider);
+     haptic->effect.data.condition.left_saturation = 
+        slider_to_magnitude(left_saturation_slider);   
+     haptic->effect.data.condition.right_coeff = 
+        slider_to_magnitude(right_coeff_slider);   
+     haptic->effect.data.condition.left_coeff = 
+        slider_to_magnitude(left_coeff_slider);
+     haptic->effect.data.condition.deadband = 
+        slider_to_magnitude(deadband_slider);
+     haptic->effect.data.condition.center = 
+        slider_to_magnitude(center_slider);
+        /* XXX, need a different conversion function here, but  I don't have a 
+         * controller that supports condition effects anyway... :p
+         */
+     break;
+  default:
+    message_label.set_text("Unknown Effect Type!");
+    log_printf("Unknown effect type %d %d\n", devno, type); 
+    return;
+  }
+  if(!al_is_haptic_effect_ok(haptic->haptic, &haptic->effect)) {
+    message_label.set_text("Effect Not Supported!");
+    log_printf("Playing of effect type %s on %s not supported\n", cap_to_name(type), haptic->name); 
+    return;
+  }
+  
+  haptic->playing = al_upload_and_play_haptic_effect(haptic->haptic, &haptic->effect, 
+                                                     loops, &haptic->id);
+  if(haptic->playing) { 
+    message_label.set_text("Playing...");
+    log_printf("Started playing effect type %s on %s\n", cap_to_name(type), haptic->name); 
+    last_haptic = haptic;
+  } else {
+    message_label.set_text("Playing of effect failed!");
+    log_printf("Playing of effect type %s on %s failed\n", cap_to_name(type), haptic->name); 
+  }
+  play_button.set_disabled(true);
+  
+}
+
+void Prog::on_stop() {
+  int devno = device_list.get_cur_value();
+  if ((devno < 0) || (devno >= num_haptics)) {
+    log_printf("No such device %d\n", devno); 
+    return;
+  }  
+  Haptic * haptic = haptics + devno;
+  if (haptic->playing && al_is_haptic_effect_playing(&haptic->id)) { 
+    al_stop_haptic_effect(&haptic->id);
+    haptic->playing = false;
+    al_release_haptic_effect(&haptic->id);
+    log_printf("Stopped device %d: %s\n", devno, haptic->name);
+  }
+  message_label.set_text("Stopped.");
+  play_button.set_disabled(false);
+}
 
 
 int main(int argc, char *argv[])
@@ -373,7 +728,6 @@ int main(int argc, char *argv[])
       abort_example("Unable to create display\n");
    }
    
-    
    font = al_create_builtin_font();
    if (!font) {
       abort_example("Failed to create builtin font.\n");
@@ -389,17 +743,23 @@ int main(int argc, char *argv[])
    num_haptics = 0;
    
    if(al_is_display_haptic(al_get_current_display())) {
-     haptics[num_haptics]    = al_get_haptic_from_display(al_get_current_display());
-     haptic_name[num_haptics]= (char *)"display";
-     num_haptics++;
+     haptics[num_haptics].haptic  = al_get_haptic_from_display(al_get_current_display());
+     if(haptics[num_haptics].haptic) { 
+        haptics[num_haptics].name    = (const char *)"display";
+        haptics[num_haptics].playing = false;
+        num_haptics++;
+     }
    }
    
    for (int i = 0; i < al_get_num_joysticks(); i++) { 
     ALLEGRO_JOYSTICK * joy = al_get_joystick(i);
     if(al_is_joystick_haptic(joy)) {
-      haptics[num_haptics]    = al_get_haptic_from_joystick(joy);
-      haptic_name[num_haptics]= (char *)al_get_joystick_name(joy);
-      num_haptics++;
+      haptics[num_haptics].haptic  = al_get_haptic_from_joystick(joy);
+      if(haptics[num_haptics].haptic) { 
+         haptics[num_haptics].name    = (const char *)al_get_joystick_name(joy);
+         haptics[num_haptics].playing = false;
+         num_haptics++;
+      }
     }
    }
 
@@ -411,7 +771,7 @@ int main(int argc, char *argv[])
    }
    
    for (int i = 0; i < num_haptics; i++) { 
-      al_release_haptic(haptics[i]); 
+      al_release_haptic(haptics[i].haptic); 
    }
 
    al_destroy_font(font);
diff --git a/examples/nihgui.cpp b/examples/nihgui.cpp
index 2d5c8c4..d81fe0c 100644
--- a/examples/nihgui.cpp
+++ b/examples/nihgui.cpp
@@ -7,6 +7,7 @@
 #include <iostream>
 #include <string>
 #include <algorithm>
+#include <allegro5/color.h>
 #include "allegro5/allegro.h"
 #include "allegro5/allegro_font.h"
 #include <allegro5/allegro_primitives.h>
@@ -75,7 +76,8 @@ Widget::Widget():
    x1(0),
    y1(0),
    x2(0),
-   y2(0)
+   y2(0),
+   disabled(false)
 {
 }
 
@@ -371,14 +373,16 @@ void Label::draw()
 {
    const Theme & theme = this->dialog->get_theme();
    SaveState state;
+   ALLEGRO_COLOR fg = theme.fg;
+   if(is_disabled()) { fg = al_map_rgb(64, 64, 64); } 
 
    al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
    if (centred) {
-      al_draw_text(theme.font, theme.fg, (this->x1 + this->x2 + 1)/2,
+      al_draw_text(theme.font, fg, (this->x1 + this->x2 + 1)/2,
          this->y1, ALLEGRO_ALIGN_CENTRE, this->text.c_str());
    }
    else {
-      al_draw_text(theme.font, theme.fg, this->x1, this->y1, 0, this->text.c_str());
+      al_draw_text(theme.font, fg, this->x1, this->y1, 0, this->text.c_str());
    }
 }
 
@@ -402,6 +406,7 @@ Button::Button(std::string text):
 
 void Button::on_mouse_button_down(int mx, int my)
 {
+   if (is_disabled()) return;
    (void)mx;
    (void)my;
    this->pushed = true;
@@ -410,6 +415,7 @@ void Button::on_mouse_button_down(int mx, int my)
 
 void Button::on_mouse_button_up(int mx, int my)
 {
+   if (is_disabled()) return;
    (void)mx;
    (void)my;
    this->pushed = false;
@@ -422,6 +428,7 @@ void Button::draw()
    ALLEGRO_COLOR fg;
    ALLEGRO_COLOR bg;
    SaveState state;
+   double y;
 
    if (this->pushed) {
       fg = theme.bg;
@@ -431,14 +438,21 @@ void Button::draw()
       fg = theme.fg;
       bg = theme.bg;
    }
+   
+   if(is_disabled()) { bg = al_map_rgb(64, 64, 64); } 
+
 
    al_draw_filled_rectangle(this->x1, this->y1,
       this->x2, this->y2, bg);
    al_draw_rectangle(this->x1 + 0.5, this->y1 + 0.5,
       this->x2 - 0.5, this->y2 - 0.5, fg, 0);
    al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
+   /* Center the text vertically in the button, taking the font size 
+      into consideration. */
+   y = (this->y1 + this->y2 - al_get_font_line_height(theme.font) - 1) / 2;
+   
    al_draw_text(theme.font, fg, (this->x1 + this->x2 + 1)/2,
-      this->y1, ALLEGRO_ALIGN_CENTRE, this->text.c_str());
+      y, ALLEGRO_ALIGN_CENTRE, this->text.c_str());
 }
 
 bool Button::get_pushed()
@@ -455,6 +469,8 @@ ToggleButton::ToggleButton(std::string text) :
 
 void ToggleButton::on_mouse_button_down(int mx, int my)
 {
+   if (is_disabled()) return; 
+   
    (void)mx;
    (void)my;
    set_pushed(!this->pushed);
@@ -462,6 +478,8 @@ void ToggleButton::on_mouse_button_down(int mx, int my)
 
 void ToggleButton::on_mouse_button_up(int mx, int my)
 {
+   if (is_disabled()) return; 
+   
    (void)mx;
    (void)my;
 }
@@ -486,12 +504,14 @@ List::List(int initial_selection) :
 
 bool List::want_key_focus()
 {
-   return true;
+   return   !is_disabled();
 }
 
 void List::on_key_down(const ALLEGRO_KEYBOARD_EVENT & event)
 {
-   switch (event.keycode) {
+  if (is_disabled()) return;
+  
+  switch (event.keycode) {
       case ALLEGRO_KEY_DOWN:
          if (selected_item < items.size() - 1) {
             selected_item++;
@@ -510,6 +530,8 @@ void List::on_key_down(const ALLEGRO_KEYBOARD_EVENT & event)
 
 void List::on_click(int mx, int my)
 {
+   if (is_disabled()) return;
+  
    const Theme & theme = dialog->get_theme();
    unsigned int i = (my - this->y1) / al_get_font_line_height(theme.font);
    if (i < this->items.size()) {
@@ -525,8 +547,10 @@ void List::draw()
 {
    const Theme & theme = dialog->get_theme();
    SaveState state;
+   ALLEGRO_COLOR bg = theme.bg;
+   if(is_disabled()) { bg = al_map_rgb(64, 64, 64); } 
 
-   al_draw_filled_rectangle(x1 + 1, y1 + 1, x2 - 1, y2 - 1, theme.bg);
+   al_draw_filled_rectangle(x1 + 1, y1 + 1, x2 - 1, y2 - 1, bg);
 
    al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
    const int font_height = al_get_font_line_height(theme.font);
@@ -576,11 +600,15 @@ VSlider::VSlider(int cur_value, int max_value) :
 
 void VSlider::on_mouse_button_down(int mx, int my)
 {
+   if (is_disabled()) return;  
+
    this->on_mouse_button_hold(mx, my);
 }
 
 void VSlider::on_mouse_button_hold(int mx, int my)
 {
+   if (is_disabled()) return;
+   
    double r = (double) (this->y2 - 1 - my) / (this->height() - 2);
    r = CLAMP(0.0, r, 1.0);
    cur_value = (int) (r * max_value);
@@ -592,11 +620,14 @@ void VSlider::on_mouse_button_hold(int mx, int my)
 void VSlider::draw()
 {
    const Theme & theme = dialog->get_theme();
+   ALLEGRO_COLOR bg = theme.fg;
+   if(is_disabled()) { bg = al_map_rgb(64, 64, 64); } 
+
    float left = x1 + 0.5, top = y1 + 0.5;
    float right = x2 + 0.5, bottom = y2 + 0.5;
    SaveState state;
 
-   al_draw_rectangle(left, top, right, bottom, theme.fg, 1);
+   al_draw_rectangle(left, top, right, bottom, bg, 1);
 
    double ratio = (double) this->cur_value / (double) this->max_value;
    int ypos = (int) (bottom - 0.5 - (int) (ratio * (height() - 7)));
@@ -608,6 +639,11 @@ int VSlider::get_cur_value() const
    return this->cur_value;
 }
 
+int VSlider::get_max_value() const
+{
+   return this->max_value;
+}
+
 void VSlider::set_cur_value(int v)
 {
    this->cur_value = v;
@@ -623,11 +659,15 @@ HSlider::HSlider(int cur_value, int max_value) :
 
 void HSlider::on_mouse_button_down(int mx, int my)
 {
+   if (is_disabled()) return;
+   
    this->on_mouse_button_hold(mx, my);
 }
 
 void HSlider::on_mouse_button_hold(int mx, int my)
 {
+   if (is_disabled()) return;
+   
    double r = (double) (mx - 1 - this->x1) / (this->width() - 2);
    r = CLAMP(0.0, r, 1.0);
    cur_value = (int) (r * max_value);
@@ -641,8 +681,11 @@ void HSlider::draw()
    const Theme & theme = dialog->get_theme();
    const int cy = (y1 + y2) / 2;
    SaveState state;
+   ALLEGRO_COLOR bg = theme.bg;
+   if(is_disabled()) { bg = al_map_rgb(64, 64, 64); } 
 
-   al_draw_filled_rectangle(x1, y1, x2, y2, theme.bg);
+
+   al_draw_filled_rectangle(x1, y1, x2, y2, bg);
    al_draw_line(x1, cy, x2, cy, theme.fg, 0);
 
    double ratio = (double) this->cur_value / (double) this->max_value;
@@ -655,6 +698,11 @@ int HSlider::get_cur_value() const
    return this->cur_value;
 }
 
+int HSlider::get_max_value() const
+{
+   return this->max_value;
+}
+
 void HSlider::set_cur_value(int v)
 {
    this->cur_value = v;
@@ -677,7 +725,7 @@ TextEntry::~TextEntry()
 
 bool TextEntry::want_key_focus()
 {
-   return true;
+  return !is_disabled();
 }
 
 void TextEntry::got_key_focus()
@@ -694,6 +742,8 @@ void TextEntry::lost_key_focus()
 
 void TextEntry::on_key_down(const ALLEGRO_KEYBOARD_EVENT & event)
 {
+   if (is_disabled()) return;
+   
    switch (event.keycode) {
       case ALLEGRO_KEY_LEFT:
          al_ustr_prev(text, &cursor_pos);
@@ -758,8 +808,12 @@ void TextEntry::draw()
 {
    const Theme & theme = dialog->get_theme();
    SaveState state;
+   
+   ALLEGRO_COLOR bg = theme.bg;
+   if(is_disabled()) { bg = al_map_rgb(64, 64, 64); } 
+
 
-   al_draw_filled_rectangle(x1, y1, x2, y2, theme.bg);
+   al_draw_filled_rectangle(x1, y1, x2, y2, bg);
 
    al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
 
diff --git a/examples/nihgui.hpp b/examples/nihgui.hpp
index 5bf8b08..216c9d6 100644
--- a/examples/nihgui.hpp
+++ b/examples/nihgui.hpp
@@ -36,6 +36,8 @@ protected:
    int      y1;
    int      x2;
    int      y2;
+   
+   bool     disabled;
 
 public:
    Widget();
@@ -62,6 +64,8 @@ public:
                      (void)event; }
 
    virtual void   draw() = 0;
+   virtual void   set_disabled(bool value) { disabled = value;  }
+   virtual bool   is_disabled()            { return disabled;   }
 
    friend class Dialog;
 };
@@ -84,6 +88,7 @@ private:
 
    bool                 draw_requested;
    bool                 quit_requested;
+
    std::list<Widget *>  all_widgets;
    Widget *             mouse_over_widget;
    Widget *             mouse_down_widget;
@@ -189,6 +194,7 @@ public:
    virtual void   on_mouse_button_hold(int mx, int my);
    virtual void   draw();
 
+   int            get_max_value() const;
    int            get_cur_value() const;
    void           set_cur_value(int v);
 };
@@ -205,6 +211,7 @@ public:
    virtual void   on_mouse_button_hold(int mx, int my);
    virtual void   draw();
 
+   int            get_max_value() const;
    int            get_cur_value() const;
    void           set_cur_value(int v);
 };
-- 
1.7.10.4


From 0101a91dc12bd4467a4f1636a1653ef227928ef3 Mon Sep 17 00:00:00 2001
From: Beoran <beoran@xxxxxxxxx>
Date: Mon, 8 Jul 2013 19:07:18 +0200
Subject: [PATCH 6/8] Show the log, use a ttf font for better legibility, and
 some small fixes.

---
 examples/CMakeLists.txt |    2 +-
 examples/ex_haptic2.cpp |   29 ++++++++++++++++++-----------
 2 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index bf6b31d..cab0c70 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -136,7 +136,7 @@ example(ex_fs_window ${IMAGE} ${PRIM} ${FONT})
 example(ex_icon ${IMAGE})
 example(ex_icon2 ${IMAGE})
 example(ex_haptic ${PRIM})
-example(ex_haptic2  ex_haptic2.cpp ${NIHGUI} ${PRIM} ${FONT})
+example(ex_haptic2  ex_haptic2.cpp ${NIHGUI} ${IMAGE} ${TTF} ${PRIM} ${FONT}) 
 example(ex_joystick_events ${PRIM} ${FONT})
 example(ex_joystick_hotplugging ${PRIM})
 example(ex_keyboard_events)
diff --git a/examples/ex_haptic2.cpp b/examples/ex_haptic2.cpp
index 0850637..2c4b598 100644
--- a/examples/ex_haptic2.cpp
+++ b/examples/ex_haptic2.cpp
@@ -10,7 +10,8 @@
 
 #include "allegro5/allegro_font.h"
 #include "allegro5/allegro_image.h"
-#include <allegro5/allegro_primitives.h>
+#include "allegro5/allegro_primitives.h"
+#include "allegro5/allegro_ttf.h"
 
 #include "common.c"
 
@@ -218,8 +219,8 @@ Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) :
    level_label("Level", false),
    start_level_slider(3, 10), end_level_slider(7, 10), 
    ramp_effect_label("Ramp Effect"),
-   start_level_label("Start Lvl.", false),
-   end_level_label("End Lvl.", false),
+   start_level_label("Start Level", false),
+   end_level_label("End Level", false),
    right_saturation_slider(5, 10) , right_coeff_slider(5, 10),
    left_saturation_slider(5, 10)  , left_coeff_slider(5, 10),
    deadband_slider(1, 10)         , center_slider(5,10),
@@ -721,6 +722,8 @@ int main(int argc, char *argv[])
    al_install_haptic();
 
    al_init_font_addon();
+   al_init_image_addon();
+   al_init_ttf_addon();
  
    al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS);
    display = al_create_display(800, 600);
@@ -728,17 +731,19 @@ int main(int argc, char *argv[])
       abort_example("Unable to create display\n");
    }
    
-   font = al_create_builtin_font();
+   open_log();
+     
+   font = al_load_font("data/DejaVuSans.ttf", 11, 0);
    if (!font) {
-      abort_example("Failed to create builtin font.\n");
+      log_printf("Failed to load data/DejaVuSans.ttf\n");
+      font = al_create_builtin_font();
+      if (!font) {
+        abort_example("Could not create builtin font.\n");
+      }
    }
    
-   /*
-   font = al_load_font("data/fixed_font.tga", 0, 0);
-   if (!font) {
-      abort_example("Failed to load data/fixed_font.tga\n");
-   }
-   */
+   
+
    
    num_haptics = 0;
    
@@ -773,6 +778,8 @@ int main(int argc, char *argv[])
    for (int i = 0; i < num_haptics; i++) { 
       al_release_haptic(haptics[i].haptic); 
    }
+   
+   close_log(false);
 
    al_destroy_font(font);
 
-- 
1.7.10.4


From a9b27a15bb64a25d3f3686fb1a370688e5e5d003 Mon Sep 17 00:00:00 2001
From: Beoran <beoran@xxxxxxxxx>
Date: Mon, 8 Jul 2013 19:10:27 +0200
Subject: [PATCH 7/8] Show the log, use a ttf font for better legibility, and
 some small fixes.

---
 examples/ex_haptic2.cpp |    3 ---
 1 file changed, 3 deletions(-)

diff --git a/examples/ex_haptic2.cpp b/examples/ex_haptic2.cpp
index 2c4b598..7490617 100644
--- a/examples/ex_haptic2.cpp
+++ b/examples/ex_haptic2.cpp
@@ -742,9 +742,6 @@ int main(int argc, char *argv[])
       }
    }
    
-   
-
-   
    num_haptics = 0;
    
    if(al_is_display_haptic(al_get_current_display())) {
-- 
1.7.10.4


From b109ba23f8c820182922df99c5701306184db351 Mon Sep 17 00:00:00 2001
From: Beoran <beoran@xxxxxxxxx>
Date: Mon, 8 Jul 2013 19:14:58 +0200
Subject: [PATCH 8/8] Indent ex_haptic2.cpp

---
 examples/ex_haptic2.cpp | 1152 ++++++++++++++++++++++++-----------------------
 1 file changed, 580 insertions(+), 572 deletions(-)

diff --git a/examples/ex_haptic2.cpp b/examples/ex_haptic2.cpp
index 7490617..121c769 100644
--- a/examples/ex_haptic2.cpp
+++ b/examples/ex_haptic2.cpp
@@ -19,45 +19,47 @@
 
 #define EX_HAPTIC2_MAX_HAPTICS 8
 
-struct Haptic {
-  ALLEGRO_HAPTIC         * haptic;
-  ALLEGRO_HAPTIC_EFFECT    effect;
-  ALLEGRO_HAPTIC_EFFECT_ID id;
-  const char             * name;
-  bool                     playing;
+struct Haptic
+{
+   ALLEGRO_HAPTIC *haptic;
+   ALLEGRO_HAPTIC_EFFECT effect;
+   ALLEGRO_HAPTIC_EFFECT_ID id;
+   const char *name;
+   bool playing;
 };
 
 
 
-Haptic                   haptics[EX_HAPTIC2_MAX_HAPTICS];
-int                      num_haptics =  0;
+Haptic haptics[EX_HAPTIC2_MAX_HAPTICS];
+int num_haptics = 0;
 /* Haptic                 * last_haptic = NULL; */
 
-struct CapacityName { 
-  int   value;
-  const char * name; 
+struct CapacityName
+{
+   int value;
+   const char *name;
 };
 
 
 CapacityName capname[] = {
-  { ALLEGRO_HAPTIC_RUMBLE   , "ALLEGRO_HAPTIC_RUMBLE"   },  
-  { ALLEGRO_HAPTIC_PERIODIC , "ALLEGRO_HAPTIC_PERIODIC" },
-  { ALLEGRO_HAPTIC_CONSTANT , "ALLEGRO_HAPTIC_CONSTANT" }, 
-  { ALLEGRO_HAPTIC_SPRING   , "ALLEGRO_HAPTIC_SPRING"   },
-  { ALLEGRO_HAPTIC_FRICTION , "ALLEGRO_HAPTIC_FRICTION" },
-  { ALLEGRO_HAPTIC_DAMPER   , "ALLEGRO_HAPTIC_DAMPER"   },
-  { ALLEGRO_HAPTIC_INERTIA  , "ALLEGRO_HAPTIC_INERTIA"  },
-  { ALLEGRO_HAPTIC_RAMP     , "ALLEGRO_HAPTIC_RAMP"     }, 
-  { ALLEGRO_HAPTIC_SQUARE   , "ALLEGRO_HAPTIC_SQUARE"   },
-  { ALLEGRO_HAPTIC_TRIANGLE , "ALLEGRO_HAPTIC_TRIANGLE" },
-  { ALLEGRO_HAPTIC_SINE     , "ALLEGRO_HAPTIC_SINE"     },
-  { ALLEGRO_HAPTIC_SAW_UP   , "ALLEGRO_HAPTIC_SAW_UP"   },
-  { ALLEGRO_HAPTIC_SAW_DOWN , "ALLEGRO_HAPTIC_SAW_DOWN" },
-  { ALLEGRO_HAPTIC_CUSTOM   , "ALLEGRO_HAPTIC_CUSTOM"   },
-  { ALLEGRO_HAPTIC_GAIN     , "ALLEGRO_HAPTIC_GAIN"     },
-  { ALLEGRO_HAPTIC_ANGLE    , "ALLEGRO_HAPTIC_ANGLE"    },
-  { ALLEGRO_HAPTIC_RADIUS   , "ALLEGRO_HAPTIC_RADIUS"   },
-  { ALLEGRO_HAPTIC_AZIMUTH  , "ALLEGRO_HAPTIC_AZIMUTH"  }
+   {ALLEGRO_HAPTIC_RUMBLE, "ALLEGRO_HAPTIC_RUMBLE"},
+   {ALLEGRO_HAPTIC_PERIODIC, "ALLEGRO_HAPTIC_PERIODIC"},
+   {ALLEGRO_HAPTIC_CONSTANT, "ALLEGRO_HAPTIC_CONSTANT"},
+   {ALLEGRO_HAPTIC_SPRING, "ALLEGRO_HAPTIC_SPRING"},
+   {ALLEGRO_HAPTIC_FRICTION, "ALLEGRO_HAPTIC_FRICTION"},
+   {ALLEGRO_HAPTIC_DAMPER, "ALLEGRO_HAPTIC_DAMPER"},
+   {ALLEGRO_HAPTIC_INERTIA, "ALLEGRO_HAPTIC_INERTIA"},
+   {ALLEGRO_HAPTIC_RAMP, "ALLEGRO_HAPTIC_RAMP"},
+   {ALLEGRO_HAPTIC_SQUARE, "ALLEGRO_HAPTIC_SQUARE"},
+   {ALLEGRO_HAPTIC_TRIANGLE, "ALLEGRO_HAPTIC_TRIANGLE"},
+   {ALLEGRO_HAPTIC_SINE, "ALLEGRO_HAPTIC_SINE"},
+   {ALLEGRO_HAPTIC_SAW_UP, "ALLEGRO_HAPTIC_SAW_UP"},
+   {ALLEGRO_HAPTIC_SAW_DOWN, "ALLEGRO_HAPTIC_SAW_DOWN"},
+   {ALLEGRO_HAPTIC_CUSTOM, "ALLEGRO_HAPTIC_CUSTOM"},
+   {ALLEGRO_HAPTIC_GAIN, "ALLEGRO_HAPTIC_GAIN"},
+   {ALLEGRO_HAPTIC_ANGLE, "ALLEGRO_HAPTIC_ANGLE"},
+   {ALLEGRO_HAPTIC_RADIUS, "ALLEGRO_HAPTIC_RADIUS"},
+   {ALLEGRO_HAPTIC_AZIMUTH, "ALLEGRO_HAPTIC_AZIMUTH"}
 };
 
 #define EX_HAPTIC2_START_TYPES   0
@@ -74,109 +76,119 @@ CapacityName capname[] = {
 #define EX_HAPTIC2_END_COORDS   18
 
 
-class CanStopAndPlay {
-   public: 
+class CanStopAndPlay
+{
+ public:
    virtual void on_play() = 0;
    virtual void on_stop() = 0;
 };
 
 
-class PlayButton : public Button {
-protected:
-   CanStopAndPlay * stop_and_play;  
-public:
-   PlayButton(CanStopAndPlay * snp) : Button("Play") , stop_and_play(snp) {}
+class PlayButton:public Button
+{
+ protected:
+   CanStopAndPlay * stop_and_play;
+ public:
+   PlayButton(CanStopAndPlay * snp):Button("Play"), stop_and_play(snp)
+   {
+   }
    void on_click(int mx, int my);
 };
 
 
 void PlayButton::on_click(int, int)
 {
-   if (is_disabled()) return; 
+   if (is_disabled())
+      return;
    log_printf("Start playing...\n");
-   if(stop_and_play) {
+   if (stop_and_play) {
       stop_and_play->on_play();
    }
 }
 
-class StopButton : public Button {
-protected:
-   CanStopAndPlay * stop_and_play;  
-public:
-   StopButton(CanStopAndPlay * snp) : Button("Stop") , stop_and_play(snp) {}
+class StopButton:public Button
+{
+ protected:
+   CanStopAndPlay * stop_and_play;
+ public:
+   StopButton(CanStopAndPlay * snp):Button("Stop"), stop_and_play(snp)
+   {
+   }
    void on_click(int mx, int my);
 };
 
 
 void StopButton::on_click(int, int)
 {
-   if (is_disabled()) return; 
+   if (is_disabled())
+      return;
    log_printf("Stop playing...\n");
-   if(stop_and_play) {
+   if (stop_and_play) {
       stop_and_play->on_stop();
    }
 }
 
 
 
-class Prog : public CanStopAndPlay {
-   private:
-   Dialog d;  
-   
-   List  device_list;
-   List  type_list;
-   List  waveform_list;
-   
-   Label device_label;  
+class Prog:public CanStopAndPlay
+{
+ private:
+   Dialog d;
+
+   List device_list;
+   List type_list;
+   List waveform_list;
+
+   Label device_label;
    Label type_label;
    Label waveform_label;
-   
+
    HSlider length_slider, delay_slider, loops_slider;
    Label replay_label, length_label, delay_label, loops_label;
-   
+
    HSlider attack_length_slider, attack_level_slider;
    HSlider fade_length_slider, fade_level_slider;
    Label envelope_label, attack_length_label, attack_level_label;
    Label fade_length_label, fade_level_label;
-   
+
    HSlider angle_slider, radius_slider, azimuth_slider;
-   Label   coordinates_label, angle_label , radius_label , azimuth_label;
-   
+   Label coordinates_label, angle_label, radius_label, azimuth_label;
+
    HSlider level_slider;
-   Label   constant_effect_label, level_label;
-   
+   Label constant_effect_label, level_label;
+
    HSlider start_level_slider, end_level_slider;
    Label ramp_effect_label, start_level_label, end_level_label;
 
    HSlider right_saturation_slider, right_coeff_slider;
-   HSlider left_saturation_slider , left_coeff_slider;
-   HSlider deadband_slider        , center_slider;
-   
+   HSlider left_saturation_slider, left_coeff_slider;
+   HSlider deadband_slider, center_slider;
+
    Label right_saturation_label, right_coeff_label;
-   Label left_saturation_label , left_coeff_label;
+   Label left_saturation_label, left_coeff_label;
    Label condition_effect_label, deadband_label, center_label;
-   
+
    HSlider period_slider, magnitude_slider, offset_slider, phase_slider;
-   Label periodic_effect_label; 
+   Label periodic_effect_label;
    Label period_label, magnitude_label, offset_label, phase_label;
-   
+
    HSlider strong_magnitude_slider, weak_magnitude_slider;
    Label rumble_effect_label, strong_magnitude_label, weak_magnitude_label;
 
    HSlider gain_slider;
    Label gain_label;
-   
+
    Label message_label, message_label_label;
-   
+
    PlayButton play_button;
    StopButton stop_button;
-   
-   Haptic                 * last_haptic;
-   Haptic                 * show_haptic;
-   
-   
-public:
-   Prog(const Theme & theme, ALLEGRO_DISPLAY *display);
+
+   Haptic *last_haptic;
+   Haptic *show_haptic;
+
+
+ public:
+   Prog(const Theme & theme, ALLEGRO_DISPLAY * display);
    void run();
    void update();
    virtual void on_play();
@@ -185,180 +197,153 @@ public:
 };
 
 
-Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) :
-   d(Dialog(theme, display, 20, 40)),
-   device_list(0),
-   type_list(0),
-   waveform_list(0),
-   device_label("Haptic Device"),
-   type_label("Haptic Effect Type"), 
-   waveform_label("Wave Form Periodic Effect"),
-   length_slider(1, 10),
-   delay_slider(1, 10),
-   loops_slider(1, 10), 
-   replay_label("Replay"),
-   length_label("Length", false),
-   delay_label("Delay", false),
-   loops_label("Loops"),   
-   attack_length_slider(2, 10),
-   attack_level_slider(4, 10),
-   fade_length_slider(2, 10),
-   fade_level_slider(4, 10),
-   envelope_label("Envelope"),
-   attack_length_label("Attack Length", false),
-   attack_level_label("Attack Level", false),
-   fade_length_label("Fade Length", false),
-   fade_level_label("Fade Level", false),
-   angle_slider(0, 360), radius_slider(0, 10), azimuth_slider(180, 360),
-   coordinates_label("Coordinates"),
-   angle_label("Angle", false), 
-   radius_label("Radius", false), 
-   azimuth_label("Azimuth", false),
-   level_slider(5, 10), 
-   constant_effect_label("Constant Effect"),
-   level_label("Level", false),
-   start_level_slider(3, 10), end_level_slider(7, 10), 
-   ramp_effect_label("Ramp Effect"),
-   start_level_label("Start Level", false),
-   end_level_label("End Level", false),
-   right_saturation_slider(5, 10) , right_coeff_slider(5, 10),
-   left_saturation_slider(5, 10)  , left_coeff_slider(5, 10),
-   deadband_slider(1, 10)         , center_slider(5,10),
-   right_saturation_label("Right Saturation", false), 
-   right_coeff_label("Right Coefficient", false),
-   left_saturation_label("Left Saturation", false), 
-   left_coeff_label("Left Coefficient", false),
-   condition_effect_label("Condition Effect"),
-   deadband_label("Deadband", false), 
-   center_label("Center", false),
-   period_slider(1, 10), magnitude_slider(5, 10), 
-   offset_slider(0, 10), phase_slider(0, 10),
-   periodic_effect_label("Periodic Effect"), 
-   period_label("Period", false), 
-   magnitude_label("Magnitude", false), 
-   offset_label("Offset", false), 
-   phase_label("Phase", false),
-   strong_magnitude_slider(5, 10), 
-   weak_magnitude_slider(5, 10),
-   rumble_effect_label("Rumble effect"),
-   strong_magnitude_label("Strong Magnitude", false), 
-   weak_magnitude_label("Weak Magnitude", false),
-   gain_slider(10, 10),
-   gain_label("Gain"),
-   message_label("Ready.", false),
-   message_label_label("Status", false),
-   play_button(this),
-   stop_button(this),
-   last_haptic(NULL),
-   show_haptic(NULL)
+Prog::Prog(const Theme & theme,
+           ALLEGRO_DISPLAY * display):d(Dialog(theme, display, 20, 40)),
+device_list(0), type_list(0), waveform_list(0), device_label("Haptic Device"),
+type_label("Haptic Effect Type"), waveform_label("Wave Form Periodic Effect"),
+length_slider(1, 10), delay_slider(1, 10), loops_slider(1, 10),
+replay_label("Replay"), length_label("Length", false), delay_label("Delay",
+                                                                   false),
+loops_label("Loops"), attack_length_slider(2, 10), attack_level_slider(4, 10),
+fade_length_slider(2, 10), fade_level_slider(4, 10), envelope_label("Envelope"),
+attack_length_label("Attack Length", false), attack_level_label("Attack Level",
+                                                                false),
+fade_length_label("Fade Length", false), fade_level_label("Fade Level", false),
+angle_slider(0, 360), radius_slider(0, 10), azimuth_slider(180, 360),
+coordinates_label("Coordinates"), angle_label("Angle", false),
+radius_label("Radius", false), azimuth_label("Azimuth", false), level_slider(5,
+                                                                             10),
+constant_effect_label("Constant Effect"), level_label("Level", false),
+start_level_slider(3, 10), end_level_slider(7, 10),
+ramp_effect_label("Ramp Effect"), start_level_label("Start Level", false),
+end_level_label("End Level", false), right_saturation_slider(5, 10),
+right_coeff_slider(5, 10), left_saturation_slider(5, 10), left_coeff_slider(5,
+                                                                            10),
+deadband_slider(1, 10), center_slider(5, 10),
+right_saturation_label("Right Saturation", false),
+right_coeff_label("Right Coefficient", false),
+left_saturation_label("Left Saturation", false),
+left_coeff_label("Left Coefficient", false),
+condition_effect_label("Condition Effect"), deadband_label("Deadband", false),
+center_label("Center", false), period_slider(1, 10), magnitude_slider(5, 10),
+offset_slider(0, 10), phase_slider(0, 10),
+periodic_effect_label("Periodic Effect"), period_label("Period", false),
+magnitude_label("Magnitude", false), offset_label("Offset", false),
+phase_label("Phase", false), strong_magnitude_slider(5, 10),
+weak_magnitude_slider(5, 10), rumble_effect_label("Rumble effect"),
+strong_magnitude_label("Strong Magnitude", false),
+weak_magnitude_label("Weak Magnitude", false), gain_slider(10, 10),
+gain_label("Gain"), message_label("Ready.", false),
+message_label_label("Status", false), play_button(this), stop_button(this),
+last_haptic(NULL), show_haptic(NULL)
 {
-  for (int i = 0; i < num_haptics; i++) {
-    device_list.append_item(haptics[i].name);
-  } 
-  d.add(device_label, 0, 1, 7, 1); 
-  d.add(device_list , 0, 2, 7, 8);
-
-  
-   for (int i = EX_HAPTIC2_START_TYPES  ; i < EX_HAPTIC2_END_TYPES  ; i++) {
-     type_list.append_item(capname[i].name);
-   }
-   d.add(type_label, 7, 1, 6, 1);    
-   d.add(type_list , 7, 2, 6, 8);
-   
-   for (int i = EX_HAPTIC2_START_WAVES  ; i < EX_HAPTIC2_END_WAVES  ; i++) {
-     waveform_list.append_item(capname[i].name);
-   }
-   d.add(waveform_label, 13, 1, 7, 1); 
-   d.add(waveform_list , 13, 2, 7, 8);
-   
-   d.add(replay_label , 0, 11 , 7, 1);
-   d.add(length_label , 0, 12 , 2, 1);
-   d.add(length_slider, 2, 12 , 5, 1);
-   d.add(delay_label  , 0, 13 , 2, 1);
-   d.add(delay_slider , 2, 13 , 5, 1);
-   
-   d.add(loops_label            ,  7, 11, 7, 1);
-   d.add(loops_slider           ,  7, 12, 6, 1);
-   d.add(gain_label             , 13, 11, 7, 1);
-   d.add(gain_slider            , 13, 12, 7, 1);
- 
-   
-   d.add(envelope_label         , 0, 15, 9, 1);
-   d.add(attack_length_label    , 0, 16, 3, 1);
-   d.add(attack_length_slider   , 4, 16, 6, 1);
-   d.add(attack_level_label     , 0, 17, 3, 1);
-   d.add(attack_level_slider    , 4, 17, 6, 1);
-   d.add(fade_length_label      , 0, 18, 3, 1);
-   d.add(fade_length_slider     , 4, 18, 6, 1);
-   d.add(fade_level_label       , 0, 19, 3, 1);
-   d.add(fade_level_slider      , 4, 19, 6, 1);
-   
-   d.add(coordinates_label      , 11, 15, 9, 1);
-   d.add(angle_label            , 11, 16, 2, 1);
-   d.add(angle_slider           , 13, 16, 7, 1);
-   d.add(radius_label           , 11, 17, 2, 1);
-   d.add(radius_slider          , 13, 17, 7, 1);
-   d.add(azimuth_label          , 11, 18, 2, 1);
-   d.add(azimuth_slider         , 13, 18, 7, 1);
-  
-   
-   d.add(condition_effect_label ,  0, 21, 9, 1); 
-   d.add(right_coeff_label      ,  0, 22, 4, 1);
-   d.add(right_coeff_slider     ,  4, 22, 6, 1);
-   d.add(right_saturation_label ,  0, 23, 4, 1);
-   d.add(right_saturation_slider,  4, 23, 6, 1);  
-   d.add(left_coeff_label       ,  0, 24, 4, 1);
-   d.add(left_coeff_slider      ,  4, 24, 6, 1);
-   d.add(left_saturation_label  ,  0, 25, 4, 1);
-   d.add(left_saturation_slider ,  4, 25, 6, 1);
-   d.add(deadband_label         ,  0, 26, 4, 1);
-   d.add(deadband_slider        ,  4, 26, 6, 1);
-   d.add(center_label           ,  0, 27, 4, 1);
-   d.add(center_slider          ,  4, 27, 6, 1);
-   
-
-   
-   d.add(periodic_effect_label  , 11, 21, 9, 1);
-   d.add(period_label           , 11, 22, 2, 1);
-   d.add(period_slider          , 13, 22, 7, 1);
-   d.add(magnitude_label        , 11, 23, 2, 1);
-   d.add(magnitude_slider       , 13, 23, 7, 1);
-   d.add(offset_label           , 11, 24, 2, 1);
-   d.add(offset_slider          , 13, 24, 7, 1);
-   d.add(phase_label            , 11, 25, 2, 1);
-   d.add(phase_slider           , 13, 25, 7, 1);
-   
-   d.add(ramp_effect_label      , 11, 29, 9, 1); 
-   d.add(start_level_label      , 11, 30, 2, 1);
-   d.add(start_level_slider     , 13, 30, 7, 1);
-   d.add(end_level_label        , 11, 31, 2, 1);
-   d.add(end_level_slider       , 13, 31, 7, 1);  
-   
-   d.add(rumble_effect_label    ,  0, 29, 9, 1);
-   d.add(strong_magnitude_label ,  0, 30, 4, 1);
-   d.add(strong_magnitude_slider,  4, 30, 6, 1);
-   d.add(weak_magnitude_label   ,  0, 31, 4, 1);
-   d.add(weak_magnitude_slider  ,  4, 31, 6, 1);
-   
-   d.add(constant_effect_label  ,  0, 33, 9, 1);
-   d.add(level_label            ,  0, 34, 3, 1);
-   d.add(level_slider           ,  4, 34, 6, 1);
-   
-   d.add(message_label_label    ,  0, 36,  2, 1);
-   d.add(message_label          ,  2, 36, 12, 1);
-   
-  
-   d.add(play_button  , 6, 38,  3, 2); 
-   d.add(stop_button  , 12, 38, 3, 2); 
-
-   
+   for (int i = 0; i < num_haptics; i++) {
+      device_list.append_item(haptics[i].name);
+   }
+   d.add(device_label, 0, 1, 7, 1);
+   d.add(device_list, 0, 2, 7, 8);
+
+
+   for (int i = EX_HAPTIC2_START_TYPES; i < EX_HAPTIC2_END_TYPES; i++) {
+      type_list.append_item(capname[i].name);
+   }
+   d.add(type_label, 7, 1, 6, 1);
+   d.add(type_list, 7, 2, 6, 8);
+
+   for (int i = EX_HAPTIC2_START_WAVES; i < EX_HAPTIC2_END_WAVES; i++) {
+      waveform_list.append_item(capname[i].name);
+   }
+   d.add(waveform_label, 13, 1, 7, 1);
+   d.add(waveform_list, 13, 2, 7, 8);
+
+   d.add(replay_label, 0, 11, 7, 1);
+   d.add(length_label, 0, 12, 2, 1);
+   d.add(length_slider, 2, 12, 5, 1);
+   d.add(delay_label, 0, 13, 2, 1);
+   d.add(delay_slider, 2, 13, 5, 1);
+
+   d.add(loops_label, 7, 11, 7, 1);
+   d.add(loops_slider, 7, 12, 6, 1);
+   d.add(gain_label, 13, 11, 7, 1);
+   d.add(gain_slider, 13, 12, 7, 1);
+
+
+   d.add(envelope_label, 0, 15, 9, 1);
+   d.add(attack_length_label, 0, 16, 3, 1);
+   d.add(attack_length_slider, 4, 16, 6, 1);
+   d.add(attack_level_label, 0, 17, 3, 1);
+   d.add(attack_level_slider, 4, 17, 6, 1);
+   d.add(fade_length_label, 0, 18, 3, 1);
+   d.add(fade_length_slider, 4, 18, 6, 1);
+   d.add(fade_level_label, 0, 19, 3, 1);
+   d.add(fade_level_slider, 4, 19, 6, 1);
+
+   d.add(coordinates_label, 11, 15, 9, 1);
+   d.add(angle_label, 11, 16, 2, 1);
+   d.add(angle_slider, 13, 16, 7, 1);
+   d.add(radius_label, 11, 17, 2, 1);
+   d.add(radius_slider, 13, 17, 7, 1);
+   d.add(azimuth_label, 11, 18, 2, 1);
+   d.add(azimuth_slider, 13, 18, 7, 1);
+
+
+   d.add(condition_effect_label, 0, 21, 9, 1);
+   d.add(right_coeff_label, 0, 22, 4, 1);
+   d.add(right_coeff_slider, 4, 22, 6, 1);
+   d.add(right_saturation_label, 0, 23, 4, 1);
+   d.add(right_saturation_slider, 4, 23, 6, 1);
+   d.add(left_coeff_label, 0, 24, 4, 1);
+   d.add(left_coeff_slider, 4, 24, 6, 1);
+   d.add(left_saturation_label, 0, 25, 4, 1);
+   d.add(left_saturation_slider, 4, 25, 6, 1);
+   d.add(deadband_label, 0, 26, 4, 1);
+   d.add(deadband_slider, 4, 26, 6, 1);
+   d.add(center_label, 0, 27, 4, 1);
+   d.add(center_slider, 4, 27, 6, 1);
+
+
+
+   d.add(periodic_effect_label, 11, 21, 9, 1);
+   d.add(period_label, 11, 22, 2, 1);
+   d.add(period_slider, 13, 22, 7, 1);
+   d.add(magnitude_label, 11, 23, 2, 1);
+   d.add(magnitude_slider, 13, 23, 7, 1);
+   d.add(offset_label, 11, 24, 2, 1);
+   d.add(offset_slider, 13, 24, 7, 1);
+   d.add(phase_label, 11, 25, 2, 1);
+   d.add(phase_slider, 13, 25, 7, 1);
+
+   d.add(ramp_effect_label, 11, 29, 9, 1);
+   d.add(start_level_label, 11, 30, 2, 1);
+   d.add(start_level_slider, 13, 30, 7, 1);
+   d.add(end_level_label, 11, 31, 2, 1);
+   d.add(end_level_slider, 13, 31, 7, 1);
+
+   d.add(rumble_effect_label, 0, 29, 9, 1);
+   d.add(strong_magnitude_label, 0, 30, 4, 1);
+   d.add(strong_magnitude_slider, 4, 30, 6, 1);
+   d.add(weak_magnitude_label, 0, 31, 4, 1);
+   d.add(weak_magnitude_slider, 4, 31, 6, 1);
+
+   d.add(constant_effect_label, 0, 33, 9, 1);
+   d.add(level_label, 0, 34, 3, 1);
+   d.add(level_slider, 4, 34, 6, 1);
+
+   d.add(message_label_label, 0, 36, 2, 1);
+   d.add(message_label, 2, 36, 12, 1);
+
+
+   d.add(play_button, 6, 38, 3, 2);
+   d.add(stop_button, 12, 38, 3, 2);
+
+
    /*
-   rgba_label[0] = Label("Source tint/color RGBA");
-   rgba_label[1] = Label("Dest tint/color RGBA");
-   d.add(rgba_label[0], 1, 34, 5, 1);
-   d.add(rgba_label[1], 7, 34, 5, 1);
+      rgba_label[0] = Label("Source tint/color RGBA");
+      rgba_label[1] = Label("Dest tint/color RGBA");
+      d.add(rgba_label[0], 1, 34, 5, 1);
+      d.add(rgba_label[1], 7, 34, 5, 1);
 
-   for (int i = 0; i < 2; i++) {
+      for (int i = 0; i < 2; i++) {
       r[i] = HSlider(255, 255);
       g[i] = HSlider(255, 255);
       b[i] = HSlider(255, 255);
@@ -367,132 +352,135 @@ Prog::Prog(const Theme & theme, ALLEGRO_DISPLAY *display) :
       d.add(g[i], 1 + i * 6, 36, 5, 1);
       d.add(b[i], 1 + i * 6, 37, 5, 1);
       d.add(a[i], 1 + i * 6, 38, 5, 1);
-   }
-   */
+      }
+    */
 }
 
 #define TEST_CAP(CAP, FLAG) (((CAP) & (FLAG)) == (FLAG))
 
-void Prog::update() {
-  /* Update playing state and display. */  
-  if(last_haptic && last_haptic->playing) {
-    if(!al_is_haptic_effect_playing(&last_haptic->id)) {
-      last_haptic->playing = false;
-      al_release_haptic_effect(&last_haptic->id);
-      message_label.set_text("Done.");
-      play_button.set_disabled(false);
-      d.request_draw();
-      log_printf("Play done on %s\n", last_haptic->name);
-    }
-  }
-  /* Update availability of controls based on capabilities. */
-  int devno = device_list.get_cur_value();
-  Haptic * dev = haptics + devno;
-  if (dev && dev->haptic) {
-    if ( dev != show_haptic) {
-      /* Take a deep breath , here we go...*/
-      bool condition, envelope, periodic;
-      show_haptic = dev;
-      int cap = al_get_haptic_capabilities(show_haptic->haptic);
-      
-      /* Gain capability */
-      gain_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_GAIN));
-      gain_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_GAIN));
-      
-      
-      /* Envelope related capabilities and sliders. */
-      envelope = TEST_CAP(cap, ALLEGRO_HAPTIC_PERIODIC) ||
-                 TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT) ||
-                 TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP);
-      
-      envelope_label.set_disabled(!envelope); 
-      attack_level_slider.set_disabled(!envelope);
-      attack_length_slider.set_disabled(!envelope);
-      fade_level_slider.set_disabled(!envelope);
-      fade_length_slider.set_disabled(!envelope);
-      attack_level_label.set_disabled(!envelope);
-      attack_length_label.set_disabled(!envelope);
-      fade_level_label.set_disabled(!envelope);
-      fade_length_label.set_disabled(!envelope);
-      
-      /* Coordinate related capabilities. */ 
-      angle_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_ANGLE));
-      angle_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_ANGLE));
-      radius_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RADIUS));
-      radius_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RADIUS));      
-      azimuth_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_AZIMUTH));      
-      azimuth_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_AZIMUTH)); 
-      
-      /* Condition effect related capabilities. */
-      condition  = TEST_CAP(cap, ALLEGRO_HAPTIC_DAMPER) ||
-                 TEST_CAP(cap, ALLEGRO_HAPTIC_FRICTION) ||
-                 TEST_CAP(cap, ALLEGRO_HAPTIC_INERTIA)  ||
-                 TEST_CAP(cap, ALLEGRO_HAPTIC_SPRING);
-      
-      condition_effect_label.set_disabled(!condition);
-      right_coeff_slider.set_disabled(!condition);
-      left_coeff_slider.set_disabled(!condition);
-      right_saturation_slider.set_disabled(!condition);
-      left_saturation_slider.set_disabled(!condition);
-      center_slider.set_disabled(!condition);
-      deadband_slider.set_disabled(!condition);
-      right_coeff_label.set_disabled(!condition);
-      left_coeff_label.set_disabled(!condition);
-      right_saturation_label.set_disabled(!condition);
-      left_saturation_label.set_disabled(!condition);
-      center_label.set_disabled(!condition);
-      deadband_label.set_disabled(!condition);
-      
-      /* Constant effect related capabilities. */
-      constant_effect_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT)); 
-      level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT));
-      level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT)); 
-      
-      /* Ramp effect capabilities. */
-      ramp_effect_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP)); 
-      start_level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP));
-      start_level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP)); 
-      end_level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP));
-      end_level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP)); 
-      
-      /* Period effect capabilities. */
-      periodic = TEST_CAP(cap, ALLEGRO_HAPTIC_PERIODIC);
-      waveform_label.set_disabled(!periodic);
-      waveform_list.set_disabled(!periodic);
-      periodic_effect_label.set_disabled(!periodic);
-      period_slider.set_disabled(!periodic);
-      magnitude_slider.set_disabled(!periodic);
-      offset_slider.set_disabled(!periodic);
-      phase_slider.set_disabled(!periodic);
-      period_label.set_disabled(!periodic);
-      magnitude_label.set_disabled(!periodic);
-      offset_label.set_disabled(!periodic);
-      phase_label.set_disabled(!periodic);
-      
-      /*Change list of supported effect types*/
-      type_list.clear_items();
-      for (int i = EX_HAPTIC2_START_TYPES; i < EX_HAPTIC2_END_TYPES; i ++) {
-        CapacityName * cn = capname + i;
-        if (TEST_CAP(cap, cn->value)) { 
-          type_list.append_item(cn->name);
-        }
+void Prog::update()
+{
+   /* Update playing state and display. */
+   if (last_haptic && last_haptic->playing) {
+      if (!al_is_haptic_effect_playing(&last_haptic->id)) {
+         last_haptic->playing = false;
+         al_release_haptic_effect(&last_haptic->id);
+         message_label.set_text("Done.");
+         play_button.set_disabled(false);
+         d.request_draw();
+         log_printf("Play done on %s\n", last_haptic->name);
       }
-      
-      /* Change list of supported wave form types. */
-      waveform_list.clear_items();
-      for (int i = EX_HAPTIC2_START_WAVES; i < EX_HAPTIC2_END_WAVES; i ++) {
-        CapacityName * cn = capname + i;
-        if (TEST_CAP(cap, cn->value)) { 
-          waveform_list.append_item(cn->name);
-        }
+   }
+   /* Update availability of controls based on capabilities. */
+   int devno = device_list.get_cur_value();
+   Haptic *dev = haptics + devno;
+   if (dev && dev->haptic) {
+      if (dev != show_haptic) {
+         /* Take a deep breath , here we go... */
+         bool condition, envelope, periodic;
+         show_haptic = dev;
+         int cap = al_get_haptic_capabilities(show_haptic->haptic);
+
+         /* Gain capability */
+         gain_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_GAIN));
+         gain_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_GAIN));
+
+
+         /* Envelope related capabilities and sliders. */
+         envelope = TEST_CAP(cap, ALLEGRO_HAPTIC_PERIODIC) ||
+             TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT) ||
+             TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP);
+
+         envelope_label.set_disabled(!envelope);
+         attack_level_slider.set_disabled(!envelope);
+         attack_length_slider.set_disabled(!envelope);
+         fade_level_slider.set_disabled(!envelope);
+         fade_length_slider.set_disabled(!envelope);
+         attack_level_label.set_disabled(!envelope);
+         attack_length_label.set_disabled(!envelope);
+         fade_level_label.set_disabled(!envelope);
+         fade_length_label.set_disabled(!envelope);
+
+         /* Coordinate related capabilities. */
+         angle_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_ANGLE));
+         angle_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_ANGLE));
+         radius_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RADIUS));
+         radius_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RADIUS));
+         azimuth_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_AZIMUTH));
+         azimuth_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_AZIMUTH));
+
+         /* Condition effect related capabilities. */
+         condition = TEST_CAP(cap, ALLEGRO_HAPTIC_DAMPER) ||
+             TEST_CAP(cap, ALLEGRO_HAPTIC_FRICTION) ||
+             TEST_CAP(cap, ALLEGRO_HAPTIC_INERTIA) ||
+             TEST_CAP(cap, ALLEGRO_HAPTIC_SPRING);
+
+         condition_effect_label.set_disabled(!condition);
+         right_coeff_slider.set_disabled(!condition);
+         left_coeff_slider.set_disabled(!condition);
+         right_saturation_slider.set_disabled(!condition);
+         left_saturation_slider.set_disabled(!condition);
+         center_slider.set_disabled(!condition);
+         deadband_slider.set_disabled(!condition);
+         right_coeff_label.set_disabled(!condition);
+         left_coeff_label.set_disabled(!condition);
+         right_saturation_label.set_disabled(!condition);
+         left_saturation_label.set_disabled(!condition);
+         center_label.set_disabled(!condition);
+         deadband_label.set_disabled(!condition);
+
+         /* Constant effect related capabilities. */
+         constant_effect_label.
+             set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT));
+         level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT));
+         level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_CONSTANT));
+
+         /* Ramp effect capabilities. */
+         ramp_effect_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP));
+         start_level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP));
+         start_level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP));
+         end_level_slider.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP));
+         end_level_label.set_disabled(!TEST_CAP(cap, ALLEGRO_HAPTIC_RAMP));
+
+         /* Period effect capabilities. */
+         periodic = TEST_CAP(cap, ALLEGRO_HAPTIC_PERIODIC);
+         waveform_label.set_disabled(!periodic);
+         waveform_list.set_disabled(!periodic);
+         periodic_effect_label.set_disabled(!periodic);
+         period_slider.set_disabled(!periodic);
+         magnitude_slider.set_disabled(!periodic);
+         offset_slider.set_disabled(!periodic);
+         phase_slider.set_disabled(!periodic);
+         period_label.set_disabled(!periodic);
+         magnitude_label.set_disabled(!periodic);
+         offset_label.set_disabled(!periodic);
+         phase_label.set_disabled(!periodic);
+
+         /*Change list of supported effect types */
+         type_list.clear_items();
+         for (int i = EX_HAPTIC2_START_TYPES; i < EX_HAPTIC2_END_TYPES; i++) {
+            CapacityName *cn = capname + i;
+            if (TEST_CAP(cap, cn->value)) {
+               type_list.append_item(cn->name);
+            }
+         }
+
+         /* Change list of supported wave form types. */
+         waveform_list.clear_items();
+         for (int i = EX_HAPTIC2_START_WAVES; i < EX_HAPTIC2_END_WAVES; i++) {
+            CapacityName *cn = capname + i;
+            if (TEST_CAP(cap, cn->value)) {
+               waveform_list.append_item(cn->name);
+            }
+         }
+
       }
-      
-    }
-  } else {
-    play_button.set_disabled(true);
-    message_label.set_text("No Haptic Device.");
-  }
-  
+   }
+   else {
+      play_button.set_disabled(true);
+      message_label.set_text("No Haptic Device.");
+   }
+
 }
 
 
@@ -501,8 +489,8 @@ void Prog::run()
    d.prepare();
 
    while (!d.is_quit_requested()) {
-      update(); 
-      if (d.is_draw_requested()) {        
+      update();
+      if (d.is_draw_requested()) {
          al_clear_to_color(al_map_rgb(128, 148, 168));
          d.draw();
          al_flip_display();
@@ -510,197 +498,216 @@ void Prog::run()
 
       d.run_step(true);
    }
-   on_stop(); /* Stop playing anything we were still playing. */
+   on_stop();                   /* Stop playing anything we were still playing. */
 }
 
-int cap_for_name(const std::string& name) {
-  for (int i = 0; i < EX_HAPTIC2_END_WAVES; i++) {
-    if (name == capname[i].name) {
-      return capname[i].value;
-    } 
-  }
-  return -1;
+int cap_for_name(const std::string & name)
+{
+   for (int i = 0; i < EX_HAPTIC2_END_WAVES; i++) {
+      if (name == capname[i].name) {
+         return capname[i].value;
+      }
+   }
+   return -1;
 }
 
-const char * cap_to_name(int cap) {
-  for (int i = 0; i < EX_HAPTIC2_END_WAVES; i++) {
-    if (cap == capname[i].value) {
-      return capname[i].name;
-    } 
-  }
-  return "unknown";
+const char *cap_to_name(int cap)
+{
+   for (int i = 0; i < EX_HAPTIC2_END_WAVES; i++) {
+      if (cap == capname[i].value) {
+         return capname[i].name;
+      }
+   }
+   return "unknown";
 }
 
 
-double slider_to_magnitude(const HSlider & slider) {
-  double value = (double) slider.get_cur_value();
-  double max   = (double) slider.get_max_value();
-  return value / max;
+double slider_to_magnitude(const HSlider & slider)
+{
+   double value = (double)slider.get_cur_value();
+   double max = (double)slider.get_max_value();
+   return value / max;
 }
 
-double slider_to_duration(const HSlider & slider) {
-  double value = (double) slider.get_cur_value();
-  double max   = 1.0;
-  return value / max;
+double slider_to_duration(const HSlider & slider)
+{
+   double value = (double)slider.get_cur_value();
+   double max = 1.0;
+   return value / max;
 }
 
-double slider_to_angle(const HSlider & slider) {
-  double value = (double) slider.get_cur_value();
-  double max   = (double) slider.get_max_value();
-  return value / max;
+double slider_to_angle(const HSlider & slider)
+{
+   double value = (double)slider.get_cur_value();
+   double max = (double)slider.get_max_value();
+   return value / max;
 }
 
-void Prog::get_envelope(ALLEGRO_HAPTIC_ENVELOPE * envelope) {
-  if(!envelope) return;
-  envelope->attack_length = slider_to_duration(attack_length_slider);
-  envelope->fade_length   = slider_to_duration(fade_length_slider);
-  envelope->attack_level  = slider_to_magnitude(attack_level_slider);
-  envelope->fade_level    = slider_to_magnitude(fade_level_slider);
-} 
-
-void Prog::on_play() {
-  int devno  = device_list.get_cur_value();
-  if ((devno < 0) || (devno >= num_haptics)) {
-    message_label.set_text("No Haptic Device!");
-    log_printf("No such device: %d\n", devno); 
-    return;
-  }  
-  Haptic * haptic     = haptics + devno;  
-  
-  if (!haptic || !haptic->haptic) {
-    log_printf("Device is NULL: %d\n", devno);
-    message_label.set_text("Device Is NULL!");
-    return;
-  }  
-  
-  if (!al_get_haptic_active(haptic->haptic)) {
-    message_label.set_text("Device Not Active!");
-    log_printf("Device is not active: %d\n", devno); 
-    return;
-  }
-  
-  /* Stop playing previous effect. */
-  if (haptic->playing) { 
-    al_stop_haptic_effect(&haptic->id);
-    haptic->playing = false;
-    al_release_haptic_effect(&haptic->id);
-  }
-  
-  /* First set gain. */
-  double gain         = slider_to_magnitude(gain_slider);
-  al_set_haptic_gain(haptic->haptic, gain);
-  
-  /* Now fill in the effect struct. */
-  int type            = cap_for_name(type_list.get_selected_item_text());
-  int wavetype        = cap_for_name (waveform_list.get_selected_item_text());
-  
-  if (type < 0)  {
-    message_label.set_text("Unknown Effect Type!");
-    log_printf("Unknown effect type: %d on %s\n", type, haptic->name); 
-    return;
-  }
-  
-  if (wavetype < 0)  {
-    message_label.set_text("Unknown Wave Form!");
-    log_printf("Unknown wave type: %d on %s\n", wavetype, haptic->name); 
-    return;
-  }
-  
-  haptic->effect.type               = type;
-  haptic->effect.replay.delay       = slider_to_duration(delay_slider);
-  haptic->effect.replay.length      = slider_to_duration(length_slider);
-  int loops                         = loops_slider.get_cur_value();
-  haptic->effect.direction.angle    = slider_to_angle(angle_slider);
-  haptic->effect.direction.radius   = slider_to_magnitude(angle_slider);
-  haptic->effect.direction.azimuth  = slider_to_angle(angle_slider);  
-  
-  switch (type) {
-  case ALLEGRO_HAPTIC_RUMBLE:
-     haptic->effect.data.rumble.strong_magnitude = 
-        slider_to_magnitude(strong_magnitude_slider);
-     haptic->effect.data.rumble.weak_magnitude = 
-        slider_to_magnitude(weak_magnitude_slider);    
-  break;
-  case ALLEGRO_HAPTIC_PERIODIC:
-    get_envelope(&haptic->effect.data.periodic.envelope);
-    haptic->effect.data.periodic.waveform   = wavetype;
-    haptic->effect.data.periodic.magnitude  = slider_to_magnitude(magnitude_slider);
-    haptic->effect.data.periodic.period     = slider_to_duration(period_slider);
-    haptic->effect.data.periodic.offset     = slider_to_duration(offset_slider);
-    haptic->effect.data.periodic.phase      = slider_to_duration(phase_slider);
-    haptic->effect.data.periodic.custom_len = 0;
-    haptic->effect.data.periodic.custom_data= NULL;
-  break;
-  case ALLEGRO_HAPTIC_CONSTANT:
-    get_envelope(&haptic->effect.data.constant.envelope);
-    haptic->effect.data.constant.level    = slider_to_magnitude(level_slider);
-  break;
-  case ALLEGRO_HAPTIC_RAMP:
-    get_envelope(&haptic->effect.data.ramp.envelope);
-    haptic->effect.data.ramp.start_level  = slider_to_magnitude(start_level_slider);
-    haptic->effect.data.ramp.end_level    = slider_to_magnitude(end_level_slider);
-  break; 
-  
-  case ALLEGRO_HAPTIC_SPRING:
-  case ALLEGRO_HAPTIC_FRICTION:
-  case ALLEGRO_HAPTIC_DAMPER:
-  case ALLEGRO_HAPTIC_INERTIA: /* fall through. */
-     haptic->effect.data.condition.right_saturation = 
-        slider_to_magnitude(right_saturation_slider);
-     haptic->effect.data.condition.left_saturation = 
-        slider_to_magnitude(left_saturation_slider);   
-     haptic->effect.data.condition.right_coeff = 
-        slider_to_magnitude(right_coeff_slider);   
-     haptic->effect.data.condition.left_coeff = 
-        slider_to_magnitude(left_coeff_slider);
-     haptic->effect.data.condition.deadband = 
-        slider_to_magnitude(deadband_slider);
-     haptic->effect.data.condition.center = 
-        slider_to_magnitude(center_slider);
-        /* XXX, need a different conversion function here, but  I don't have a 
-         * controller that supports condition effects anyway... :p
-         */
-     break;
-  default:
-    message_label.set_text("Unknown Effect Type!");
-    log_printf("Unknown effect type %d %d\n", devno, type); 
-    return;
-  }
-  if(!al_is_haptic_effect_ok(haptic->haptic, &haptic->effect)) {
-    message_label.set_text("Effect Not Supported!");
-    log_printf("Playing of effect type %s on %s not supported\n", cap_to_name(type), haptic->name); 
-    return;
-  }
-  
-  haptic->playing = al_upload_and_play_haptic_effect(haptic->haptic, &haptic->effect, 
-                                                     loops, &haptic->id);
-  if(haptic->playing) { 
-    message_label.set_text("Playing...");
-    log_printf("Started playing effect type %s on %s\n", cap_to_name(type), haptic->name); 
-    last_haptic = haptic;
-  } else {
-    message_label.set_text("Playing of effect failed!");
-    log_printf("Playing of effect type %s on %s failed\n", cap_to_name(type), haptic->name); 
-  }
-  play_button.set_disabled(true);
-  
+void Prog::get_envelope(ALLEGRO_HAPTIC_ENVELOPE * envelope)
+{
+   if (!envelope)
+      return;
+   envelope->attack_length = slider_to_duration(attack_length_slider);
+   envelope->fade_length = slider_to_duration(fade_length_slider);
+   envelope->attack_level = slider_to_magnitude(attack_level_slider);
+   envelope->fade_level = slider_to_magnitude(fade_level_slider);
 }
 
-void Prog::on_stop() {
-  int devno = device_list.get_cur_value();
-  if ((devno < 0) || (devno >= num_haptics)) {
-    log_printf("No such device %d\n", devno); 
-    return;
-  }  
-  Haptic * haptic = haptics + devno;
-  if (haptic->playing && al_is_haptic_effect_playing(&haptic->id)) { 
-    al_stop_haptic_effect(&haptic->id);
-    haptic->playing = false;
-    al_release_haptic_effect(&haptic->id);
-    log_printf("Stopped device %d: %s\n", devno, haptic->name);
-  }
-  message_label.set_text("Stopped.");
-  play_button.set_disabled(false);
+void Prog::on_play()
+{
+   int devno = device_list.get_cur_value();
+   if ((devno < 0) || (devno >= num_haptics)) {
+      message_label.set_text("No Haptic Device!");
+      log_printf("No such device: %d\n", devno);
+      return;
+   }
+   Haptic *haptic = haptics + devno;
+
+   if (!haptic || !haptic->haptic) {
+      log_printf("Device is NULL: %d\n", devno);
+      message_label.set_text("Device Is NULL!");
+      return;
+   }
+
+   if (!al_get_haptic_active(haptic->haptic)) {
+      message_label.set_text("Device Not Active!");
+      log_printf("Device is not active: %d\n", devno);
+      return;
+   }
+
+   /* Stop playing previous effect. */
+   if (haptic->playing) {
+      al_stop_haptic_effect(&haptic->id);
+      haptic->playing = false;
+      al_release_haptic_effect(&haptic->id);
+   }
+
+   /* First set gain. */
+   double gain = slider_to_magnitude(gain_slider);
+   al_set_haptic_gain(haptic->haptic, gain);
+
+   /* Now fill in the effect struct. */
+   int type = cap_for_name(type_list.get_selected_item_text());
+   int wavetype = cap_for_name(waveform_list.get_selected_item_text());
+
+   if (type < 0) {
+      message_label.set_text("Unknown Effect Type!");
+      log_printf("Unknown effect type: %d on %s\n", type, haptic->name);
+      return;
+   }
+
+   if (wavetype < 0) {
+      message_label.set_text("Unknown Wave Form!");
+      log_printf("Unknown wave type: %d on %s\n", wavetype, haptic->name);
+      return;
+   }
+
+   haptic->effect.type = type;
+   haptic->effect.replay.delay = slider_to_duration(delay_slider);
+   haptic->effect.replay.length = slider_to_duration(length_slider);
+   int loops = loops_slider.get_cur_value();
+   haptic->effect.direction.angle = slider_to_angle(angle_slider);
+   haptic->effect.direction.radius = slider_to_magnitude(angle_slider);
+   haptic->effect.direction.azimuth = slider_to_angle(angle_slider);
+
+   switch (type) {
+      case ALLEGRO_HAPTIC_RUMBLE:
+         haptic->effect.data.rumble.strong_magnitude =
+             slider_to_magnitude(strong_magnitude_slider);
+         haptic->effect.data.rumble.weak_magnitude =
+             slider_to_magnitude(weak_magnitude_slider);
+         break;
+      case ALLEGRO_HAPTIC_PERIODIC:
+         get_envelope(&haptic->effect.data.periodic.envelope);
+         haptic->effect.data.periodic.waveform = wavetype;
+         haptic->effect.data.periodic.magnitude =
+             slider_to_magnitude(magnitude_slider);
+         haptic->effect.data.periodic.period =
+             slider_to_duration(period_slider);
+         haptic->effect.data.periodic.offset =
+             slider_to_duration(offset_slider);
+         haptic->effect.data.periodic.phase = slider_to_duration(phase_slider);
+         haptic->effect.data.periodic.custom_len = 0;
+         haptic->effect.data.periodic.custom_data = NULL;
+         break;
+      case ALLEGRO_HAPTIC_CONSTANT:
+         get_envelope(&haptic->effect.data.constant.envelope);
+         haptic->effect.data.constant.level = slider_to_magnitude(level_slider);
+         break;
+      case ALLEGRO_HAPTIC_RAMP:
+         get_envelope(&haptic->effect.data.ramp.envelope);
+         haptic->effect.data.ramp.start_level =
+             slider_to_magnitude(start_level_slider);
+         haptic->effect.data.ramp.end_level =
+             slider_to_magnitude(end_level_slider);
+         break;
+
+      case ALLEGRO_HAPTIC_SPRING:
+      case ALLEGRO_HAPTIC_FRICTION:
+      case ALLEGRO_HAPTIC_DAMPER:
+      case ALLEGRO_HAPTIC_INERTIA:     /* fall through. */
+         haptic->effect.data.condition.right_saturation =
+             slider_to_magnitude(right_saturation_slider);
+         haptic->effect.data.condition.left_saturation =
+             slider_to_magnitude(left_saturation_slider);
+         haptic->effect.data.condition.right_coeff =
+             slider_to_magnitude(right_coeff_slider);
+         haptic->effect.data.condition.left_coeff =
+             slider_to_magnitude(left_coeff_slider);
+         haptic->effect.data.condition.deadband =
+             slider_to_magnitude(deadband_slider);
+         haptic->effect.data.condition.center =
+             slider_to_magnitude(center_slider);
+         /* XXX, need a different conversion function here, but  I don't have a 
+          * controller that supports condition effects anyway... :p
+          */
+         break;
+      default:
+         message_label.set_text("Unknown Effect Type!");
+         log_printf("Unknown effect type %d %d\n", devno, type);
+         return;
+   }
+   if (!al_is_haptic_effect_ok(haptic->haptic, &haptic->effect)) {
+      message_label.set_text("Effect Not Supported!");
+      log_printf("Playing of effect type %s on %s not supported\n",
+                 cap_to_name(type), haptic->name);
+      return;
+   }
+
+   haptic->playing =
+       al_upload_and_play_haptic_effect(haptic->haptic, &haptic->effect, loops,
+                                        &haptic->id);
+   if (haptic->playing) {
+      message_label.set_text("Playing...");
+      log_printf("Started playing effect type %s on %s\n", cap_to_name(type),
+                 haptic->name);
+      last_haptic = haptic;
+   }
+   else {
+      message_label.set_text("Playing of effect failed!");
+      log_printf("Playing of effect type %s on %s failed\n", cap_to_name(type),
+                 haptic->name);
+   }
+   play_button.set_disabled(true);
+
+}
+
+void Prog::on_stop()
+{
+   int devno = device_list.get_cur_value();
+   if ((devno < 0) || (devno >= num_haptics)) {
+      log_printf("No such device %d\n", devno);
+      return;
+   }
+   Haptic *haptic = haptics + devno;
+   if (haptic->playing && al_is_haptic_effect_playing(&haptic->id)) {
+      al_stop_haptic_effect(&haptic->id);
+      haptic->playing = false;
+      al_release_haptic_effect(&haptic->id);
+      log_printf("Stopped device %d: %s\n", devno, haptic->name);
+   }
+   message_label.set_text("Stopped.");
+   play_button.set_disabled(false);
 }
 
 
@@ -724,45 +731,46 @@ int main(int argc, char *argv[])
    al_init_font_addon();
    al_init_image_addon();
    al_init_ttf_addon();
- 
+
    al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS);
    display = al_create_display(800, 600);
    if (!display) {
       abort_example("Unable to create display\n");
    }
-   
+
    open_log();
-     
+
    font = al_load_font("data/DejaVuSans.ttf", 11, 0);
    if (!font) {
       log_printf("Failed to load data/DejaVuSans.ttf\n");
       font = al_create_builtin_font();
       if (!font) {
-        abort_example("Could not create builtin font.\n");
+         abort_example("Could not create builtin font.\n");
       }
    }
-   
+
    num_haptics = 0;
-   
-   if(al_is_display_haptic(al_get_current_display())) {
-     haptics[num_haptics].haptic  = al_get_haptic_from_display(al_get_current_display());
-     if(haptics[num_haptics].haptic) { 
-        haptics[num_haptics].name    = (const char *)"display";
-        haptics[num_haptics].playing = false;
-        num_haptics++;
-     }
-   }
-   
-   for (int i = 0; i < al_get_num_joysticks(); i++) { 
-    ALLEGRO_JOYSTICK * joy = al_get_joystick(i);
-    if(al_is_joystick_haptic(joy)) {
-      haptics[num_haptics].haptic  = al_get_haptic_from_joystick(joy);
-      if(haptics[num_haptics].haptic) { 
-         haptics[num_haptics].name    = (const char *)al_get_joystick_name(joy);
+
+   if (al_is_display_haptic(al_get_current_display())) {
+      haptics[num_haptics].haptic =
+          al_get_haptic_from_display(al_get_current_display());
+      if (haptics[num_haptics].haptic) {
+         haptics[num_haptics].name = (const char *)"display";
          haptics[num_haptics].playing = false;
          num_haptics++;
       }
-    }
+   }
+
+   for (int i = 0; i < al_get_num_joysticks(); i++) {
+      ALLEGRO_JOYSTICK *joy = al_get_joystick(i);
+      if (al_is_joystick_haptic(joy)) {
+         haptics[num_haptics].haptic = al_get_haptic_from_joystick(joy);
+         if (haptics[num_haptics].haptic) {
+            haptics[num_haptics].name = (const char *)al_get_joystick_name(joy);
+            haptics[num_haptics].playing = false;
+            num_haptics++;
+         }
+      }
    }
 
    /* Don't remove these braces. */
@@ -771,11 +779,11 @@ int main(int argc, char *argv[])
       Prog prog(theme, display);
       prog.run();
    }
-   
-   for (int i = 0; i < num_haptics; i++) { 
-      al_release_haptic(haptics[i].haptic); 
+
+   for (int i = 0; i < num_haptics; i++) {
+      al_release_haptic(haptics[i].haptic);
    }
-   
+
    close_log(false);
 
    al_destroy_font(font);
-- 
1.7.10.4



Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/