~ubuntu-branches/ubuntu/precise/widelands/precise-backports

« back to all changes in this revision

Viewing changes to src/ui/ui_basic/ui_listselect.cc

  • Committer: Bazaar Package Importer
  • Author(s): Martin Quinson
  • Date: 2005-02-14 10:41:12 UTC
  • Revision ID: james.westby@ubuntu.com-20050214104112-6v08iux9fptxpva9
Tags: upstream-build9
Import upstream version build9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2002 by the Widelands Development Team
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License
 
6
 * as published by the Free Software Foundation; either version 2
 
7
 * of the License, or (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
17
 *
 
18
 */
 
19
 
 
20
#include "constants.h"
 
21
#include "graphic.h"
 
22
#include "rendertarget.h"
 
23
#include "system.h"
 
24
#include "types.h"
 
25
#include "ui_listselect.h"
 
26
#include "ui_scrollbar.h"
 
27
 
 
28
/**
 
29
Initialize a list select panel
 
30
 
 
31
Args: parent    parent panel
 
32
      x         coordinates of the UIListselect
 
33
      y
 
34
      w         dimensions, in pixels, of the UIListselect
 
35
      h
 
36
      align     alignment of text inside the UIListselect
 
37
*/
 
38
UIListselect::UIListselect(UIPanel *parent, int x, int y, uint w, uint h, Align align, bool show_check)
 
39
        : UIPanel(parent, x, y, w, h)
 
40
{
 
41
        set_think(false);
 
42
 
 
43
        set_align(align);
 
44
 
 
45
        m_scrollpos = 0;
 
46
        m_selection = -1;
 
47
 
 
48
        m_scrollbar = new UIScrollbar(parent, x+get_w()-24, y, 24, h, false);
 
49
        m_scrollbar->moved.set(this, &UIListselect::set_scrollpos);
 
50
 
 
51
        m_scrollbar->set_pagesize(h - 2*g_fh->get_fontheight(UI_FONT_SMALL));
 
52
        m_scrollbar->set_steps(1);
 
53
 
 
54
   m_lineheight=g_fh->get_fontheight(UI_FONT_SMALL); 
 
55
 
 
56
   m_last_click_time=-10000;
 
57
   m_last_selection=-1;
 
58
        
 
59
        m_show_check = show_check;
 
60
        if (show_check) {
 
61
                int pic_h;
 
62
                m_check_picid = g_gr->get_picture(PicMod_Game, "pics/list_selected.png", true);
 
63
                g_gr->get_picture_size(m_check_picid, &m_max_pic_width, &pic_h);
 
64
                if (pic_h > m_lineheight)
 
65
                        m_lineheight = pic_h;
 
66
        }
 
67
        else {
 
68
                m_max_pic_width=0;
 
69
        }
 
70
                
 
71
}
 
72
 
 
73
 
 
74
/**
 
75
Free allocated resources
 
76
*/
 
77
UIListselect::~UIListselect()
 
78
{
 
79
        m_scrollbar = 0;
 
80
   clear();
 
81
}
 
82
 
 
83
 
 
84
/**
 
85
Remove all entries from the listselect
 
86
*/
 
87
void UIListselect::clear()
 
88
{
 
89
        for(uint i = 0; i < m_entries.size(); i++)
 
90
                free(m_entries[i]);
 
91
        m_entries.clear();
 
92
 
 
93
        if (m_scrollbar)
 
94
                m_scrollbar->set_steps(1);
 
95
        m_scrollpos = 0;
 
96
        m_selection = -1;
 
97
        m_last_click_time = -10000; 
 
98
   m_last_selection = -1;
 
99
}
 
100
 
 
101
 
 
102
/**
 
103
Add a new entry to the listselect.
 
104
 
 
105
Args: name      name that will be displayed
 
106
      value     value returned by get_select()
 
107
      select if true, directly select the new entry
 
108
*/
 
109
void UIListselect::add_entry(const char *name, void* value, bool select, int picid)
 
110
{
 
111
        Entry *e = (Entry *)malloc(sizeof(Entry) + strlen(name));
 
112
 
 
113
        e->value = value;
 
114
   e->picid = picid;
 
115
        strcpy(e->name, name);
 
116
 
 
117
   int entry_height=0;
 
118
   if(picid==-1) {
 
119
      entry_height=g_fh->get_fontheight(UI_FONT_SMALL);
 
120
   } else {
 
121
      int w,h;
 
122
      g_gr->get_picture_size(picid, &w, &h);
 
123
      entry_height= (h >= g_fh->get_fontheight(UI_FONT_SMALL)) ? h : g_fh->get_fontheight(UI_FONT_SMALL);  
 
124
      if(m_max_pic_width<w) m_max_pic_width=w;
 
125
   }
 
126
   if(entry_height>m_lineheight) m_lineheight=entry_height;
 
127
 
 
128
   m_entries.push_back(e);
 
129
 
 
130
        m_scrollbar->set_steps(m_entries.size() * get_lineheight() - get_h());
 
131
 
 
132
        update(0, 0, get_eff_w(), get_h());
 
133
   if(select) {
 
134
      m_selection=m_entries.size()-1;
 
135
                if (m_show_check)
 
136
                        m_entries[m_selection]->picid = m_check_picid;
 
137
        }
 
138
}
 
139
 
 
140
 
 
141
/*
 
142
 * Sort the listbox alphabetically. make sure that the current selection stays
 
143
 * valid (though it might scroll out of visibility). 
 
144
 * start and end defines the beginning and the end of a subarea to 
 
145
 * sort, for example you might want to sort directorys for themselves at the
 
146
 * top of list and files at the bottom.
 
147
 */
 
148
void UIListselect::sort(int gstart, int gend) {
 
149
   uint start=gstart; 
 
150
   uint stop=gend;
 
151
   if(gstart==-1) start=0;
 
152
   if(gend==-1) stop=m_entries.size();
 
153
   
 
154
   Entry *ei, *ej;
 
155
   for(uint i=start; i<stop; i++)
 
156
      for(uint j=i; j<stop; j++) {
 
157
         ei=m_entries[i];
 
158
         ej=m_entries[j];
 
159
         if(strcmp(ei->name, ej->name) > 0)  {
 
160
            if(m_selection==((int)i))
 
161
               m_selection=j;
 
162
            else if(m_selection==((int)j))
 
163
               m_selection=i;
 
164
            m_entries[i]=ej;
 
165
            m_entries[j]=ei;
 
166
         }
 
167
      }
 
168
}
 
169
 
 
170
/**
 
171
Set the list alignment (only horizontal alignment works)
 
172
*/
 
173
void UIListselect::set_align(Align align)
 
174
{
 
175
        m_align = (Align)(align & Align_Horizontal);
 
176
}
 
177
 
 
178
 
 
179
/**
 
180
Scroll to the given position, in pixels.
 
181
*/
 
182
void UIListselect::set_scrollpos(int i)
 
183
{
 
184
        m_scrollpos = i;
 
185
 
 
186
        update(0, 0, get_eff_w(), get_h());
 
187
}
 
188
 
 
189
 
 
190
/**
 
191
 *
 
192
 * Change the currently selected entry
 
193
 *
 
194
 * Args: i      the entry to select
 
195
 */
 
196
void UIListselect::select(int i)
 
197
{
 
198
        if (m_selection == i)
 
199
                return;
 
200
        
 
201
        if (m_show_check) {
 
202
                if (m_selection != -1)
 
203
                        m_entries[m_selection]->picid = -1;
 
204
                m_entries[i]->picid = m_check_picid;
 
205
        }
 
206
        m_selection = i;
 
207
 
 
208
        selected.call(m_selection);
 
209
        update(0, 0, get_eff_w(), get_h());
 
210
}
 
211
 
 
212
 
 
213
/**
 
214
Return the total height (text + spacing) occupied by a single line
 
215
*/
 
216
int UIListselect::get_lineheight()
 
217
{
 
218
        return m_lineheight+2; 
 
219
}
 
220
 
 
221
 
 
222
/**
 
223
Redraw the listselect box
 
224
*/
 
225
void UIListselect::draw(RenderTarget* dst)
 
226
{
 
227
        // draw text lines
 
228
        int lineheight = get_lineheight();
 
229
        int idx = m_scrollpos / lineheight;
 
230
        int y = 1 + idx*lineheight - m_scrollpos;
 
231
 
 
232
   dst->brighten_rect(0,0,get_w(),get_h(),ms_darken_value);
 
233
 
 
234
        while(idx < (int)m_entries.size())
 
235
                {
 
236
                if (y >= get_h())
 
237
                        return;
 
238
 
 
239
                Entry* e = m_entries[idx];
 
240
 
 
241
                if (idx == m_selection) {
 
242
                        // dst->fill_rect(1, y, get_eff_w()-2, g_font->get_fontheight(), m_selcolor);
 
243
                        dst->brighten_rect(1, y, get_eff_w()-2, m_lineheight, -ms_darken_value);
 
244
      }
 
245
 
 
246
                int x;
 
247
                if (m_align & Align_Right)
 
248
                        x = get_eff_w() - 1;
 
249
                else if (m_align & Align_HCenter)
 
250
                        x = get_eff_w()>>1;
 
251
                else {
 
252
         // Pictures are always left aligned, leave some space here
 
253
                        if(m_max_pic_width)
 
254
            x= m_max_pic_width + 10;
 
255
         else 
 
256
            x=1;
 
257
      }
 
258
 
 
259
      // Horizontal center the string
 
260
                g_fh->draw_string(dst, UI_FONT_SMALL, UI_FONT_SMALL_CLR, x, y + (get_lineheight()-g_fh->get_fontheight(UI_FONT_SMALL))/2, e->name, m_align, -1);
 
261
 
 
262
      // Now draw pictures
 
263
      if(e->picid!=-1) {
 
264
         int w,h;
 
265
         g_gr->get_picture_size(e->picid, &w, &h);
 
266
         dst->blit(1, y + (get_lineheight()-h)/2, e->picid);
 
267
      }
 
268
                y += lineheight;
 
269
                idx++;
 
270
        }
 
271
}
 
272
 
 
273
 
 
274
/**
 
275
 * Handle mouse clicks: select the appropriate entry
 
276
 */
 
277
bool UIListselect::handle_mouseclick(uint btn, bool down, int x, int y)
 
278
{
 
279
   
 
280
        if (btn != 0) // only left-click
 
281
                return false;
 
282
 
 
283
   if (down) {
 
284
      int time=Sys_GetTime();
 
285
 
 
286
      // This hick hack is needed if any of the 
 
287
      // callback functions calls clear to forget the last
 
288
      // clicked time.
 
289
      int real_last_click_time=m_last_click_time; 
 
290
      
 
291
      m_last_selection=m_selection;
 
292
      m_last_click_time=time;
 
293
 
 
294
      y = (y + m_scrollpos) / get_lineheight();
 
295
      if (y >= 0 && y < (int)m_entries.size())
 
296
         select(y);
 
297
     
 
298
      // check if doubleclicked
 
299
      if(time-real_last_click_time < DOUBLE_CLICK_INTERVAL && m_last_selection==m_selection && m_selection!=-1) 
 
300
         double_clicked.call(m_selection);
 
301
 
 
302
   }
 
303
 
 
304
        return true;
 
305
}
 
306
 
 
307
/*
 
308
 * Remove entry
 
309
 */
 
310
void UIListselect::remove_entry(int i) {
 
311
   if(i<0 || ((uint)i)>=m_entries.size()) return;
 
312
 
 
313
   free(m_entries[i]);
 
314
   m_entries.erase(m_entries.begin() + i);
 
315
   if(m_selection==i)
 
316
      m_selection=-1;
 
317
}
 
318
 
 
319
/*
 
320
 * Remove an entry by name. This only removes
 
321
 * the first entry with this name. If none is found, nothing
 
322
 * is done
 
323
 */
 
324
void UIListselect::remove_entry(const char *str ) {
 
325
   for(uint i=0; i<m_entries.size(); i++) {
 
326
      if(!strcmp(m_entries[i]->name,str)) {
 
327
         remove_entry(i);
 
328
         return;
 
329
      }
 
330
   }
 
331
}