5 XCSoar Glide Computer - http://www.xcsoar.org/
6 Copyright (C) 2000-2013 The XCSoar Project
7 A detailed list of copyright holders can be found in the file "AUTHORS".
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 #include "PopupMessage.hpp"
27 #include "Look/Fonts.hpp"
28 #include "Screen/SingleWindow.hpp"
29 #include "Screen/Layout.hpp"
30 #include "Screen/Font.hpp"
31 #include "LocalPath.hpp"
32 #include "Audio/Sound.hpp"
33 #include "LogFile.hpp"
34 #include "ComputerSettings.hpp"
35 #include "Language/Language.hpp"
36 #include "StatusMessage.hpp"
37 #include "UISettings.hpp"
38 #include "OS/Clock.hpp"
48 PopupMessage::Message::Set(Type _type
, unsigned _tshow
, const TCHAR
*_text
,
59 PopupMessage::Message::Update(unsigned now
)
62 // ignore unknown messages
65 if (IsNewlyExpired(now
))
66 // this message has expired for first time
69 // new message has been added
71 // set new expiry time.
72 texpiry
= now
+ tshow
;
73 // this is a new message..
81 PopupMessage::Message::AppendTo(StaticString
<2000> &buffer
, unsigned now
)
84 // ignore unknown messages
89 // reset expiry so we don't refresh
94 buffer
.append(_T("\r\n"));
99 PopupMessage::PopupMessage(const StatusMessageList
&_status_messages
,
100 SingleWindow
&_parent
, const UISettings
&_settings
)
101 :status_messages(_status_messages
),
110 PopupMessage::Create(const PixelRect _rc
)
114 LargeTextWindowStyle style
;
119 LargeTextWindow::Create(parent
, GetRect(100), style
);
121 SetFont(Fonts::map_bold
);
126 PopupMessage::OnMouseDown(PixelScalar x
, PixelScalar y
)
128 // acknowledge with click/touch
129 Acknowledge(MSG_UNKNOWN
);
135 PopupMessage::GetRect(UPixelScalar height
) const
139 if (settings
.popup_message_position
== UISettings::PopupMessagePosition::TOP_LEFT
) {
142 rthis
.bottom
= height
;
143 rthis
.right
= Layout::FastScale(206);
144 // TODO code: this shouldn't be hard-coded
146 PixelScalar width
=// min((rc.right-rc.left)*0.8,tsize.cx);
147 (PixelScalar
)((rc
.right
- rc
.left
) * 0.9);
148 PixelScalar midx
= (rc
.right
+ rc
.left
) / 2;
149 PixelScalar midy
= (rc
.bottom
+ rc
.top
) / 2;
150 PixelScalar h1
= height
/ 2;
151 PixelScalar h2
= height
- h1
;
152 rthis
.left
= midx
-width
/2;
153 rthis
.right
= midx
+width
/2;
155 rthis
.bottom
= midy
+h2
;
162 PopupMessage::UpdateTextAndLayout(const TCHAR
*text
)
164 if (StringIsEmpty(text
)) {
169 const UPixelScalar font_height
= Fonts::map_bold
.GetHeight();
171 unsigned n_lines
= max(n_visible
, max(1u, GetRowCount()));
173 PixelScalar height
= min((PixelScalar
)((rc
.bottom
-rc
.top
) * 0.8),
174 (PixelScalar
)(font_height
* (n_lines
+ 1)));
176 PixelRect rthis
= GetRect(height
);
178 PixelRect old_rc
= GetPosition();
179 if (rthis
.left
!= old_rc
.left
|| rthis
.right
!= old_rc
.right
) {
180 /* on Windows, the TEXT control can never change its text style
181 after it has been created, so we have to destroy it and
195 PopupMessage::Render()
198 if (parent
.HasDialog()) {
203 const unsigned now
= MonotonicClockMS();
205 // this has to be done quickly, since it happens in GUI thread
206 // at subsecond interval
208 // first loop through all messages, and determine which should be
209 // made invisible that were previously visible, or
212 bool changed
= false;
213 for (unsigned i
= 0; i
< MAXMESSAGES
; ++i
)
214 changed
= messages
[i
].Update(now
) || changed
;
216 static bool doresize
= false;
223 // do one extra resize after display so we are sure we get all
224 // the text (workaround bug in getlinecount)
225 UpdateTextAndLayout(text
);
230 // ok, we've changed the visible messages, so need to regenerate the
236 for (unsigned i
= 0; i
< MAXMESSAGES
; ++i
)
237 if (messages
[i
].AppendTo(text
, now
))
242 UpdateTextAndLayout(text
);
248 PopupMessage::GetEmptySlot()
250 // find oldest message that is no longer visible
252 // todo: make this more robust with respect to message types and if can't
253 // find anything to remove..
255 for (unsigned i
= 0, tmin
= 0; i
< MAXMESSAGES
; i
++) {
256 if (i
== 0 || messages
[i
].tstart
< tmin
) {
257 tmin
= messages
[i
].tstart
;
265 PopupMessage::AddMessage(unsigned tshow
, Type type
, const TCHAR
*Text
)
267 assert(mutex
.IsLockedByCurrent());
269 const unsigned now
= MonotonicClockMS();
271 int i
= GetEmptySlot();
272 messages
[i
].Set(type
, tshow
, Text
, now
);
276 PopupMessage::Repeat(Type type
)
281 const unsigned now
= MonotonicClockMS();
283 // find most recent non-visible message
285 for (unsigned i
= 0, tmax
= 0; i
< MAXMESSAGES
; i
++) {
286 if (messages
[i
].texpiry
< now
&&
287 messages
[i
].tstart
> tmax
&&
288 (messages
[i
].type
== type
|| type
== 0)) {
290 tmax
= messages
[i
].tstart
;
295 messages
[imax
].tstart
= now
;
296 messages
[imax
].texpiry
= messages
[imax
].tstart
;
303 PopupMessage::Acknowledge(Type type
)
305 ScopeLock
protect(mutex
);
306 const unsigned now
= MonotonicClockMS();
308 for (unsigned i
= 0; i
< MAXMESSAGES
; i
++) {
309 if (messages
[i
].texpiry
> messages
[i
].tstart
&&
310 (type
== MSG_UNKNOWN
|| type
== messages
[i
].type
)) {
311 // message was previously visible, so make it expire now.
312 messages
[i
].texpiry
= now
- 1;
319 // DoMessage is designed to delegate what to do for a message
320 // The "what to do" can be defined in a configuration file
321 // Defaults for each message include:
322 // - Text to display (including multiple languages)
323 // - Text to display extra - NOT multiple language
324 // (eg: If Airspace Warning - what details - airfield name is in data file, already
325 // covers multiple languages).
326 // - ShowStatusMessage - including font size and delay
327 // - Sound to play - What sound to play
328 // - Log - Keep the message on the log/history window (goes to log file and history)
330 // TODO code: (need to discuss) Consider moving almost all this functionality into AddMessage ?
333 PopupMessage::AddMessage(const TCHAR
* text
, const TCHAR
*data
)
335 ScopeLock
protect(mutex
);
337 StatusMessage msg
= status_messages
.First();
338 const StatusMessage
*found
= status_messages
.Find(text
);
342 if (enable_sound
&& msg
.sound
!= NULL
)
343 PlayResource(msg
.sound
);
345 // TODO code: consider what is a sensible size?
347 TCHAR msgcache
[1024];
348 _tcscpy(msgcache
, text
);
350 _tcscat(msgcache
, _T(" "));
351 _tcscat(msgcache
, data
);
354 AddMessage(msg
.delay_ms
, MSG_USERINTERFACE
, msgcache
);