| 1 | /* |
|---|
| 2 | * Copyright (c) 2004-2006 Kazunori "jagarl" Ueno |
|---|
| 3 | * All rights reserved. |
|---|
| 4 | * |
|---|
| 5 | * Redistribution and use in source and binary forms, with or without |
|---|
| 6 | * modification, are permitted provided that the following conditions |
|---|
| 7 | * are met: |
|---|
| 8 | * 1. Redistributions of source code must retain the above copyright |
|---|
| 9 | * notice, this list of conditions and the following disclaimer. |
|---|
| 10 | * 2. Redistributions in binary form must reproduce the above copyright |
|---|
| 11 | * notice, this list of conditions and the following disclaimer in the |
|---|
| 12 | * documentation and/or other materials provided with the distribution. |
|---|
| 13 | * 3. The name of the author may not be used to endorse or promote products |
|---|
| 14 | * derived from this software without specific prior written permission. |
|---|
| 15 | * |
|---|
| 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
|---|
| 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|---|
| 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|---|
| 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
|---|
| 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|---|
| 21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|---|
| 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|---|
| 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|---|
| 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|---|
| 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|---|
| 26 | */ |
|---|
| 27 | |
|---|
| 28 | |
|---|
| 29 | #include "menuitem.h" |
|---|
| 30 | |
|---|
| 31 | #define Button WidButton |
|---|
| 32 | #define Scale WidScale |
|---|
| 33 | #define Label WidLabel |
|---|
| 34 | #define TextButton WidTextButton |
|---|
| 35 | #define Text WidText |
|---|
| 36 | |
|---|
| 37 | #define MenuItem WidMenuItem |
|---|
| 38 | #define RadioGroup WidRadioGroup |
|---|
| 39 | #define ScaleMenu WidScaleMenu |
|---|
| 40 | void fill(Surface* src, const Rect& rect, int r, int g, int b, int a = 0xff); |
|---|
| 41 | |
|---|
| 42 | MenuItem::MenuItem(PicContainer* parent, const Rect& r_orig, int _x_size, int _y_size, int* _value_ptr) : |
|---|
| 43 | x_size(_x_size), y_size(_y_size), value_ptr(_value_ptr), set_func(0), set_pointer(0) { |
|---|
| 44 | SetPic(parent->create_node(r_orig, 0)); |
|---|
| 45 | menu_width = r_orig.width(); |
|---|
| 46 | menu_height = r_orig.height(); |
|---|
| 47 | label = NULL; |
|---|
| 48 | lb_width = 0; lb_right = 0; |
|---|
| 49 | lb_left = -1; lb_bottom = -1; |
|---|
| 50 | int i; |
|---|
| 51 | for (i=0; i<x_size*y_size; i++) item.push_back(0); |
|---|
| 52 | } |
|---|
| 53 | |
|---|
| 54 | void MenuItem::SetLabelLeft(PicWidget* lb, const Rect& min_rect, const Rect& min_margin) { |
|---|
| 55 | lb_width = min_rect.width(); |
|---|
| 56 | lb_right = min_margin.width(); |
|---|
| 57 | lb_left = -1; |
|---|
| 58 | lb_bottom = -1; |
|---|
| 59 | label = lb; |
|---|
| 60 | } |
|---|
| 61 | |
|---|
| 62 | void MenuItem::SetLabelTop(PicWidget* lb, const Rect& left_margin, const Rect& bottom_margin) { |
|---|
| 63 | lb_left = left_margin.width(); |
|---|
| 64 | lb_bottom = bottom_margin.height(); |
|---|
| 65 | lb_width = -1; |
|---|
| 66 | lb_right = -1; |
|---|
| 67 | label = lb; |
|---|
| 68 | } |
|---|
| 69 | |
|---|
| 70 | void MenuItem::SetValue(int new_value) { |
|---|
| 71 | SetValueImpl(new_value); |
|---|
| 72 | if (value_ptr) *value_ptr = new_value; |
|---|
| 73 | if (set_func) (*set_func)(set_pointer, this); |
|---|
| 74 | } |
|---|
| 75 | |
|---|
| 76 | void MenuItem::activate(void) { |
|---|
| 77 | iterator it; |
|---|
| 78 | for (it=item.begin(); it!=item.end(); it++) { |
|---|
| 79 | if (*it == NULL) continue; |
|---|
| 80 | (*it)->activate(); |
|---|
| 81 | } |
|---|
| 82 | } |
|---|
| 83 | |
|---|
| 84 | void MenuItem::deactivate(void) { |
|---|
| 85 | iterator it; |
|---|
| 86 | for (it=item.begin(); it!=item.end(); it++) { |
|---|
| 87 | if (*it == NULL) continue; |
|---|
| 88 | (*it)->deactivate(); |
|---|
| 89 | } |
|---|
| 90 | } |
|---|
| 91 | |
|---|
| 92 | void MenuItem::pack(void) { |
|---|
| 93 | int x_min = 0, y_min = 0; |
|---|
| 94 | if (lb_width == -1) { // äžã«ã©ãã«ã貌ã |
|---|
| 95 | if (lb_left < 0) lb_left = 0; |
|---|
| 96 | if (lb_bottom < 0) lb_bottom = 0; |
|---|
| 97 | if (label && label->Pic()) { |
|---|
| 98 | label->Pic()->Move(lb_left, 0); |
|---|
| 99 | y_min = lb_bottom + label->Pic()->Height(); |
|---|
| 100 | } else { |
|---|
| 101 | y_min = lb_bottom; |
|---|
| 102 | } |
|---|
| 103 | } else { // å·Šã«ã©ãã«ã貌ã |
|---|
| 104 | if (lb_right < 0) lb_right = 0; |
|---|
| 105 | if (label && label->Pic()) { |
|---|
| 106 | int label_width = label->Pic()->Width(); |
|---|
| 107 | int label_height = label->Pic()->Height(); |
|---|
| 108 | if (label_width > lb_width - lb_right) { |
|---|
| 109 | x_min = label_width + lb_right; |
|---|
| 110 | } else { |
|---|
| 111 | x_min = lb_width; |
|---|
| 112 | } |
|---|
| 113 | } else { |
|---|
| 114 | x_min = lb_width; |
|---|
| 115 | } |
|---|
| 116 | } |
|---|
| 117 | int* item_width = new int[x_size]; |
|---|
| 118 | int* item_height = new int[y_size]; |
|---|
| 119 | int* item_x = new int[x_size]; |
|---|
| 120 | int* item_y = new int[y_size]; |
|---|
| 121 | int i, j; |
|---|
| 122 | for (i=0; i<x_size; i++) item_width[i]=0; |
|---|
| 123 | for (i=0; i<y_size; i++) item_height[i]=0; |
|---|
| 124 | |
|---|
| 125 | iterator it = item.begin(); |
|---|
| 126 | for (i=0; i<y_size; i++) { |
|---|
| 127 | for (j=0; j<x_size; j++) { |
|---|
| 128 | if (*it != NULL && (*it)->Pic() != NULL) { |
|---|
| 129 | PicBase* pic = (*it)->Pic(); |
|---|
| 130 | if (item_width[j] < pic->Width()) item_width[j] = pic->Width(); |
|---|
| 131 | if (item_height[i] < pic->Height()) item_height[i] = pic->Height(); |
|---|
| 132 | } |
|---|
| 133 | it++; |
|---|
| 134 | } |
|---|
| 135 | } |
|---|
| 136 | int width=0, height=0; |
|---|
| 137 | for (i=0; i<x_size; i++) { |
|---|
| 138 | width += item_width[i]; |
|---|
| 139 | } |
|---|
| 140 | for (i=0; i<y_size; i++) { |
|---|
| 141 | height += item_height[i]; |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | int x=x_min, y=y_min; |
|---|
| 145 | // width / height ã®åå²ãåœãŠ |
|---|
| 146 | if (menu_width > width + x_min) { |
|---|
| 147 | int dif = menu_width - width - x_min; |
|---|
| 148 | int n = x_size + 1; |
|---|
| 149 | x += dif/n; |
|---|
| 150 | for (i=0; i<x_size; i++) { |
|---|
| 151 | item_x[i] = x + item_width[i] / 2; |
|---|
| 152 | x += item_width[i] + dif*(i+2)/n - dif*(i+1)/n; |
|---|
| 153 | } |
|---|
| 154 | } else { |
|---|
| 155 | if (menu_width == 0) { |
|---|
| 156 | Pic()->SetSurfaceRect(Rect(0, 0, width+x_min, Pic()->Height())); |
|---|
| 157 | } |
|---|
| 158 | for (i=0; i<x_size; i++) { |
|---|
| 159 | item_x[i] = x + item_width[i] / 2; |
|---|
| 160 | x += item_width[i]; |
|---|
| 161 | } |
|---|
| 162 | } |
|---|
| 163 | if (menu_height > height+y_min) { |
|---|
| 164 | int dif = menu_height - height - y_min; |
|---|
| 165 | int n = y_size + 1; |
|---|
| 166 | y += dif/n; |
|---|
| 167 | for (i=0; i<y_size; i++) { |
|---|
| 168 | item_y[i] = y + item_height[i] / 2; |
|---|
| 169 | y += item_height[i] + dif*(i+2)/n - dif*(i+1)/n; |
|---|
| 170 | } |
|---|
| 171 | } else { |
|---|
| 172 | if (menu_height == 0) { |
|---|
| 173 | Pic()->SetSurfaceRect(Rect(0, 0, Pic()->Width(), height+y_min)); |
|---|
| 174 | } |
|---|
| 175 | for (i=0; i<y_size; i++) { |
|---|
| 176 | item_y[i] = y + item_height[i] / 2; |
|---|
| 177 | y += item_height[i]; |
|---|
| 178 | } |
|---|
| 179 | } |
|---|
| 180 | // äœçœ®ã®åå²ãåœãŠ |
|---|
| 181 | it = item.begin(); |
|---|
| 182 | for (i=0; i<y_size; i++) { |
|---|
| 183 | for (j=0; j<x_size; j++) { |
|---|
| 184 | if (*it != NULL && (*it)->Pic() != NULL) { |
|---|
| 185 | PicBase* pic = (*it)->Pic(); |
|---|
| 186 | int x0 = item_x[j]-pic->Width()/2; |
|---|
| 187 | int y0 = item_y[i]-pic->Height()/2; |
|---|
| 188 | pic->Move(x0, y0); |
|---|
| 189 | } |
|---|
| 190 | it++; |
|---|
| 191 | } |
|---|
| 192 | } |
|---|
| 193 | // å·Šã«ã©ãã«ãããå Žåãã©ãã«ã®é«ãæ¹åã®ã»ã³ã¿ãªã³ã° |
|---|
| 194 | if (label && label->Pic() && lb_width != -1) { |
|---|
| 195 | int label_width = label->Pic()->Width(); |
|---|
| 196 | int label_height = label->Pic()->Height(); |
|---|
| 197 | label->Pic()->Move(x_min-label_width-lb_right, (Pic()->Height() - label_height) / 2); |
|---|
| 198 | } |
|---|
| 199 | |
|---|
| 200 | delete[] item_width; |
|---|
| 201 | delete[] item_height; |
|---|
| 202 | delete[] item_x; |
|---|
| 203 | delete[] item_y; |
|---|
| 204 | } |
|---|
| 205 | |
|---|
| 206 | RadioButton::RadioButton(Event::Container& _container, PicContainer* _parent, const Rect& r_orig, int _x_size, int _y_size, int* _value_ptr, const Rect& _button_r, int _text_size, const Color& _fore, const Color& _pressed, const Color& _back) : |
|---|
| 207 | MenuItem(_parent, r_orig, _x_size, _y_size,_value_ptr), |
|---|
| 208 | container(_container), parent(_parent), text_size(_text_size), button_rect(_button_r), buttons(0), |
|---|
| 209 | fore_color(_fore), pressed_color(_pressed), back_color(_back) { |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | void RadioButton::Add(const char* s, bool is_center) { |
|---|
| 213 | Add(s, fore_color, pressed_color, back_color, is_center); |
|---|
| 214 | } |
|---|
| 215 | |
|---|
| 216 | void RadioButton::Add(const char* s, const Color& fore, const Color& pressed, const Color& back, bool is_center) { |
|---|
| 217 | if (buttons >= x_size*y_size) { |
|---|
| 218 | fprintf(stderr,"too many buttons (%d/%d) in RadioButton::Add ; text = %s\n",x_size,y_size,s); |
|---|
| 219 | return; |
|---|
| 220 | } |
|---|
| 221 | TextButton* wid = new TextButton(container, PicNode(), s, text_size, TextButton::Attribute(is_center ? TextButton::CENTER : 0), button_rect, 1, fore, pressed, back); |
|---|
| 222 | |
|---|
| 223 | wid->press_func = &PressCallback; |
|---|
| 224 | wid->press_pointer = (void*)this; |
|---|
| 225 | |
|---|
| 226 | if (value_ptr && buttons == *value_ptr) wid->Toggle(true); |
|---|
| 227 | int x_pos, y_pos; |
|---|
| 228 | if (y_size == 0) x_pos=buttons; |
|---|
| 229 | else x_pos = buttons / y_size, y_pos = buttons % y_size; |
|---|
| 230 | item[x_pos + y_pos*x_size] = wid; |
|---|
| 231 | buttons++; |
|---|
| 232 | } |
|---|
| 233 | |
|---|
| 234 | void RadioButton::PressCallback(void* pointer, Button* from) { |
|---|
| 235 | RadioButton* wid = (RadioButton*)pointer; |
|---|
| 236 | int i; |
|---|
| 237 | for (i=0; i<wid->x_size*wid->y_size; i++) { |
|---|
| 238 | if (from == wid->item[i]) { |
|---|
| 239 | wid->SetValue(i); |
|---|
| 240 | return; |
|---|
| 241 | } |
|---|
| 242 | } |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | void RadioButton::SetValueImpl(int new_value) { |
|---|
| 246 | int i; |
|---|
| 247 | for (i=0; i<x_size*y_size; i++) { |
|---|
| 248 | Button* wid = dynamic_cast<Button*>(item[i]); |
|---|
| 249 | if (wid != NULL) { |
|---|
| 250 | if (i == new_value) wid->Toggle(true); |
|---|
| 251 | else wid->Toggle(false); |
|---|
| 252 | } |
|---|
| 253 | } |
|---|
| 254 | } |
|---|