1 /******************************************************************************
2  *  Warmux is a convivial mass murder game.
3  *  Copyright (C) 2001-2011 Warmux Team.
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18  *****************************************************************************/
19 
20 #include <vector>
21 #include <sstream>
22 #include "graphic/polygon_generator.h"
23 #include "graphic/sprite.h"
24 #include "graphic/text.h"
25 #include "graphic/video.h"
26 #include "gui/combo_box.h"
27 #include "gui/torus_cache.h"
28 #include "include/app.h"
29 #include "tool/affine_transform.h"
30 #include "tool/math_tools.h"
31 #include "tool/resource_manager.h"
32 
33 #define SMALL_R 25
34 #define BIG_R   35
35 #define OPEN_ANGLE 0.96f // 55
36 
ComboBox(const std::string & label,const std::string & resource_id,const Point2i & _size,const std::vector<std::pair<std::string,std::string>> & choices,const std::string choice)37 ComboBox::ComboBox (const std::string &label,
38                     const std::string &resource_id,
39                     const Point2i &_size,
40                     const std::vector<std::pair<std::string, std::string> > &choices,
41                     const std::string choice)
42   : m_choices(choices)
43   , m_index(0)
44 {
45   position = Point2i(-1, -1);
46   size = _size;
47 
48   Profile *res = GetResourceManager().LoadXMLProfile("graphism.xml", false);
49   torus = new TorusCache(res, resource_id, BIG_R, SMALL_R);
50 
51   txt_label = new Text(label, dark_gray_color, Font::FONT_SMALL, Font::FONT_BOLD, false);
52   txt_label->SetMaxWidth(GetSizeX());
53 
54   txt_value_black = new Text("", black_color, Font::FONT_MEDIUM, Font::FONT_BOLD, false);
55   txt_value_white = new Text("", white_color, Font::FONT_MEDIUM, Font::FONT_BOLD, false);
56 
57   std::vector<std::string>::size_type index = 0;
58   for (std::vector<std::pair<std::string, std::string> >::const_iterator iter
59        = choices.begin ();
60        iter != choices.end ();
61        iter++) {
62 
63     if (iter->first == choice)
64       m_index = index;
65     index++;
66   }
67 
68   SetChoice(m_index);
69 }
70 
~ComboBox()71 ComboBox::~ComboBox ()
72 {
73   delete txt_label;
74   delete txt_value_black;
75   delete txt_value_white;
76   delete torus;
77 }
78 
Pack()79 void ComboBox::Pack()
80 {
81   txt_label->SetMaxWidth(size.x);
82 }
83 
Draw(const Point2i & mousePosition)84 void ComboBox::Draw(const Point2i &mousePosition)
85 {
86   Surface& window = GetMainWindow();
87 
88   //  the computed positions are to center on the image part of the widget
89 
90   // 1. first draw the torus
91   torus->Draw(*this);
92 
93 
94   // 2. then draw buttons
95   #define IMG_BUTTONS_W 5
96   #define IMG_BUTTONS_H 12
97 
98   Point2i center = GetPosition() + torus->GetCenter();
99   if (m_index > 0) {
100 
101     if (Contains(mousePosition) && mousePosition.x < center.x)
102       torus->m_minus->SetCurrentFrame(1);
103     else
104       torus->m_minus->SetCurrentFrame(0);
105 
106     torus->m_minus->Blit(window, GetPositionX() + IMG_BUTTONS_W, GetPositionY() + IMG_BUTTONS_H);
107   }
108 
109   if (m_index < m_choices.size() - 1) {
110     if (Contains(mousePosition) && mousePosition.x > center.x)
111       torus->m_plus->SetCurrentFrame(1);
112     else
113       torus->m_plus->SetCurrentFrame(0);
114 
115     torus->m_plus->Blit(window, GetPositionX() + GetSizeX() - torus->m_plus->GetWidth() - IMG_BUTTONS_W,
116                         GetPosition().y + IMG_BUTTONS_H);
117   }
118 
119   // 3. add in the value image
120   uint tmp_x = GetPositionX() + GetSizeX()/2;
121   uint tmp_y = center.y + SMALL_R - 3;
122   uint value_h = Font::GetInstance(Font::FONT_MEDIUM)->GetHeight();
123 
124   txt_value_black->DrawCenterTop(Point2i(tmp_x + 1, tmp_y + 1 - value_h/2));
125   txt_value_white->DrawCenterTop(Point2i(tmp_x, tmp_y - value_h/2));
126 
127   // 7. and finally the label image
128   txt_label->DrawCenterTop(Point2i(tmp_x, GetPositionY() + GetSizeY() - txt_label->GetHeight()));
129 }
130 
ClickUp(const Point2i & mousePosition,uint button)131 Widget* ComboBox::ClickUp(const Point2i &mousePosition, uint button)
132 {
133   NeedRedrawing();
134 
135   bool is_click = Mouse::IS_CLICK_BUTTON(button);
136   if ( (is_click && mousePosition.x > (GetPositionX() + GetSizeX()/2))
137        || button == SDL_BUTTON_WHEELUP ) {
138     SetChoice(m_index + 1);
139     return this;
140   } else if ( (is_click && mousePosition.x <= (GetPositionX() + GetSizeX()/2))
141               || button == SDL_BUTTON_WHEELDOWN ) {
142     SetChoice(m_index - 1);
143     return this;
144   }
145 
146   return NULL;
147 }
148 
SetChoice(std::vector<std::string>::size_type index)149 void ComboBox::SetChoice(std::vector<std::string>::size_type index)
150 {
151   std::string text;
152 
153   if (index >= m_choices.size ())
154     return; /* index = 0; // loop back */
155 
156   m_index = index;
157 
158   txt_value_black->SetText(m_choices[m_index].second);
159   txt_value_white->SetText(m_choices[m_index].second);
160 
161   RecreateTorus();
162   NeedRedrawing();
163 }
164 
GetIntValue() const165 int ComboBox::GetIntValue() const
166 {
167   int tmp = 0;
168   sscanf(GetValue().c_str(),"%d", &tmp);
169   return tmp;
170 }
171 
RecreateTorus()172 void ComboBox::RecreateTorus()
173 {
174   float angle;
175   if (m_choices.size () > 1)
176     angle = m_index*(2.0f*M_PI - OPEN_ANGLE) / (m_choices.size () - 1);
177   else
178     angle = 0;
179   torus->Refresh(angle, OPEN_ANGLE);
180 }
181