1 #ifndef NO_EDITOR
2 #include <boost/bind.hpp>
3 #include <vector>
4 
5 #include "asserts.hpp"
6 #include "geometry.hpp"
7 #include "image_widget.hpp"
8 #include "drag_widget.hpp"
9 #include "raster.hpp"
10 
11 enum {
12 	HOT_X = 16,
13 	HOT_Y = 16,
14 };
15 enum {
16 	CURSOR_WIDTH	= 32,
17 	CURSOR_HEIGHT	= 32,
18 };
19 
20 enum {
21 	BORDER_THICKNESS = 14,
22 };
23 
24 static const unsigned char horiz_cursor_data[] = {
25         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
26         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
27         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x60,
28         0x0a, 0x00, 0x00, 0x50, 0x12, 0x00, 0x00, 0x48, 0x23, 0xff, 0xff, 0xc4, 0x40, 0x00, 0x00, 0x02,
29         0x23, 0xff, 0xff, 0xc4, 0x12, 0x00, 0x00, 0x48, 0x0a, 0x00, 0x00, 0x50, 0x06, 0x00, 0x00, 0x60,
30         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
32         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
33 };
34 
35 static const unsigned char horiz_cursor_mask[] = {
36         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x60,
39         0x0e, 0x00, 0x00, 0x70, 0x1e, 0x00, 0x00, 0x78, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe,
40         0x3f, 0xff, 0xff, 0xfc, 0x1e, 0x00, 0x00, 0x78, 0x0e, 0x00, 0x00, 0x70, 0x06, 0x00, 0x00, 0x60,
41         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44 };
45 
46 static const unsigned char vert_cursor_data[] = {
47         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0x20, 0x00,
48         0x00, 0x04, 0x10, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x0f, 0x78, 0x00, 0x00, 0x01, 0x40, 0x00,
49         0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00,
50         0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00,
51         0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00,
52         0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00,
53         0x00, 0x01, 0x40, 0x00, 0x00, 0x0f, 0x78, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x04, 0x10, 0x00,
54         0x00, 0x02, 0x20, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
55 };
56 
57 static const unsigned char vert_cursor_mask[] = {
58         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x03, 0xe0, 0x00,
59         0x00, 0x07, 0xf0, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x01, 0xc0, 0x00,
60         0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00,
61         0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00,
62         0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00,
63         0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00,
64         0x00, 0x01, 0xc0, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x07, 0xf0, 0x00,
65         0x00, 0x03, 0xe0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
66 };
67 
68 namespace gui {
69 
70 namespace {
71 const std::string DraggerImageVert  = "drag-widget-vertical";
72 const std::string DraggerImageHoriz = "drag-widget-horizontal";
73 }
74 
drag_widget(const int x,const int y,const int w,const int h,const drag_direction dir,boost::function<void (int,int)> drag_start,boost::function<void (int,int)> drag_end,boost::function<void (int,int)> drag_move)75 drag_widget::drag_widget(const int x, const int y, const int w, const int h,
76 	const drag_direction dir,
77     boost::function<void(int, int)> drag_start,
78     boost::function<void(int, int)> drag_end,
79     boost::function<void(int, int)> drag_move)
80     : x_(x), y_(y), w_(w), h_(h), dir_(dir),
81     drag_start_(drag_start), drag_end_(drag_end), drag_move_(drag_move),
82 
83 	old_cursor_(NULL), dragging_handle_(0)
84 {
85 	set_environment();
86 	init();
87 }
88 
drag_widget(const variant & v,game_logic::formula_callable * e)89 drag_widget::drag_widget(const variant& v, game_logic::formula_callable* e)
90 	: widget(v,e), old_cursor_(NULL), dragging_handle_(0)
91 {
92 	ASSERT_LOG(get_environment() != 0, "You must specify a callable environment");
93 	dir_ = v["direction"].as_string_default("horizontal") == "horizontal" ? DRAG_HORIZONTAL : DRAG_VERTICAL;
94 	if(v.has_key("on_drag_start")) {
95 		drag_start_ = boost::bind(&drag_widget::drag_start, this, _1, _2);
96 		drag_start_handler_ = get_environment()->create_formula(v["on_drag_start"]);
97 	}
98 	if(v.has_key("on_drag_end")) {
99 		drag_end_ = boost::bind(&drag_widget::drag_end, this, _1, _2);
100 		drag_end_handler_ = get_environment()->create_formula(v["on_drag_end"]);
101 	}
102 	if(v.has_key("on_drag")) {
103 		drag_move_ = boost::bind(&drag_widget::drag, this, _1, _2);
104 		drag_handler_ = get_environment()->create_formula(v["on_drag"]);
105 	}
106 	std::vector<int> r = v["rect"].as_list_int();
107 	ASSERT_EQ(r.size(), 4);
108 	x_ = r[0];
109 	y_ = r[1];
110 	w_ = r[2];
111 	h_ = r[3];
112 	init();
113 }
114 
init()115 void drag_widget::init()
116 {
117 	SDL_Cursor* curs;
118 	if(dir_ == DRAG_HORIZONTAL) {
119 		curs = SDL_CreateCursor(const_cast<Uint8*>(horiz_cursor_data), const_cast<Uint8*>(horiz_cursor_mask),
120 			CURSOR_WIDTH, CURSOR_HEIGHT, HOT_X, HOT_Y);
121 		dragger_ = widget_ptr(new gui_section_widget(DraggerImageHoriz));
122 	} else if(dir_ == DRAG_VERTICAL) {
123 		curs = SDL_CreateCursor(const_cast<Uint8*>(vert_cursor_data), const_cast<Uint8*>(vert_cursor_mask),
124 			CURSOR_WIDTH, CURSOR_HEIGHT, HOT_X, HOT_Y);
125 		drag_cursor_ = cursor_ptr(curs, SDL_FreeCursor);
126 
127 		dragger_ = widget_ptr(new gui_section_widget(DraggerImageVert));
128 	} else {
129 		ASSERT_LOG(false, "Drag direction not given as horizontal or vertical " << dir_);
130 	}
131 	drag_cursor_ = cursor_ptr(curs, SDL_FreeCursor);
132 
133 	dragger_->set_loc(0, h_/2 - dragger_->height()/2);
134 	//std::cerr << "DRAGGER LOC: " << dragger_dims_ << std::endl;
135 	//std::cerr << "LEFT EDGE BORDER: " << border_ << std::endl;
136 }
137 
drag(int dx,int dy)138 void drag_widget::drag(int dx, int dy)
139 {
140 	using namespace game_logic;
141 	if(get_environment()) {
142 		map_formula_callable_ptr callable = map_formula_callable_ptr(new map_formula_callable(get_environment()));
143 		callable->add("drag_dx", variant(dx));
144 		callable->add("drag_dy", variant(dy));
145 		variant value = drag_handler_->execute(*callable);
146 		get_environment()->execute_command(value);
147 	} else {
148 		std::cerr << "drag_widget::drag() called without environment!" << std::endl;
149 	}
150 }
151 
drag_start(int x,int y)152 void drag_widget::drag_start(int x, int y)
153 {
154 	using namespace game_logic;
155 	if(get_environment()) {
156 		map_formula_callable_ptr callable = map_formula_callable_ptr(new map_formula_callable(get_environment()));
157 		callable->add("drag_x", variant(x));
158 		callable->add("drag_y", variant(y));
159 		variant value = drag_start_handler_->execute(*callable);
160 		get_environment()->execute_command(value);
161 	} else {
162 		std::cerr << "drag_widget::drag_start() called without environment!" << std::endl;
163 	}
164 }
165 
drag_end(int x,int y)166 void drag_widget::drag_end(int x, int y)
167 {
168 	using namespace game_logic;
169 	if(get_environment()) {
170 		map_formula_callable_ptr callable = map_formula_callable_ptr(new map_formula_callable(get_environment()));
171 		callable->add("drag_x", variant(x));
172 		callable->add("drag_y", variant(y));
173 		variant value = drag_end_handler_->execute(*callable);
174 		get_environment()->execute_command(value);
175 	} else {
176 		std::cerr << "drag_widget::drag_end() called without environment!" << std::endl;
177 	}
178 }
179 
handle_draw() const180 void drag_widget::handle_draw() const
181 {
182 	if(dragger_) {
183 		dragger_->draw();
184 	}
185 }
186 
handle_event(const SDL_Event & event,bool claimed)187 bool drag_widget::handle_event(const SDL_Event& event, bool claimed)
188 {
189 	if(claimed) {
190 		return claimed;
191 	}
192 
193 	if(event.type == SDL_MOUSEMOTION) {
194 		return handle_mousemotion(event.motion, claimed);
195 	} else if(event.type == SDL_MOUSEBUTTONDOWN) {
196 		return handle_mousedown(event.button, claimed);
197 	} else if(event.type == SDL_MOUSEBUTTONUP) {
198 		return handle_mouseup(event.button, claimed);
199 	}
200 
201 	return claimed;
202 }
203 
get_border_rect() const204 rect drag_widget::get_border_rect() const
205 {
206 	if(dir_ == DRAG_HORIZONTAL) {
207 		return rect(x_ - BORDER_THICKNESS/2, y_, BORDER_THICKNESS, h_);
208 	}
209 	return rect(x_, y_ - BORDER_THICKNESS/2, w_, BORDER_THICKNESS);
210 }
211 
get_dragger_rect() const212 rect drag_widget::get_dragger_rect() const
213 {
214 	return rect(x_, y_ + h_/2 - dragger_->height()/2, dragger_->width(), dragger_->height() );
215 }
216 
handle_mousedown(const SDL_MouseButtonEvent & event,bool claimed)217 bool drag_widget::handle_mousedown(const SDL_MouseButtonEvent& event, bool claimed)
218 {
219 	point p;
220 	int button_state = SDL_GetMouseState(&p.x, &p.y);
221 	if(point_in_rect(p, get_border_rect()) || point_in_rect(p, get_dragger_rect())) {
222 		if(dragging_handle_ == 0) {
223 			dragging_handle_ = event.button;
224 			start_pos_ = p;
225 			if(drag_start_) {
226 				drag_start_(p.x, p.y);
227 			}
228 			claimed = true;
229 		}
230 	}
231 	return claimed;
232 }
233 
handle_mouseup(const SDL_MouseButtonEvent & event,bool claimed)234 bool drag_widget::handle_mouseup(const SDL_MouseButtonEvent& event, bool claimed)
235 {
236 	int mousex, mousey;
237 	int button_state = SDL_GetMouseState(&mousex, &mousey);
238 	if(dragging_handle_ == event.button) {
239 		dragging_handle_ = 0;
240 		if(drag_end_) {
241 			drag_end_(mousex, mousey);
242 		}
243 		claimed = true;
244 	}
245 	return claimed;
246 }
247 
handle_mousemotion(const SDL_MouseMotionEvent & event,bool claimed)248 bool drag_widget::handle_mousemotion(const SDL_MouseMotionEvent& event, bool claimed)
249 {
250 	point p;
251 	int button_state = SDL_GetMouseState(&p.x, &p.y);
252 	if(dragging_handle_) {
253 		int dx = start_pos_.x - p.x;
254 		int dy = start_pos_.y - p.y;
255 		//std::cerr << "SDL_MOUSEMOTION: " << p.x << ", " << p.y << "; " << dx << "," << dy << std::endl;
256 		if(drag_move_) {
257 			drag_move_(dx, dy);
258 			start_pos_.x = p.x;
259 			start_pos_.y = p.y;
260 			if(dir_ == DRAG_HORIZONTAL) {
261 				x_ += dx;
262 				w_ += dx;
263 			} else if(dir_ == DRAG_VERTICAL) {
264 				y_ += dy;
265 				h_ += dy;
266 			}
267 		}
268 	} else {
269 		if(point_in_rect(p, get_dragger_rect()) || point_in_rect(p, get_border_rect())) {
270 			if(old_cursor_ == NULL) {
271 				old_cursor_ = SDL_GetCursor();
272 				SDL_SetCursor(drag_cursor_.get());
273 			}
274 		} else {
275 			if(old_cursor_) {
276 				SDL_SetCursor(old_cursor_);
277 				old_cursor_ = NULL;
278 			}
279 		}
280 	}
281 	return claimed;
282 }
283 
284 }
285 
286 #endif
287