Use field width of 9 on sscanf (fixes cppcheck portability issues)
[supertux.git] / src / gui / dialog.cpp
index 5d7b117..47b9a0c 100644 (file)
 
 #include "control/controller.hpp"
 #include "gui/menu_manager.hpp"
+#include "gui/menu.hpp"
+#include "gui/mousecursor.hpp"
 #include "supertux/resources.hpp"
+#include "supertux/colorscheme.hpp"
 #include "video/drawing_context.hpp"
+#include "video/renderer.hpp"
+#include "video/video_system.hpp"
 
 Dialog::Dialog() :
   m_text(),
   m_buttons(),
-  m_selected_button()
+  m_selected_button(),
+  m_cancel_button(-1),
+  m_text_size()
 {
 }
 
@@ -36,12 +43,103 @@ void
 Dialog::set_text(const std::string& text)
 {
   m_text = text;
+
+  m_text_size = Sizef(Resources::normal_font->get_text_width(m_text),
+                      Resources::normal_font->get_text_height(m_text));
+
+}
+
+void
+Dialog::clear_buttons()
+{
+  m_buttons.clear();
+  m_selected_button = 0;
+  m_cancel_button = -1;
+}
+
+void
+Dialog::add_default_button(const std::string& text, const std::function<void ()>& callback)
+{
+  add_button(text, callback);
+  m_selected_button = m_buttons.size() - 1;
+}
+
+void
+Dialog::add_cancel_button(const std::string& text, const std::function<void ()>& callback)
+{
+  add_button(text, callback);
+  m_cancel_button = m_buttons.size() - 1;
+}
+
+void
+Dialog::add_button(const std::string& text, const std::function<void ()>& callback)
+{
+  m_buttons.push_back({text, callback});
+}
+
+int
+Dialog::get_button_at(const Vector& mouse_pos) const
+{
+  Rectf bg_rect(Vector(SCREEN_WIDTH/2 - m_text_size.width/2,
+                       SCREEN_HEIGHT/2 - m_text_size.height/2),
+                Sizef(m_text_size.width,
+                      m_text_size.height + 44));
+
+  for(int i = 0; i < static_cast<int>(m_buttons.size()); ++i)
+  {
+    float segment_width = bg_rect.get_width() / m_buttons.size();
+    float button_width = segment_width;
+    float button_height = 24.0f;
+    Vector pos(bg_rect.p1.x + segment_width/2.0f + i * segment_width,
+               bg_rect.p2.y - 12);
+    Rectf button_rect(Vector(pos.x - button_width/2, pos.y - button_height/2),
+                      Vector(pos.x + button_width/2, pos.y + button_height/2));
+    if (button_rect.contains(mouse_pos))
+    {
+      return i;
+    }
+  }
+  return -1;
 }
 
 void
-Dialog::add_button(const std::string& text)
+Dialog::event(const SDL_Event& ev)
 {
-  m_buttons.push_back(text);
+  switch(ev.type) {
+    case SDL_MOUSEBUTTONDOWN:
+    if(ev.button.button == SDL_BUTTON_LEFT)
+    {
+      Vector mouse_pos = VideoSystem::current()->get_renderer().to_logical(ev.motion.x, ev.motion.y);
+      int new_button = get_button_at(mouse_pos);
+      if (new_button != -1)
+      {
+        m_selected_button = new_button;
+        on_button_click(m_selected_button);
+      }
+    }
+    break;
+
+    case SDL_MOUSEMOTION:
+    {
+      Vector mouse_pos = VideoSystem::current()->get_renderer().to_logical(ev.motion.x, ev.motion.y);
+      int new_button = get_button_at(mouse_pos);
+      if (new_button != -1)
+      {
+        m_selected_button = new_button;
+        if(MouseCursor::current())
+          MouseCursor::current()->set_state(MC_LINK);
+      }
+      else
+      {
+        if(MouseCursor::current())
+          MouseCursor::current()->set_state(MC_NORMAL);
+      }
+    }
+    break;
+
+    default:
+      break;
+  }
 }
 
 void
@@ -62,27 +160,24 @@ Dialog::process_input(const Controller& controller)
   if (controller.pressed(Controller::ACTION) ||
       controller.pressed(Controller::MENU_SELECT))
   {
-    on_select(m_selected_button);
+    on_button_click(m_selected_button);
+  }
 
-    // warning: this will "delete this"
-    MenuManager::instance().set_dialog({});
+  if (m_cancel_button != -1 &&
+      (controller.pressed(Controller::ESCAPE) ||
+       controller.pressed(Controller::MENU_BACK)))
+  {
+    on_button_click(m_cancel_button);
   }
 }
 
 void
 Dialog::draw(DrawingContext& ctx)
 {
-  Vector center(SCREEN_WIDTH/2, SCREEN_HEIGHT/2);
-
-  Sizef text_size(Resources::normal_font->get_text_width(m_text),
-                  Resources::normal_font->get_text_height(m_text));
-
-  Rectf text_rect(Vector(center.x - text_size.width/2,
-                         center.y - text_size.height/2),
-                  text_size);
-
-  Rectf bg_rect = text_rect;
-  bg_rect.p2.y += 44;
+  Rectf bg_rect(Vector(SCREEN_WIDTH/2 - m_text_size.width/2,
+                       SCREEN_HEIGHT/2 - m_text_size.height/2),
+                Sizef(m_text_size.width,
+                      m_text_size.height + 44));
 
   // draw background rect
   ctx.draw_filled_rect(bg_rect.grown(12.0f),
@@ -103,23 +198,23 @@ Dialog::draw(DrawingContext& ctx)
 
   // draw HL line
   ctx.draw_filled_rect(Vector(bg_rect.p1.x, bg_rect.p2.y - 35),
-                           Vector(bg_rect.get_width(), 4),
-                           Color(0.6f, 0.7f, 1.0f, 1.0f), LAYER_GUI);
+                       Vector(bg_rect.get_width(), 4),
+                       Color(0.6f, 0.7f, 1.0f, 1.0f), LAYER_GUI);
   ctx.draw_filled_rect(Vector(bg_rect.p1.x, bg_rect.p2.y - 35),
-                           Vector(bg_rect.get_width(), 2),
-                           Color(1.0f, 1.0f, 1.0f, 1.0f), LAYER_GUI);
+                       Vector(bg_rect.get_width(), 2),
+                       Color(1.0f, 1.0f, 1.0f, 1.0f), LAYER_GUI);
 
   // draw buttons
   for(int i = 0; i < static_cast<int>(m_buttons.size()); ++i)
   {
     float segment_width = bg_rect.get_width() / m_buttons.size();
-    float button_width = segment_width * 0.95;
-    float button_height = 24.0f;
+    float button_width = segment_width;
     Vector pos(bg_rect.p1.x + segment_width/2.0f + i * segment_width,
                bg_rect.p2.y - 12);
 
     if (i == m_selected_button)
     {
+      float button_height = 24.0f;
       float blink = (sinf(real_time * M_PI * 1.0f)/2.0f + 0.5f) * 0.5f + 0.25f;
       ctx.draw_filled_rect(Rectf(Vector(pos.x - button_width/2, pos.y - button_height/2),
                                  Vector(pos.x + button_width/2, pos.y + button_height/2)).grown(2.0f),
@@ -133,15 +228,21 @@ Dialog::draw(DrawingContext& ctx)
                            LAYER_GUI-10);
     }
 
-    ctx.draw_text(Resources::normal_font, m_buttons[i],
+    ctx.draw_text(Resources::normal_font, m_buttons[i].text,
                   Vector(pos.x, pos.y - int(Resources::normal_font->get_height()/2)),
-                  ALIGN_CENTER, LAYER_GUI);
+                  ALIGN_CENTER, LAYER_GUI,
+                  i == m_selected_button ? ColorScheme::Menu::active_color : ColorScheme::Menu::default_color);
   }
 }
 
 void
-Dialog::on_select(int id)
+Dialog::on_button_click(int button) const
 {
+  if (m_buttons[button].callback)
+  {
+    m_buttons[button].callback();
+  }
+  MenuManager::instance().set_dialog({});
 }
 
 /* EOF */