]> git.mxchange.org Git - flightgear.git/blob - src/Main/FGManipulator.cxx
Handle scroll wheel events in osgViewer version
[flightgear.git] / src / Main / FGManipulator.cxx
1 #ifdef HAVE_CONFIG_H
2 #  include <config.h>
3 #endif
4 #include <osg/Math>
5 #include <osgViewer/Viewer>
6 #include <plib/pu.h>
7 #include "FGManipulator.hxx"
8
9 #if !defined(X_DISPLAY_MISSING)
10 #define X_DOUBLE_SCROLL_BUG 1
11 #endif
12
13 // The manipulator is responsible for updating a Viewer's camera. It's
14 // event handling method is also a convenient place to run the the FG
15 // idle and draw handlers.
16
17 FGManipulator::FGManipulator() :
18     idleHandler(0), drawHandler(0), windowResizeHandler(0), keyHandler(0),
19     mouseClickHandler(0), mouseMotionHandler(0), currentModifiers(0),
20     osgModifiers(0), resizable(true), mouseWarped(false),
21     scrollButtonPressed(false)
22 {
23     using namespace osgGA;
24     
25     keyMaskMap[GUIEventAdapter::KEY_Shift_L]
26         = GUIEventAdapter::MODKEY_LEFT_SHIFT;
27     keyMaskMap[GUIEventAdapter::KEY_Shift_R]
28         = GUIEventAdapter::MODKEY_RIGHT_SHIFT;
29     keyMaskMap[GUIEventAdapter::KEY_Control_L]
30         = GUIEventAdapter::MODKEY_LEFT_CTRL;
31     keyMaskMap[GUIEventAdapter::KEY_Control_R]
32         = GUIEventAdapter::MODKEY_RIGHT_CTRL;
33     keyMaskMap[GUIEventAdapter::KEY_Alt_L] = GUIEventAdapter::MODKEY_LEFT_ALT;
34     keyMaskMap[GUIEventAdapter::KEY_Alt_R] = GUIEventAdapter::MODKEY_RIGHT_ALT;
35     // We have to implement numlock too.
36     numlockKeyMap[GUIEventAdapter::KEY_KP_Insert]  = '0';
37     numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1';
38     numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2';
39     numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = '3';
40     numlockKeyMap[GUIEventAdapter::KEY_KP_Left] = '4';
41     numlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
42     numlockKeyMap[GUIEventAdapter::KEY_KP_Right] = '6';
43     numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7';
44     numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8';
45     numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9';
46 }
47
48 void FGManipulator::setByMatrix(const osg::Matrixd& matrix)
49 {
50     // Yuck
51     position = matrix.getTrans();
52     attitude = matrix.getRotate();
53 }
54
55 osg::Matrixd FGManipulator::getMatrix() const
56 {
57     return osg::Matrixd::rotate(attitude) * osg::Matrixd::translate(position);
58 }
59
60 osg::Matrixd FGManipulator::getInverseMatrix() const
61 {
62     return (osg::Matrixd::translate(-position)
63             * osg::Matrixd::rotate(attitude.inverse())) ;
64 }
65
66 // Not used, but part of the interface.
67 void FGManipulator::setNode(osg::Node* node)
68 {
69     _node = node;
70 }
71     
72 const osg::Node* FGManipulator::getNode() const
73 {
74     return _node.get();
75 }
76
77 osg::Node* FGManipulator::getNode()
78 {
79     return _node.get();
80 }
81
82 // All the usual translation from window system to FG / plib
83 static int osgToFGModifiers(int modifiers)
84 {
85     int result = 0;
86     if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT |
87                      osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT))
88         result |= KEYMOD_SHIFT;
89     if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL |
90                      osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL))
91         result |= KEYMOD_CTRL;
92     if (modifiers & (osgGA::GUIEventAdapter::MODKEY_LEFT_ALT |
93                      osgGA::GUIEventAdapter::MODKEY_RIGHT_ALT))
94         result |= KEYMOD_ALT;
95     return result;
96 }
97
98 void FGManipulator::init(const osgGA::GUIEventAdapter& ea,
99                          osgGA::GUIActionAdapter& us)
100 {
101     currentModifiers = osgToFGModifiers(ea.getModKeyMask());
102     (void)handle(ea, us);
103 }
104
105 static bool
106 eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
107                 int& x, int& y)
108 {
109   x = -1;
110   y = -1;
111
112   const osgViewer::Viewer* viewer;
113   viewer = dynamic_cast<const osgViewer::Viewer*>(&us);
114   if (!viewer)
115       return false;
116
117   float lx, ly;
118   const osg::Camera* camera;
119   camera = viewer->getCameraContainingPosition(ea.getX(), ea.getY(), lx, ly);
120
121   if (!fgOSIsMainCamera(camera))
122       return false;
123
124   x = int(lx);
125   y = int(camera->getViewport()->height() - ly);
126
127   return true;
128 }
129
130 bool FGManipulator::handle(const osgGA::GUIEventAdapter& ea,
131                            osgGA::GUIActionAdapter& us)
132 {
133     int x, y;
134     switch (ea.getEventType()) {
135     case osgGA::GUIEventAdapter::FRAME:
136         if (idleHandler)
137             (*idleHandler)();
138         if (drawHandler)
139             (*drawHandler)();
140         mouseWarped = false;
141         return true;
142     case osgGA::GUIEventAdapter::KEYDOWN:
143     case osgGA::GUIEventAdapter::KEYUP:
144     {
145         int key, modmask;
146         handleKey(ea, key, modmask);
147         eventToViewport(ea, us, x, y);
148         if (keyHandler)
149             (*keyHandler)(key, modmask, x, y);
150         return true;
151     }
152     case osgGA::GUIEventAdapter::PUSH:
153     case osgGA::GUIEventAdapter::RELEASE:
154     {
155         bool mainWindow = eventToViewport(ea, us, x, y);
156         int button = 0;
157         switch (ea.getButton()) {
158         case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
159             button = 0;
160             break;
161         case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
162             button = 1;
163             break;
164         case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
165             button = 2;
166             break;
167         }
168         if (mouseClickHandler)
169             (*mouseClickHandler)(button,
170                                  (ea.getEventType()
171                                   == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea);
172         return true;
173     }
174     case osgGA::GUIEventAdapter::SCROLL:
175     {
176         bool mainWindow = eventToViewport(ea, us, x, y);
177 #ifdef X_DOUBLE_SCROLL_BUG
178         scrollButtonPressed = !scrollButtonPressed;
179         if (!scrollButtonPressed) // Drop the button release event
180             return true;
181 #endif
182         int button;
183         if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP)
184             button = 3;
185         else
186             button = 4;
187         if (mouseClickHandler) {
188             (*mouseClickHandler)(button, 0, x, y, mainWindow, &ea);
189             (*mouseClickHandler)(button, 1, x, y, mainWindow, &ea);
190         }
191         return true;
192     }
193     case osgGA::GUIEventAdapter::MOVE:
194     case osgGA::GUIEventAdapter::DRAG:
195         // If we warped the mouse, then disregard all pointer motion
196         // events for this frame. We really want to flush the event
197         // queue of mouse events, but don't have the ability to do
198         // that with osgViewer.
199         if (mouseWarped)
200             return true;
201         eventToViewport(ea, us, x, y);
202         if (mouseMotionHandler)
203             (*mouseMotionHandler)(x, y);
204         return true;
205     case osgGA::GUIEventAdapter::RESIZE:
206         if (resizable && windowResizeHandler)
207             (*windowResizeHandler)(ea.getWindowWidth(), ea.getWindowHeight());
208         return true;
209      case osgGA::GUIEventAdapter::CLOSE_WINDOW:
210     case osgGA::GUIEventAdapter::QUIT_APPLICATION:
211         fgOSExit(0);
212         return true;
213     default:
214         return false;
215     }
216 }
217
218 void FGManipulator::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
219                               int& modifiers)
220 {
221     key = ea.getKey();
222     // XXX Probably other translations are needed too.
223     switch (key) {
224     case osgGA::GUIEventAdapter::KEY_Escape: key = 0x1b; break;
225     case osgGA::GUIEventAdapter::KEY_Return: key = '\n'; break;
226     case osgGA::GUIEventAdapter::KEY_BackSpace: key = '\b'; break;
227     case osgGA::GUIEventAdapter::KEY_Delete:   key = 0x7f; break;
228     case osgGA::GUIEventAdapter::KEY_Tab:      key = '\t'; break;
229     case osgGA::GUIEventAdapter::KEY_Left:     key = PU_KEY_LEFT;      break;
230     case osgGA::GUIEventAdapter::KEY_Up:       key = PU_KEY_UP;        break;
231     case osgGA::GUIEventAdapter::KEY_Right:    key = PU_KEY_RIGHT;     break;
232     case osgGA::GUIEventAdapter::KEY_Down:     key = PU_KEY_DOWN;      break;
233     case osgGA::GUIEventAdapter::KEY_Page_Up:   key = PU_KEY_PAGE_UP;   break;
234     case osgGA::GUIEventAdapter::KEY_Page_Down: key = PU_KEY_PAGE_DOWN; break;
235     case osgGA::GUIEventAdapter::KEY_Home:     key = PU_KEY_HOME;      break;
236     case osgGA::GUIEventAdapter::KEY_End:      key = PU_KEY_END;       break;
237     case osgGA::GUIEventAdapter::KEY_Insert:   key = PU_KEY_INSERT;    break;
238     case osgGA::GUIEventAdapter::KEY_F1:       key = PU_KEY_F1;        break;
239     case osgGA::GUIEventAdapter::KEY_F2:       key = PU_KEY_F2;        break;
240     case osgGA::GUIEventAdapter::KEY_F3:       key = PU_KEY_F3;        break;
241     case osgGA::GUIEventAdapter::KEY_F4:       key = PU_KEY_F4;        break;
242     case osgGA::GUIEventAdapter::KEY_F5:       key = PU_KEY_F5;        break;
243     case osgGA::GUIEventAdapter::KEY_F6:       key = PU_KEY_F6;        break;
244     case osgGA::GUIEventAdapter::KEY_F7:       key = PU_KEY_F7;        break;
245     case osgGA::GUIEventAdapter::KEY_F8:       key = PU_KEY_F8;        break;
246     case osgGA::GUIEventAdapter::KEY_F9:       key = PU_KEY_F9;        break;
247     case osgGA::GUIEventAdapter::KEY_F10:      key = PU_KEY_F10;       break;
248     case osgGA::GUIEventAdapter::KEY_F11:      key = PU_KEY_F11;       break;
249     case osgGA::GUIEventAdapter::KEY_F12:      key = PU_KEY_F12;       break;
250     case osgGA::GUIEventAdapter::KEY_KP_Delete: key = '.'; break;
251     case osgGA::GUIEventAdapter::KEY_KP_Enter: key = '\r'; break;
252     case osgGA::GUIEventAdapter::KEY_KP_Add:   key = '+'; break;
253     case osgGA::GUIEventAdapter::KEY_KP_Divide: key = '/'; break;
254     case osgGA::GUIEventAdapter::KEY_KP_Multiply: key = '*'; break;
255     case osgGA::GUIEventAdapter::KEY_KP_Subtract: key = '-'; break;
256     }
257     osgGA::GUIEventAdapter::EventType eventType = ea.getEventType();
258     std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
259
260     if (numPadIter != numlockKeyMap.end()) {
261         if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK) {
262             key = numPadIter->second;
263         }
264     } else {
265         // Track the modifiers because OSG is currently (2.0) broken
266         KeyMaskMap::iterator iter = keyMaskMap.find(key);
267         if (iter != keyMaskMap.end()) {
268             int mask = iter->second;
269             if (eventType == osgGA::GUIEventAdapter::KEYUP)
270                 osgModifiers &= ~mask;
271             else
272                 osgModifiers |= mask;
273         }
274     }
275     modifiers = osgToFGModifiers(osgModifiers);
276     currentModifiers = modifiers;
277     if (eventType == osgGA::GUIEventAdapter::KEYUP)
278         modifiers |= KEYMOD_RELEASED;
279 }
280