1 // $Id: worldview_select_tool.cxx,v 1.22 2003/07/28 22:46:48 grumbel Exp $
3 // Construo - A wire-frame construction gamee
4 // Copyright (C) 2002 Ingo Ruhnke <grumbel@gmx.de>
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "controller.hxx"
25 #include "worldview_component.hxx"
26 #include "particle.hxx"
27 #include "world_gui_manager.hxx"
29 #include "root_graphic_context.hxx"
30 #include "worldview_select_tool.hxx"
32 WorldViewSelectTool::WorldViewSelectTool ()
35 old_scale_factor
= 1.0f
;
38 WorldViewSelectTool::~WorldViewSelectTool ()
43 WorldViewSelectTool::draw_background (ZoomGraphicContext
* gc
)
45 for (Selection::iterator i
= selection
.begin (); i
!= selection
.end (); ++i
)
47 (*i
)->draw_velocity_vector (gc
);
48 (*i
)->draw_highlight (gc
);
53 WorldViewSelectTool::draw_foreground (ZoomGraphicContext
* gc
)
55 float x
= WorldViewComponent::instance()->get_gc()->screen_to_world_x (input_context
->get_mouse_x ());
56 float y
= WorldViewComponent::instance()->get_gc()->screen_to_world_y (input_context
->get_mouse_y ());
58 if (mode
== GETTING_SELECTION_MODE
)
60 gc
->draw_rect (Math::min(x
, click_pos
.x
),
61 Math::min(y
, click_pos
.y
),
62 Math::max(x
, click_pos
.x
),
63 Math::max(y
, click_pos
.y
),
64 Colors::selection_rect
);
67 if (!selection
.empty())
69 Particle
& p
= **selection
.begin();
70 Rect
<float> selection_box (p
.pos
.x
, p
.pos
.y
, p
.pos
.x
, p
.pos
.y
);
72 for (Selection::iterator i
= selection
.begin (); i
!= selection
.end (); ++i
)
74 selection_box
.x1
= Math::min(selection_box
.x1
, (*i
)->pos
.x
);
75 selection_box
.y1
= Math::min(selection_box
.y1
, (*i
)->pos
.y
);
77 selection_box
.x2
= Math::max(selection_box
.x2
, (*i
)->pos
.x
);
78 selection_box
.y2
= Math::max(selection_box
.y2
, (*i
)->pos
.y
);
81 float border
= 20.0f
/ gc
->get_zoom();
82 gc
->draw_rect (selection_box
.x1
- border
, selection_box
.y1
- border
,
83 selection_box
.x2
+ border
, selection_box
.y2
+ border
,
86 if (0) // draw selection rect
88 float rsize
= 5.0f
/ gc
->get_zoom();
89 gc
->draw_fill_rect (selection_box
.x1
- border
- rsize
, selection_box
.y1
- border
- rsize
,
90 selection_box
.x1
- border
+ rsize
, selection_box
.y1
- border
+ rsize
,
91 Colors::selection_resizer
);
92 gc
->draw_fill_rect (selection_box
.x2
+ border
- rsize
, selection_box
.y1
- border
- rsize
,
93 selection_box
.x2
+ border
+ rsize
, selection_box
.y1
- border
+ rsize
,
94 Colors::selection_resizer
);
95 gc
->draw_fill_rect (selection_box
.x1
- border
- rsize
, selection_box
.y2
+ border
- rsize
,
96 selection_box
.x1
- border
+ rsize
, selection_box
.y2
+ border
+ rsize
,
97 Colors::selection_resizer
);
98 gc
->draw_fill_rect (selection_box
.x2
+ border
- rsize
, selection_box
.y2
+ border
- rsize
,
99 selection_box
.x2
+ border
+ rsize
, selection_box
.y2
+ border
+ rsize
,
100 Colors::selection_resizer
);
103 gc
->get_parent_gc()->draw_circle(gc
->world_to_screen(selection
.get_center ()),
104 8.0f
, Colors::selection_rect
);
105 gc
->get_parent_gc()->draw_circle(gc
->world_to_screen(selection
.get_center ()),
106 16.0f
, Colors::selection_rect
);
111 WorldViewSelectTool::activate ()
116 WorldViewSelectTool::deactivate ()
122 WorldViewSelectTool::on_primary_button_press (int screen_x
, int screen_y
)
128 float x
= WorldViewComponent::instance()->get_gc()->screen_to_world_x (screen_x
);
129 float y
= WorldViewComponent::instance()->get_gc()->screen_to_world_y (screen_y
);
131 World
& world
= *Controller::instance()->get_world ();
133 WorldGUIManager::instance()->grab_mouse (WorldViewComponent::instance());
135 mode
= GETTING_SELECTION_MODE
;
140 // If the mouse clicks on a particle from the selection, we move the selection
141 Particle
* new_current_particle
= world
.get_particle (x
, y
);
142 for (Selection::iterator i
= selection
.begin (); i
!= selection
.end (); ++i
)
144 if (new_current_particle
== *i
)
146 Controller::instance()->push_undo();
147 mode
= MOVING_SELECTION_MODE
;
148 move_diff
= Vector2d();
153 // If mouse clicks into empty space, we make a new selection
154 if (mode
== GETTING_SELECTION_MODE
)
161 case SCALING_SELECTION_MODE
:
163 graphic_context
->pop_cursor();
164 WorldGUIManager::instance()->ungrab_mouse (WorldViewComponent::instance());
166 graphic_context
->pop_cursor();
167 old_scale_factor
= 1.0f
;
171 // Do nothing, so that we don't mess up other modes
177 WorldViewSelectTool::on_primary_button_release (int x
, int y
)
179 WorldGUIManager::instance()->ungrab_mouse (WorldViewComponent::instance());
183 case GETTING_SELECTION_MODE
:
185 selection
.select_particles(click_pos
,
186 WorldViewComponent::instance()->get_gc()->screen_to_world (Vector2d(x
,y
)));
191 case MOVING_SELECTION_MODE
:
200 WorldViewSelectTool::on_secondary_button_press (int screen_x
, int screen_y
)
205 if (!selection
.empty())
207 Controller::instance()->push_undo();
208 graphic_context
->push_cursor();
209 graphic_context
->set_cursor(CURSOR_ROTATE
);
211 mode
= ROTATING_SELECTION_MODE
;
212 WorldGUIManager::instance()->grab_mouse (WorldViewComponent::instance());
214 click_pos
= WorldViewComponent::instance()->get_gc()->screen_to_world(Vector2d(screen_x
, screen_y
));
216 rotate_center
= selection
.get_center();
220 case SCALING_SELECTION_MODE
:
222 graphic_context
->pop_cursor();
223 WorldGUIManager::instance()->ungrab_mouse (WorldViewComponent::instance());
225 graphic_context
->pop_cursor();
226 selection
.scale(1.0f
/old_scale_factor
, scale_center
);
227 old_scale_factor
= 1.0f
;
237 WorldViewSelectTool::on_secondary_button_release (int x
, int y
)
241 case ROTATING_SELECTION_MODE
:
242 graphic_context
->pop_cursor();
243 WorldGUIManager::instance()->ungrab_mouse (WorldViewComponent::instance());
253 WorldViewSelectTool::on_delete_press (int x
, int y
)
255 Controller::instance()->push_undo();
257 World
& world
= *Controller::instance()->get_world ();
258 for (Selection::iterator i
= selection
.begin (); i
!= selection
.end (); ++i
)
260 world
.remove_particle(*i
);
267 WorldViewSelectTool::on_fix_press (int x
, int y
)
269 bool mark_all
= false;
270 for (Selection::iterator i
= selection
.begin (); i
!= selection
.end (); ++i
)
272 if (!(*i
)->get_fixed())
280 for (Selection::iterator i
= selection
.begin (); i
!= selection
.end (); ++i
)
282 (*i
)->set_fixed (true);
287 for (Selection::iterator i
= selection
.begin (); i
!= selection
.end (); ++i
)
289 (*i
)->set_fixed (!(*i
)->get_fixed());
295 WorldViewSelectTool::on_mouse_move (int screen_x
, int screen_y
, int of_x
, int of_y
)
297 World
& world
= *Controller::instance()->get_world ();
301 case MOVING_SELECTION_MODE
:
303 Vector2d
new_pos(WorldViewComponent::instance()->get_gc()->screen_to_world_x (screen_x
),
304 WorldViewComponent::instance()->get_gc()->screen_to_world_y (screen_y
));
306 Vector2d diff
= new_pos
- click_pos
;
308 // Undo the last move (FIXME: Potential round errors)
309 for (Selection::iterator i
= selection
.begin (); i
!= selection
.end (); ++i
)
311 (*i
)->pos
-= move_diff
;
314 if (WorldViewComponent::instance()->uses_grid())
316 diff
.x
= Math::round_to(diff
.x
, 10);
317 diff
.y
= Math::round_to(diff
.y
, 10);
322 for (Selection::iterator i
= selection
.begin (); i
!= selection
.end (); ++i
)
326 // Recalculate all springs that are attached to the
327 // selection, but not fully in it.
328 std::vector
<Spring
*>& spring_mgr
= world
.get_spring_mgr();
329 for (std::vector
<Spring
*>::iterator j
= spring_mgr
.begin ();
330 j
!= spring_mgr
.end (); ++j
)
332 if ((*j
)->particles
.first
== *i
333 || (*j
)->particles
.second
== *i
)
335 (*j
)->recalc_length ();
342 case SCALING_SELECTION_MODE
:
344 Vector2d new_pos
= WorldViewComponent::instance()->get_gc()->screen_to_world(Vector2d(screen_x
, screen_y
));
345 float scale_factor
= fabsf((scale_center
- new_pos
).norm()/(scale_center
- click_pos
).norm());
346 selection
.scale(1.0f
/old_scale_factor
, scale_center
);
347 selection
.scale(scale_factor
, scale_center
);
348 old_scale_factor
= scale_factor
;
351 case ROTATING_SELECTION_MODE
:
353 Vector2d
new_pos(WorldViewComponent::instance()->get_gc()->screen_to_world_x (screen_x
),
354 WorldViewComponent::instance()->get_gc()->screen_to_world_y (screen_y
));
356 float new_angle
= atan2(new_pos
.y
- rotate_center
.y
,
357 new_pos
.x
- rotate_center
.x
);
358 float old_angle
= atan2(click_pos
.y
- rotate_center
.y
,
359 click_pos
.x
- rotate_center
.x
);
360 float rot_angle
= new_angle
- old_angle
;
362 selection
.rotate (rot_angle
, rotate_center
);
373 WorldViewSelectTool::on_scale_press (int x
, int y
)
375 if (!selection
.empty())
377 rotate_center
= selection
.get_center();
378 Controller::instance()->push_undo();
379 graphic_context
->push_cursor();
380 graphic_context
->set_cursor(CURSOR_SCALE
);
382 click_pos
= WorldViewComponent::instance()->get_gc()->screen_to_world(Vector2d(x
, y
));
383 WorldGUIManager::instance()->grab_mouse (WorldViewComponent::instance());
385 mode
= SCALING_SELECTION_MODE
;
387 scale_center
= selection
.get_center();
392 WorldViewSelectTool::on_duplicate_press (int x
, int y
)
394 selection
.duplicate ();
398 WorldViewSelectTool::on_button_press (int button_id
, int x
, int y
)
400 Vector2d pos
= WorldViewComponent::instance()->get_gc()->screen_to_world(Vector2d(x
, y
));
404 case BUTTON_SETVELOCITY
:
405 selection
.set_velocity (pos
- selection
.get_center ());
417 WorldViewSelectTool::on_join_press (int x
, int y
)
419 std::cout
<< "Join pressed" << std::endl
;
420 selection
.join_doubles(5.0f
);