FlightGear next
MouseCursor.cxx
Go to the documentation of this file.
1// MouseCursor.cxx - abstract inteface for mouse cursor control
2
3// Copyright (C) 2013 James Turner <zakalawe@mac.com>
4//
5// This program is free software; you can redistribute it and/or
6// modify it under the terms of the GNU General Public License as
7// published by the Free Software Foundation; either version 2 of the
8// License, or (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful, but
11// WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13// General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18//
19
20#ifdef HAVE_CONFIG_H
21 #include "config.h"
22#endif
23
24#include "MouseCursor.hxx"
25
26#include <cstring>
27
28#include <osgViewer/GraphicsWindow>
29#include <osgViewer/Viewer>
30
31#include <simgear/debug/logstream.hxx>
32#include <simgear/simgear_config.h>
33#include <simgear/structure/commands.hxx>
34
35#ifdef SG_MAC
36#include "CocoaMouseCursor.hxx"
37#endif
38
39#ifdef SG_WINDOWS
41#endif
42
43#include <Main/fg_props.hxx>
44#include <Main/globals.hxx>
45#include <Viewer/renderer.hxx>
46#include <Main/fg_os.hxx> // for fgWarpMouse
47
48namespace
49{
50
55class StockOSGCursor : public FGMouseCursor
56{
57public:
58 StockOSGCursor() :
59 mCursorObscured(false),
60 mCursorVisible(true),
61 mCursor(osgViewer::GraphicsWindow::InheritCursor)
62 {
63 mActualCursor = mCursor;
64 }
65
66 virtual void setCursor(Cursor aCursor)
67 {
68 m_currentCursor = aCursor;
69 mCursor = translateCursor(aCursor);
70 updateCursor();
71 }
72
73 virtual void setCursorVisible(bool aVis)
74 {
75 if (mCursorObscured == aVis) {
76 return;
77 }
78
79 mCursorVisible = aVis;
80 updateCursor();
81 }
82
83 virtual void hideCursorUntilMouseMove()
84 {
85 if (mCursorObscured) {
86 return;
87 }
88
89 mCursorObscured = true;
90 updateCursor();
91 }
92
93 virtual void mouseMoved()
94 {
95 if (mCursorObscured) {
96 mCursorObscured = false;
97 updateCursor();
98 }
99 }
100private:
101 osgViewer::GraphicsWindow::MouseCursor translateCursor(Cursor aCursor)
102 {
103 switch (aCursor) {
104 case CURSOR_ARROW: return osgViewer::GraphicsWindow::RightArrowCursor;
105 case CURSOR_HAND: return osgViewer::GraphicsWindow::HandCursor;
106 case CURSOR_CLOSED_HAND: return osgViewer::GraphicsWindow::HandCursor;
107 case CURSOR_CROSSHAIR: return osgViewer::GraphicsWindow::CrosshairCursor;
108 case CURSOR_IBEAM: return osgViewer::GraphicsWindow::TextCursor;
109 case CURSOR_LEFT_RIGHT: return osgViewer::GraphicsWindow::LeftRightCursor;
110 case CURSOR_UP_DOWN: return osgViewer::GraphicsWindow::UpDownCursor;
111
112 case CURSOR_LEFT_SIDE: return osgViewer::GraphicsWindow::LeftSideCursor;
113 case CURSOR_RIGHT_SIDE: return osgViewer::GraphicsWindow::RightSideCursor;
114 case CURSOR_TOP_SIDE: return osgViewer::GraphicsWindow::TopSideCursor;
115 case CURSOR_BOTTOM_SIDE: return osgViewer::GraphicsWindow::BottomSideCursor;
116
117 case CURSOR_TOP_LEFT: return osgViewer::GraphicsWindow::TopLeftCorner;
118 case CURSOR_TOP_RIGHT: return osgViewer::GraphicsWindow::TopRightCorner;
119 case CURSOR_BOTTOM_LEFT: return osgViewer::GraphicsWindow::BottomLeftCorner;
120 case CURSOR_BOTTOM_RIGHT: return osgViewer::GraphicsWindow::BottomRightCorner;
121
122 case CURSOR_WAIT: return osgViewer::GraphicsWindow::WaitCursor;
123
124 default:
125 return osgViewer::GraphicsWindow::RightArrowCursor;
126 }
127 }
128
129 void updateCursor()
130 {
131 auto cur = osgViewer::GraphicsWindow::InheritCursor;
132 if (mCursorObscured || !mCursorVisible) {
133 cur = osgViewer::GraphicsWindow::NoCursor;
134 } else {
135 cur = mCursor;
136 }
137
138 if (cur == mActualCursor) {
139 return;
140 }
141
142 // can happen during shutdown, we call fgSetMouseCursor from fgExitCleanup
143 if (!globals || !globals->get_renderer()) {
144 return;
145 }
146
147 osgViewer::ViewerBase* viewer_base = globals->get_renderer()->getViewerBase();
148 if (!viewer_base)
149 return;
150
151 std::vector<osgViewer::GraphicsWindow*> windows;
152 viewer_base->getWindows(windows);
153
154 for (auto gw : windows) {
155 gw->setCursor(cur);
156 }
157
158 mActualCursor = cur;
159 }
160
161 bool mCursorObscured;
162 bool mCursorVisible;
163 osgViewer::GraphicsWindow::MouseCursor mCursor, mActualCursor;
164};
165
166} // of anonymous namespace
167
169
174
176{
177 if (static_instance == NULL) {
178 #ifdef SG_MAC
179 if (true) {
181 }
182 #endif
183 #ifdef SG_WINDOWS
184 // set osgViewer cursor inherit, otherwise it will interefere
185 std::vector<osgViewer::GraphicsWindow*> gws;
186 globals->get_renderer()->getViewerBase()->getWindows(gws);
187 for (auto gw : gws) {
188 gw->setCursor(osgViewer::GraphicsWindow::InheritCursor);
189 }
190
191 // Windows native curosr disabled while interaction with OSG
192 // is resolved - right now NCHITs (non-client-area hits)
193 // overwire the InheritCursor value above, and hence our cursor
194 // get stuck.
195 // and create our real implementation
196 // static_instance = new WindowsMouseCursor;
197 #endif
198
199 // X11
200
201 if (static_instance == NULL) {
202 static_instance = new StockOSGCursor;
203 }
204
205 // initialise mouse-hide delay from global properties
206
207 globals->get_commands()->addCommand("set-cursor", static_instance, &FGMouseCursor::setCursorCommand);
208 }
209
210 return static_instance;
211}
212
214{
215 mAutoHideTimeMsec = aMsec;
216}
217
222
223bool FGMouseCursor::setCursorCommand(const SGPropertyNode* arg, SGPropertyNode*)
224{
225 // JMT 2013 - I would prefer this was a seperate 'warp' command, but
226 // historically set-cursor has done both.
227 if (arg->hasValue("x") || arg->hasValue("y")) {
228 SGPropertyNode *mx = fgGetNode("/devices/status/mice/mouse/x", true);
229 SGPropertyNode *my = fgGetNode("/devices/status/mice/mouse/y", true);
230 int x = arg->getIntValue("x", mx->getIntValue());
231 int y = arg->getIntValue("y", my->getIntValue());
232 fgWarpMouse(x, y);
233 mx->setIntValue(x);
234 my->setIntValue(y);
235 }
236
237
238 Cursor c = cursorFromString(arg->getStringValue("cursor").c_str());
239 setCursor(c);
240 return true;
241}
242
243typedef struct {
244 const char * name;
247
249 { "inherit", FGMouseCursor::CURSOR_ARROW },
250 { "crosshair", FGMouseCursor::CURSOR_CROSSHAIR },
251 { "left-right", FGMouseCursor::CURSOR_LEFT_RIGHT },
252 { "hand", FGMouseCursor::CURSOR_HAND },
253 { "closed-hand", FGMouseCursor::CURSOR_CLOSED_HAND },
254 { "text", FGMouseCursor::CURSOR_IBEAM },
255
256// aliases
257 { "drag-horizontal", FGMouseCursor::CURSOR_LEFT_RIGHT },
258 { "drag-vertical", FGMouseCursor::CURSOR_UP_DOWN },
260};
261
263{
264 for (unsigned int k = 0; mouse_cursor_map[k].name != 0; k++) {
265 if (!strcmp(mouse_cursor_map[k].name, cursor_name)) {
266 return mouse_cursor_map[k].cursor;
267 }
268 }
269
270 SG_LOG(SG_GENERAL, SG_WARN, "unknown cursor:" << cursor_name);
271 return CURSOR_ARROW;
272}
static std::unique_ptr< FavouriteAircraftData > static_instance
const MouseCursorMap mouse_cursor_map[]
virtual FGRenderer * get_renderer() const
Definition globals.cxx:572
virtual Cursor getCursor() const
unsigned int mAutoHideTimeMsec
virtual void setCursor(Cursor aCursor)=0
virtual void setAutoHideTimeMsec(unsigned int aMsec)
@ CURSOR_HAND
the browser 'link' cursor
@ CURSOR_IBEAM
for editing text
bool setCursorCommand(const SGPropertyNode *arg, SGPropertyNode *)
static FGMouseCursor * instance()
static Cursor cursorFromString(const char *str)
Cursor m_currentCursor
osgViewer::ViewerBase * getViewerBase() const
Definition renderer.cxx:782
const char * name
void fgWarpMouse(int x, int y)
FGGlobals * globals
Definition globals.cxx:142
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
Definition proptest.cpp:27
FGMouseCursor::Cursor cursor
const char * name