- Trampoline test level
[supertux.git] / src / button.cpp
index 9380158..8bb8e50 100644 (file)
@@ -1,14 +1,22 @@
+//  $Id$
 //
-// C Implementation: button
+//  SuperTux
+//  Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
 //
-// Description:
-//
-//
-// Author: Tobias Glaesser <tobi.web@gmx.de>, (C) 2004
-//
-// Copyright: See COPYING file that comes with this distribution
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
 //
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
 //
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+//  02111-1307, USA.
 
 #include <string.h>
 #include <stdlib.h>
 #include "globals.h"
 #include "button.h"
 
-void button_load(button_type* pbutton,char* icon_file, char* info, SDLKey shortcut, int x, int y)
+Timer Button::popup_timer;
+
+Button::Button(std::string icon_file, std::string ninfo, SDLKey nshortcut, int x, int y, int mw, int mh)
 {
-  char filename[1024];
+  popup_timer.init(false);
 
-  if(icon_file != NULL)
-    {
-      snprintf(filename, 1024, "%s/%s", datadir.c_str(), icon_file);
-      if(!faccessible(filename))
-        snprintf(filename, 1024, "%s/images/icons/default-icon.png", datadir.c_str());
-    }
-  else
-    {
-      snprintf(filename, 1024, "%s/images/icons/default-icon.png", datadir.c_str());
-    }
-  texture_load(&pbutton->icon,filename,USE_ALPHA);
+  add_icon(icon_file,mw,mh);
 
-  if(info == NULL)
-    {
-      pbutton->info = NULL;
-    }
-  else
-    {
-      pbutton->info = (char*) malloc(sizeof(char)*(strlen(info) + 1));
-      strcpy(pbutton->info,info);
-    }
+  info = ninfo;
 
-  pbutton->shortcut = shortcut;
+  shortcut = nshortcut;
 
-  pbutton->x = x;
-  pbutton->y = y;
-  pbutton->w = pbutton->icon.w;
-  pbutton->h = pbutton->icon.h;
-  pbutton->tag = -1;
-  pbutton->state = BUTTON_NONE;
-  pbutton->show_info = NO;
-  pbutton->bkgd = NULL;
+  rect.x = x;
+  rect.y = y;
+  rect.w = icon[0]->w;
+  rect.h = icon[0]->h;
+  tag = -1;
+  state = BUTTON_NONE;
+  show_info = false;
+  game_object = NULL;
 }
 
-void button_change_icon(button_type* pbutton,char* icon_file)
+void Button::add_icon(std::string icon_file, int mw, int mh)
 {
   char filename[1024];
 
-  if(icon_file != NULL)
-    {
-      snprintf(filename, 1024, "%s/%s", datadir.c_str(), icon_file);
-      if(!faccessible(filename))
-        snprintf(filename, 1024, "%s/images/icons/default-icon.png", datadir.c_str());
-    }
-  else
-    {
+  if(!icon_file.empty())
+  {
+    snprintf(filename, 1024, "%s/%s", datadir.c_str(), icon_file.c_str());
+    if(!faccessible(filename))
       snprintf(filename, 1024, "%s/images/icons/default-icon.png", datadir.c_str());
-    }
-  
-  texture_free(&pbutton->icon);
-  texture_load(&pbutton->icon,filename,USE_ALPHA);
-}
+  }
+  else
+  {
+    snprintf(filename, 1024, "%s/images/icons/default-icon.png", datadir.c_str());
+  }
+
+  if(mw != -1 || mh != -1)
+  {
+    icon.push_back(new Surface(filename,USE_ALPHA));
+    icon.back()->resize(mw,mh);
+  }
+  else
+    icon.push_back(new Surface(filename,USE_ALPHA));
 
-button_type* button_create(char* icon_file, char* info, SDLKey shortcut, int x, int y)
-{
-  button_type* pnew_button = (button_type*) malloc(sizeof(button_type));
-  button_load(pnew_button,icon_file, info, shortcut, x, y);
-  return pnew_button;
 }
 
-void button_draw(button_type* pbutton)
+void Button::draw()
 {
-  fillrect(pbutton->x,pbutton->y,pbutton->w,pbutton->h,75,75,75,200);
-  fillrect(pbutton->x+1,pbutton->y+1,pbutton->w-2,pbutton->h-2,175,175,175,200);
-  if(pbutton->bkgd != NULL)
+  if(state == BUTTON_HOVER)
+    if(!popup_timer.check())
+      show_info = true;
+
+  fillrect(rect.x,rect.y,rect.w,rect.h,75,75,75,200);
+  fillrect(rect.x+1,rect.y+1,rect.w-2,rect.h-2,175,175,175,200);
+
+  for(std::vector<Surface*>::iterator it = icon.begin(); it != icon.end(); ++it)
+    (*it)->draw(rect.x,rect.y);
+
+  if(game_object != NULL)
   {
-  texture_draw(pbutton->bkgd,pbutton->x,pbutton->y,NO_UPDATE);
+    game_object->draw_on_screen(rect.x,rect.y);
   }
-  texture_draw(&pbutton->icon,pbutton->x,pbutton->y,NO_UPDATE);
-  if(pbutton->show_info == YES)
-    {
-      char str[80];
-      int i = -32;
 
-      if(0 > pbutton->x - (int)strlen(pbutton->info) * white_small_text.w)
-        i = pbutton->w + strlen(pbutton->info) * white_small_text.w;
+  if(show_info)
+  {
+    char str[80];
+    int i = -32;
 
-      if(pbutton->info)
-        text_draw(&white_small_text, pbutton->info, i + pbutton->x - strlen(pbutton->info) * white_small_text.w, pbutton->y, 1, NO_UPDATE);
-      sprintf(str,"(%s)", SDL_GetKeyName(pbutton->shortcut));
-      text_draw(&white_small_text, str, i + pbutton->x - strlen(str) * white_small_text.w, pbutton->y + white_small_text.h+2, 1, NO_UPDATE);
-    }
-  if(pbutton->state == BUTTON_PRESSED)
-    fillrect(pbutton->x,pbutton->y,pbutton->w,pbutton->h,75,75,75,200);
-  else if(pbutton->state == BUTTON_HOVER)
-    fillrect(pbutton->x,pbutton->y,pbutton->w,pbutton->h,150,150,150,128);
+    if(0 > rect.x - (int)strlen(info.c_str()) * white_small_text->w)
+      i = rect.w + strlen(info.c_str()) * white_small_text->w;
+
+    if(!info.empty())
+      white_small_text->draw(info.c_str(), i + rect.x - strlen(info.c_str()) * white_small_text->w, rect.y, 1);
+    sprintf(str,"(%s)", SDL_GetKeyName(shortcut));
+    white_small_text->draw(str, i + rect.x - strlen(str) * white_small_text->w, rect.y + white_small_text->h+2, 1);
+  }
+  if(state == BUTTON_PRESSED || state == BUTTON_DEACTIVE)
+    fillrect(rect.x,rect.y,rect.w,rect.h,75,75,75,200);
+  else if(state == BUTTON_HOVER)
+    fillrect(rect.x,rect.y,rect.w,rect.h,150,150,150,128);
 }
 
-void button_free(button_type* pbutton)
+Button::~Button()
 {
-  free(pbutton->info);
-  texture_free(&pbutton->icon);
+  for(std::vector<Surface*>::iterator it = icon.begin(); it != icon.end(); ++it)
+    delete (*it);
+  icon.clear();
+  delete game_object;
 }
 
-void button_event(button_type* pbutton, SDL_Event *event)
+void Button::event(SDL_Event &event)
 {
-  SDLKey key = event->key.keysym.sym;
+  if(state == BUTTON_DEACTIVE)
+    return;
+
+  SDLKey key = event.key.keysym.sym;
+
+  if(event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP)
+  {
+    if(event.button.x < rect.x || event.button.x >= rect.x + rect.w ||
+        event.button.y < rect.y || event.button.y >= rect.y + rect.h)
+      return;
 
-  if(event->motion.x > pbutton->x && event->motion.x < pbutton->x + pbutton->w &&
-      event->motion.y > pbutton->y && event->motion.y < pbutton->y + pbutton->h)
+    if(event.button.button == SDL_BUTTON_RIGHT)
     {
-      if(event->type == SDL_MOUSEBUTTONDOWN)
-        {
-          if(event->button.button == SDL_BUTTON_LEFT)
-            {
-              pbutton->state = BUTTON_PRESSED;
-            }
-          else
-            {
-              pbutton->show_info = YES;
-            }
-        }
-      else if(event->type == SDL_MOUSEBUTTONUP)
-        {
-          if(event->button.button == SDL_BUTTON_LEFT && pbutton->state == BUTTON_PRESSED)
-            {
-              pbutton->state = BUTTON_CLICKED;
-            }
-          else if(event->button.button != SDL_BUTTON_LEFT && pbutton->state != BUTTON_PRESSED)
-            {
-              pbutton->show_info = YES;
-            }
-        }
-
-      if(pbutton->state != BUTTON_PRESSED && pbutton->state != BUTTON_CLICKED)
-        {
-          pbutton->state = BUTTON_HOVER;
-        }
+      show_info = true;
+      return;
     }
-  else if(event->type != SDL_KEYDOWN && event->type != SDL_KEYUP)
+    else if(event.type == SDL_MOUSEBUTTONUP && event.button.button == 4) /* Mouse wheel up. */
     {
-      pbutton->state = BUTTON_NONE;
-      if(pbutton->show_info)
-        {
-          pbutton->show_info = NO;
-        }
+      state = BUTTON_WHEELUP;
+      return;
     }
-
-  if(event->type == SDL_KEYDOWN)
+    else if(event.type == SDL_MOUSEBUTTONUP && event.button.button == 5) /* Mouse wheel down. */
     {
-      if(key == pbutton->shortcut)
-        pbutton->state = BUTTON_PRESSED;
+      state = BUTTON_WHEELDOWN;
+      return;
     }
-  else if(event->type == SDL_KEYUP)
+
+    if(event.button.button == SDL_BUTTON_LEFT)
+      if(event.type == SDL_MOUSEBUTTONDOWN)
+        state = BUTTON_PRESSED;
+      else
+        state = BUTTON_CLICKED;
+  }
+  else if(event.type == SDL_MOUSEMOTION)
+  {
+    if(event.motion.x < rect.x || event.motion.x >= rect.x + rect.w ||
+        event.motion.y < rect.y || event.motion.y >= rect.y + rect.h)
     {
-      if(pbutton->state == BUTTON_PRESSED && key == pbutton->shortcut)
-        pbutton->state = BUTTON_CLICKED;
+      state = BUTTON_NONE;
     }
-  else if(event->type == SDL_MOUSEMOTION)
+    else
     {
+      state = BUTTON_HOVER;
+      popup_timer.start(1500);
+    }
 
-      if(pbutton->show_info)
-        {
-          pbutton->show_info = NO;
-        }
+    if(show_info)
+    {
+      show_info = false;
     }
+  }
+  else if(event.type == SDL_KEYDOWN)
+  {
+    if(key == shortcut)
+      state = BUTTON_PRESSED;
+  }
+  else if(event.type == SDL_KEYUP)
+  {
+    if(state == BUTTON_PRESSED && key == shortcut)
+      state = BUTTON_CLICKED;
+  }
 }
 
-int button_get_state(button_type* pbutton)
+int Button::get_state()
 {
-  int state;
-  if(pbutton->state == BUTTON_CLICKED)
-    {
-      state = pbutton->state;
-      pbutton->state = BUTTON_NONE;
-      return state;
-    }
-  else
-    {
-      return pbutton->state;
-    }
+  int rstate;
+  switch(state)
+  {
+  case BUTTON_CLICKED:
+  case BUTTON_WHEELUP:
+  case BUTTON_WHEELDOWN:
+    rstate = state;
+    state = BUTTON_NONE;
+    return rstate;
+  default:
+    return state;
+  }
 }
 
-void button_panel_init(button_panel_type* pbutton_panel, int x, int y, int w, int h)
+ButtonPanel::ButtonPanel(int x, int y, int w, int h)
 {
-  pbutton_panel->num_items = 0;
-  pbutton_panel->item = NULL;
-  pbutton_panel->x = x;
-  pbutton_panel->y = y;
-  pbutton_panel->w = w;
-  pbutton_panel->h = h;
-  pbutton_panel->hidden = NO;
+  bw = 32;
+  bh = 32;
+  rect.x = x;
+  rect.y = y;
+  rect.w = w;
+  rect.h = h;
+  hidden = false;
+  hlast = false;
 }
 
-button_type* button_panel_event(button_panel_type* pbutton_panel, SDL_Event* event)
+Button* ButtonPanel::event(SDL_Event& event)
 {
-  if(pbutton_panel->hidden == NO)
+  if(!hidden)
+  {
+  Button* ret = NULL;
+    for(std::vector<Button*>::iterator it = item.begin(); it != item.end(); ++it)
     {
-      int i;
-      for(i = 0; i < pbutton_panel->num_items; ++i)
-        {
-          button_event(&pbutton_panel->item[i],event);
-          if(pbutton_panel->item[i].state != -1)
-            return &pbutton_panel->item[i];
-        }
-      return NULL;
+      (*it)->event(event);
+      if((*it)->state != BUTTON_NONE)
+      {
+        if(hlast && (*it)->state == BUTTON_CLICKED)
+          last_clicked = it;
+       ret = (*it);
+      }
     }
+    return ret;
+  }
   else
-    {
-      return NULL;
-    }
+  {
+    return NULL;
+  }
 }
 
-void button_panel_free(button_panel_type* pbutton_panel)
+ButtonPanel::~ButtonPanel()
 {
-  int i;
-  for(i = 0; i < pbutton_panel->num_items; ++i)
-    {
-      button_free(&pbutton_panel->item[i]);
-    }
-  if(pbutton_panel->num_items)
-    free(pbutton_panel->item);
+  for(std::vector<Button*>::iterator it = item.begin(); it != item.end(); ++it)
+  {
+    delete (*it);
+  }
+  item.clear();
 }
 
-void button_panel_draw(button_panel_type* pbutton_panel)
+void ButtonPanel::draw()
 {
-  if(pbutton_panel->hidden == NO)
+
+  if(hidden == false)
+  {
+    fillrect(rect.x,rect.y,rect.w,rect.h,100,100,100,200);
+    for(std::vector<Button*>::iterator it = item.begin(); it != item.end(); ++it)
     {
-      int i;
-      fillrect(pbutton_panel->x,pbutton_panel->y,pbutton_panel->w,pbutton_panel->h,100,100,100,200);
-      for(i = 0; i < pbutton_panel->num_items; ++i)
-        {
-          button_draw(&pbutton_panel->item[i]);
-        }
+      (*it)->draw();
+      if(hlast && it == last_clicked)
+      {
+        fillrect((*it)->get_pos().x,(*it)->get_pos().y,(*it)->get_pos().w,(*it)->get_pos().h,100,100,100,128);
+      }
     }
+  }
 }
 
-void button_panel_additem(button_panel_type* pbutton_panel, button_type* pbutton, int tag)
+void ButtonPanel::additem(Button* pbutton, int tag)
 {
   int max_cols, row, col;
 
-  ++pbutton_panel->num_items;
-  pbutton_panel->item = (button_type*) realloc(pbutton_panel->item, sizeof(button_type) * pbutton_panel->num_items);
-  memcpy(&pbutton_panel->item[pbutton_panel->num_items-1],pbutton,sizeof(button_type));
-  free(pbutton);
+  item.push_back(pbutton);
 
   /* A button_panel takes control of the buttons it contains and arranges them */
 
-  max_cols = pbutton_panel->w / 32;
+  max_cols = rect.w / bw;
 
-  row = (pbutton_panel->num_items-1) / max_cols;
-  col = (pbutton_panel->num_items-1) % max_cols;
+  row = (item.size()-1) / max_cols;
+  col = (item.size()-1) % max_cols;
 
-  pbutton_panel->item[pbutton_panel->num_items-1].x = pbutton_panel->x + col * 32;
-  pbutton_panel->item[pbutton_panel->num_items-1].y = pbutton_panel->y + row * 32;
-  pbutton_panel->item[pbutton_panel->num_items-1].tag = tag;
+  item[item.size()-1]->rect.x = rect.x + col * bw;
+  item[item.size()-1]->rect.y = rect.y + row * bh;
+  item[item.size()-1]->tag = tag;
 
 }
 
+void ButtonPanel::set_button_size(int w, int h)
+{
+  bw = w;
+  bh = h;
+}
+
+Button* ButtonPanel::manipulate_button(int i)
+{
+  if(int(item.size())-1 < i)
+    return item[item.size()-1];
+  else
+    return item[i];
+}
+
+void ButtonPanel::highlight_last(bool b)
+{
+  hlast = b;
+}
+
+