1 
2 /*
3    Copyright (C) 2007 by David White <dave@whitevine.net>
4    Part of the Silver Tree Project
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License version 2 or later.
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY.
10 
11    See the COPYING file for more details.
12 */
13 #include <boost/bind.hpp>
14 
15 #include "asserts.hpp"
16 #include "button.hpp"
17 #include "custom_object_functions.hpp"
18 #include "iphone_controls.hpp"
19 #include "formula.hpp"
20 #include "label.hpp"
21 #include "raster.hpp"
22 #include "surface_cache.hpp"
23 #include "framed_gui_element.hpp"
24 #include "widget_factory.hpp"
25 
26 namespace gui {
27 
button(const std::string & str,boost::function<void ()> onclick)28 button::button(const std::string& str, boost::function<void()> onclick)
29   : label_(new label(str, graphics::color_white())),
30     onclick_(onclick), button_resolution_(BUTTON_SIZE_NORMAL_RESOLUTION),
31 	button_style_(BUTTON_STYLE_NORMAL), hpadding_(10), vpadding_(4),
32 	down_(false)
33 {
34 	set_environment();
35 	setup();
36 }
37 
button(widget_ptr label,boost::function<void ()> onclick,BUTTON_STYLE button_style,BUTTON_RESOLUTION button_resolution)38 button::button(widget_ptr label, boost::function<void ()> onclick, BUTTON_STYLE button_style, BUTTON_RESOLUTION button_resolution)
39   : label_(label), onclick_(onclick), button_resolution_(button_resolution), button_style_(button_style),
40 	down_(false), hpadding_(10), vpadding_(4)
41 
42 {
43 	set_environment();
44 	setup();
45 }
46 
button(const variant & v,game_logic::formula_callable * e)47 button::button(const variant& v, game_logic::formula_callable* e) : widget(v,e), down_(false)
48 {
49 	variant label_var = v["label"];
50 	label_ = label_var.is_map() ? widget_factory::create(label_var, e) : new label(label_var.as_string_default("Button"), graphics::color_white());
51 	ASSERT_LOG(v.has_key("on_click"), "Button must be supplied with an on_click handler");
52 	// create delegate for onclick
53 	ASSERT_LOG(get_environment() != 0, "You must specify a callable environment");
54 	click_handler_ = get_environment()->create_formula(v["on_click"]);
55 	onclick_ = boost::bind(&button::click, this);
56 	button_resolution_ = v["resolution"].as_string_default("normal") == "normal" ? BUTTON_SIZE_NORMAL_RESOLUTION : BUTTON_SIZE_DOUBLE_RESOLUTION;
57 	button_style_ = v["style"].as_string_default("default") == "default" ? BUTTON_STYLE_DEFAULT : BUTTON_STYLE_NORMAL;
58 	hpadding_ = v["hpad"].as_int(10);
59 	vpadding_ = v["vpad"].as_int(4);
60 	if(v.has_key("padding")) {
61 		ASSERT_LOG(v["padding"].num_elements() == 2, "Incorrect number of padding elements specifed." << v["padding"].num_elements());
62 		hpadding_ = v["padding"][0].as_int();
63 		vpadding_ = v["padding"][1].as_int();
64 	}
65 	setup();
66 }
67 
click()68 void button::click()
69 {
70 	if(get_environment()) {
71 		variant value = click_handler_->execute(*get_environment());
72 		get_environment()->execute_command(value);
73 	} else {
74 		std::cerr << "button::click() called without environment!" << std::endl;
75 	}
76 }
77 
setup()78 void button::setup()
79 {
80 	if(button_style_ == BUTTON_STYLE_DEFAULT){
81 		normal_button_image_set_ = framed_gui_element::get("default_button");
82 		depressed_button_image_set_ = framed_gui_element::get("default_button_pressed");
83 		focus_button_image_set_ = framed_gui_element::get("default_button_focus");
84 	}else{
85 		normal_button_image_set_ = framed_gui_element::get("regular_button");
86 		depressed_button_image_set_ = framed_gui_element::get("regular_button_pressed");
87 		focus_button_image_set_ = framed_gui_element::get("regular_button_focus");
88 	}
89 	current_button_image_set_ = normal_button_image_set_;
90 
91 	set_label(label_);
92 }
93 
set_label(widget_ptr label)94 void button::set_label(widget_ptr label)
95 {
96 	label_ = label;
97 	set_dim(label_->width()+hpadding_*2,label_->height()+vpadding_*2);
98 }
99 
handle_draw() const100 void button::handle_draw() const
101 {
102 	label_->set_loc(x()+width()/2 - label_->width()/2,y()+height()/2 - label_->height()/2);
103 	current_button_image_set_->blit(x(),y(),width(),height(), button_resolution_ != 0);
104 	label_->draw();
105 }
106 
handle_process()107 void button::handle_process()
108 {
109 	widget::handle_process();
110 	label_->process();
111 }
112 
handle_event(const SDL_Event & event,bool claimed)113 bool button::handle_event(const SDL_Event& event, bool claimed)
114 {
115 	if((event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP)
116 		&& (event.button.button == SDL_BUTTON_WHEELUP || event.button.button == SDL_BUTTON_WHEELDOWN)
117 		&& in_widget(event.button.x, event.button.y)) {
118 		// skip processing if mousewheel event
119 		return claimed;
120 	}
121 
122     if(claimed) {
123 		current_button_image_set_ = normal_button_image_set_;
124 		down_ = false;
125     }
126 
127 	if(event.type == SDL_MOUSEMOTION) {
128 		const SDL_MouseMotionEvent& e = event.motion;
129 		if(in_widget(e.x,e.y)) {
130 			current_button_image_set_ = down_ ? depressed_button_image_set_ : focus_button_image_set_;
131 		} else {
132 			current_button_image_set_ = normal_button_image_set_;
133 		}
134 	} else if(event.type == SDL_MOUSEBUTTONDOWN) {
135 		const SDL_MouseButtonEvent& e = event.button;
136 		if(in_widget(e.x,e.y)) {
137 			current_button_image_set_ = depressed_button_image_set_;
138 			down_ = true;
139 			claimed = true;
140 		}
141 	} else if(event.type == SDL_MOUSEBUTTONUP) {
142 		down_ = false;
143 		const SDL_MouseButtonEvent& e = event.button;
144 		if(current_button_image_set_ == depressed_button_image_set_) {
145 			if(in_widget(e.x,e.y)) {
146 				current_button_image_set_ = focus_button_image_set_;
147 				onclick_();
148 				claimed = true;
149 			} else {
150 				current_button_image_set_ = normal_button_image_set_;
151 			}
152 		}
153 	}
154 	return claimed;
155 }
156 
get_widget_by_id(const std::string & id)157 widget_ptr button::get_widget_by_id(const std::string& id)
158 {
159 	if(label_ && label_->get_widget_by_id(id)) {
160 		return label_;
161 	}
162 	return widget::get_widget_by_id(id);
163 }
164 
get_value(const std::string & key) const165 variant button::get_value(const std::string& key) const
166 {
167 	if(key == "label") {
168 		return variant(label_.get());
169 	}
170 	return widget::get_value(key);
171 }
172 
173 }
174