5 XCSoar Glide Computer - http://www.xcsoar.org/
6 Copyright (C) 2000-2012 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 "Protection.hpp"
28 #include "Screen/AnyCanvas.hpp"
29 #include "Screen/Fonts.hpp"
30 #include "Screen/SingleWindow.hpp"
31 #include "Screen/Layout.hpp"
32 #include "LocalPath.hpp"
33 #include "Audio/Sound.hpp"
34 #include "LogFile.hpp"
35 #include "ComputerSettings.hpp"
36 #include "Language/Language.hpp"
37 #include "StatusMessage.hpp"
38 #include "UISettings.hpp"
48 PopupMessage::Message::Set(int _type
, int _tshow
, const TCHAR
*_text
, int now
)
58 PopupMessage::Message::Update(int 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(TCHAR
*buffer
, int now
)
83 // ignore unknown messages
88 // reset expiry so we don't refresh
92 if (buffer
[0] != _T('\0'))
93 _tcscat(buffer
, _T("\r\n"));
94 _tcscat(buffer
, text
);
98 PopupMessage::PopupMessage(const StatusMessageList
&_status_messages
,
99 SingleWindow
&_parent
, const UISettings
&_settings
)
100 :status_messages(_status_messages
),
110 PopupMessage::set(const PixelRect _rc
)
114 EditWindowStyle style
;
121 EditWindow::set(parent
, GetRect(100), style
);
123 set_font(Fonts::map_bold
);
128 PopupMessage::OnMouseDown(PixelScalar x
, PixelScalar y
)
130 // acknowledge with click/touch
137 PopupMessage::GetRect(UPixelScalar height
) const
141 if (settings
.popup_message_position
== UISettings::smAlignTopLeft
){
144 rthis
.bottom
= height
;
145 rthis
.right
= Layout::FastScale(206);
146 // TODO code: this shouldn't be hard-coded
148 PixelScalar width
=// min((rc.right-rc.left)*0.8,tsize.cx);
149 (PixelScalar
)((rc
.right
- rc
.left
) * 0.9);
150 PixelScalar midx
= (rc
.right
+ rc
.left
) / 2;
151 PixelScalar midy
= (rc
.bottom
+ rc
.top
) / 2;
152 PixelScalar h1
= height
/ 2;
153 PixelScalar h2
= height
- h1
;
154 rthis
.left
= midx
-width
/2;
155 rthis
.right
= midx
+width
/2;
157 rthis
.bottom
= midy
+h2
;
164 PopupMessage::Resize()
166 if (*msgText
== _T('\0')) {
172 canvas
.Select(Fonts::map_bold
);
173 PixelSize tsize
= canvas
.CalcTextSize(msgText
);
175 int linecount
= max((unsigned)nvisible
, max((unsigned)1, get_row_count()));
177 PixelScalar height
= min((PixelScalar
)((rc
.bottom
-rc
.top
) * 0.8),
178 (PixelScalar
)(tsize
.cy
* (linecount
+ 1)));
180 PixelRect rthis
= GetRect(height
);
182 PixelRect old_rc
= get_position();
183 if (rthis
.left
!= old_rc
.left
|| rthis
.right
!= old_rc
.right
) {
184 /* on Windows, the TEXT control can never change its text style
185 after it has been created, so we have to destroy it and
193 move(rthis
.left
, rthis
.top
,
194 rthis
.right
- rthis
.left
,
195 rthis
.bottom
- rthis
.top
);
201 PopupMessage::Render()
203 if (!globalRunningEvent
.Test())
207 if (parent
.HasDialog()) {
212 int fpsTime
= clock
.Elapsed();
214 // this has to be done quickly, since it happens in GUI thread
215 // at subsecond interval
217 // first loop through all messages, and determine which should be
218 // made invisible that were previously visible, or
221 bool changed
= false;
222 for (unsigned i
= 0; i
< MAXMESSAGES
; ++i
)
223 changed
= messages
[i
].Update(fpsTime
) || changed
;
225 static bool doresize
= false;
232 // do one extra resize after display so we are sure we get all
233 // the text (workaround bug in getlinecount)
239 // ok, we've changed the visible messages, so need to regenerate the
243 msgText
[0] = _T('\0');
245 for (unsigned i
= 0; i
< MAXMESSAGES
; ++i
)
246 if (messages
[i
].AppendTo(msgText
, fpsTime
))
257 PopupMessage::GetEmptySlot()
259 // find oldest message that is no longer visible
261 // todo: make this more robust with respect to message types and if can't
262 // find anything to remove..
266 for (i
= 0; i
< MAXMESSAGES
; i
++) {
267 if (i
== 0 || messages
[i
].tstart
< tmin
) {
268 tmin
= messages
[i
].tstart
;
276 PopupMessage::AddMessage(int tshow
, int type
, const TCHAR
*Text
)
279 int fpsTime
= clock
.Elapsed();
282 messages
[i
].Set(type
, tshow
, Text
, fpsTime
);
286 PopupMessage::Repeat(int type
)
294 int fpsTime
= clock
.Elapsed();
296 // find most recent non-visible message
298 for (i
= 0; i
< MAXMESSAGES
; i
++) {
299 if (messages
[i
].texpiry
< fpsTime
&&
300 messages
[i
].tstart
> tmax
&&
301 (messages
[i
].type
== type
|| type
== 0)) {
303 tmax
= messages
[i
].tstart
;
308 messages
[imax
].tstart
= fpsTime
;
309 messages
[imax
].texpiry
= messages
[imax
].tstart
;
316 PopupMessage::Acknowledge(int type
)
318 ScopeLock
protect(mutex
);
320 int fpsTime
= clock
.Elapsed();
322 for (i
= 0; i
< MAXMESSAGES
; i
++) {
323 if (messages
[i
].texpiry
> messages
[i
].tstart
&&
324 (type
== 0 || type
== messages
[i
].type
)) {
325 // message was previously visible, so make it expire now.
326 messages
[i
].texpiry
= fpsTime
- 1;
333 // DoMessage is designed to delegate what to do for a message
334 // The "what to do" can be defined in a configuration file
335 // Defaults for each message include:
336 // - Text to display (including multiple languages)
337 // - Text to display extra - NOT multiple language
338 // (eg: If Airspace Warning - what details - airfield name is in data file, already
339 // covers multiple languages).
340 // - ShowStatusMessage - including font size and delay
341 // - Sound to play - What sound to play
342 // - Log - Keep the message on the log/history window (goes to log file and history)
344 // TODO code: (need to discuss) Consider moving almost all this functionality into AddMessage ?
347 PopupMessage::AddMessage(const TCHAR
* text
, const TCHAR
*data
)
349 ScopeLock
protect(mutex
);
351 StatusMessageSTRUCT LocalMessage
= status_messages
.First();
352 const StatusMessageSTRUCT
*found
= status_messages
.Find(text
);
354 LocalMessage
= *found
;
356 if (enable_sound
&& LocalMessage
.doSound
)
357 PlayResource(LocalMessage
.sound
);
359 // TODO code: consider what is a sensible size?
360 TCHAR msgcache
[1024];
361 if (LocalMessage
.doStatus
) {
363 _tcscpy(msgcache
, text
);
365 _tcscat(msgcache
, _T(" "));
366 _tcscat(msgcache
, data
);
369 AddMessage(LocalMessage
.delay_ms
, MSG_USERINTERFACE
, msgcache
);