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 "Language/Language.hpp"
35 #include "StatusMessage.hpp"
36 #include "UISettings.hpp"
37 #include "OS/Clock.hpp"
47 PopupMessage::Message::Set(Type _type
, unsigned _tshow
, const TCHAR
*_text
,
58 PopupMessage::Message::Update(unsigned now
)
61 // ignore unknown messages
64 if (IsNewlyExpired(now
))
65 // this message has expired for first time
68 // new message has been added
70 // set new expiry time.
71 texpiry
= now
+ tshow
;
72 // this is a new message..
80 PopupMessage::Message::AppendTo(StaticString
<2000> &buffer
, unsigned now
)
83 // ignore unknown messages
88 // reset expiry so we don't refresh
93 buffer
.append(_T("\r\n"));
98 PopupMessage::PopupMessage(const StatusMessageList
&_status_messages
,
99 SingleWindow
&_parent
, const UISettings
&_settings
)
100 :status_messages(_status_messages
),
109 PopupMessage::Create(const PixelRect _rc
)
113 LargeTextWindowStyle style
;
118 LargeTextWindow::Create(parent
, GetRect(100), style
);
120 SetFont(Fonts::map_bold
);
125 PopupMessage::OnMouseDown(PixelScalar x
, PixelScalar y
)
127 // acknowledge with click/touch
128 Acknowledge(MSG_UNKNOWN
);
134 PopupMessage::GetRect(UPixelScalar height
) const
138 if (settings
.popup_message_position
== UISettings::PopupMessagePosition::TOP_LEFT
) {
141 rthis
.bottom
= height
;
142 rthis
.right
= Layout::FastScale(206);
143 // TODO code: this shouldn't be hard-coded
145 PixelScalar width
=// min((rc.right-rc.left)*0.8,tsize.cx);
146 (PixelScalar
)((rc
.right
- rc
.left
) * 0.9);
147 PixelScalar midx
= (rc
.right
+ rc
.left
) / 2;
148 PixelScalar midy
= (rc
.bottom
+ rc
.top
) / 2;
149 PixelScalar h1
= height
/ 2;
150 PixelScalar h2
= height
- h1
;
151 rthis
.left
= midx
-width
/2;
152 rthis
.right
= midx
+width
/2;
154 rthis
.bottom
= midy
+h2
;
161 PopupMessage::UpdateTextAndLayout(const TCHAR
*text
)
163 if (StringIsEmpty(text
)) {
168 const UPixelScalar font_height
= Fonts::map_bold
.GetHeight();
170 unsigned n_lines
= max(n_visible
, max(1u, GetRowCount()));
172 PixelScalar height
= min((PixelScalar
)((rc
.bottom
-rc
.top
) * 0.8),
173 (PixelScalar
)(font_height
* (n_lines
+ 1)));
175 PixelRect rthis
= GetRect(height
);
177 PixelRect old_rc
= GetPosition();
178 if (rthis
.left
!= old_rc
.left
|| rthis
.right
!= old_rc
.right
) {
179 /* on Windows, the TEXT control can never change its text style
180 after it has been created, so we have to destroy it and
194 PopupMessage::Render()
197 if (parent
.HasDialog()) {
202 const unsigned now
= MonotonicClockMS();
204 // this has to be done quickly, since it happens in GUI thread
205 // at subsecond interval
207 // first loop through all messages, and determine which should be
208 // made invisible that were previously visible, or
211 bool changed
= false;
212 for (unsigned i
= 0; i
< MAXMESSAGES
; ++i
)
213 changed
= messages
[i
].Update(now
) || changed
;
215 static bool doresize
= false;
222 // do one extra resize after display so we are sure we get all
223 // the text (workaround bug in getlinecount)
224 UpdateTextAndLayout(text
);
229 // ok, we've changed the visible messages, so need to regenerate the
235 for (unsigned i
= 0; i
< MAXMESSAGES
; ++i
)
236 if (messages
[i
].AppendTo(text
, now
))
241 UpdateTextAndLayout(text
);
247 PopupMessage::GetEmptySlot()
249 // find oldest message that is no longer visible
251 // todo: make this more robust with respect to message types and if can't
252 // find anything to remove..
254 for (unsigned i
= 0, tmin
= 0; i
< MAXMESSAGES
; i
++) {
255 if (i
== 0 || messages
[i
].tstart
< tmin
) {
256 tmin
= messages
[i
].tstart
;
264 PopupMessage::AddMessage(unsigned tshow
, Type type
, const TCHAR
*Text
)
266 assert(mutex
.IsLockedByCurrent());
268 const unsigned now
= MonotonicClockMS();
270 int i
= GetEmptySlot();
271 messages
[i
].Set(type
, tshow
, Text
, now
);
275 PopupMessage::Repeat(Type type
)
280 const unsigned now
= MonotonicClockMS();
282 // find most recent non-visible message
284 for (unsigned i
= 0, tmax
= 0; i
< MAXMESSAGES
; i
++) {
285 if (messages
[i
].texpiry
< now
&&
286 messages
[i
].tstart
> tmax
&&
287 (messages
[i
].type
== type
|| type
== 0)) {
289 tmax
= messages
[i
].tstart
;
294 messages
[imax
].tstart
= now
;
295 messages
[imax
].texpiry
= messages
[imax
].tstart
;
302 PopupMessage::Acknowledge(Type type
)
304 ScopeLock
protect(mutex
);
305 const unsigned now
= MonotonicClockMS();
307 for (unsigned i
= 0; i
< MAXMESSAGES
; i
++) {
308 if (messages
[i
].texpiry
> messages
[i
].tstart
&&
309 (type
== MSG_UNKNOWN
|| type
== messages
[i
].type
)) {
310 // message was previously visible, so make it expire now.
311 messages
[i
].texpiry
= now
- 1;
318 // DoMessage is designed to delegate what to do for a message
319 // The "what to do" can be defined in a configuration file
320 // Defaults for each message include:
321 // - Text to display (including multiple languages)
322 // - Text to display extra - NOT multiple language
323 // (eg: If Airspace Warning - what details - airfield name is in data file, already
324 // covers multiple languages).
325 // - ShowStatusMessage - including font size and delay
326 // - Sound to play - What sound to play
327 // - Log - Keep the message on the log/history window (goes to log file and history)
329 // TODO code: (need to discuss) Consider moving almost all this functionality into AddMessage ?
332 PopupMessage::AddMessage(const TCHAR
* text
, const TCHAR
*data
)
334 ScopeLock
protect(mutex
);
336 StatusMessage msg
= status_messages
.First();
337 const StatusMessage
*found
= status_messages
.Find(text
);
341 if (enable_sound
&& msg
.sound
!= NULL
)
342 PlayResource(msg
.sound
);
344 // TODO code: consider what is a sensible size?
346 TCHAR msgcache
[1024];
347 _tcscpy(msgcache
, text
);
349 _tcscat(msgcache
, _T(" "));
350 _tcscat(msgcache
, data
);
353 AddMessage(msg
.delay_ms
, MSG_USERINTERFACE
, msgcache
);