/[winpt]/trunk/Src/wptBalloonPop.cpp
ViewVC logotype

Contents of /trunk/Src/wptBalloonPop.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 340 - (show annotations)
Sun Nov 27 13:15:07 2011 UTC (13 years, 3 months ago) by twoaday
File size: 7179 byte(s)


1 /* wptBalloonPop.cpp - Balloon Popup-Box
2 * Copyright (C) 2009 Timo Schulz
3 *
4 * This file is part of WinPT.
5 *
6 * WinPT is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * WinPT is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 */
16
17
18 /* The idea is to use a balloon style 'error message' which
19 points to the control the error happened at. For instance
20 if no valid E-Mail address was entered, the balloon message
21 contains an error description with an arrow to the edit field
22 the address was supposed to be entered in. */
23
24 #include <windows.h>
25 #include <stdio.h>
26 #include <time.h>
27
28 #include "wptTypes.h"
29
30 #define BT_WINDOWNAME "WinPT_BalloonPop"
31 #define BT_TIMER_IDENTIFIER 23
32 #define BT_IOFFSET 8
33
34
35 extern HINSTANCE glob_hinst;
36
37 struct balloon_ctx_s {
38 LPCTSTR text;
39 LPCTSTR icon_name;
40 POINT pos;
41 HWND hwnd;
42 };
43 static struct balloon_ctx_s glob_msg;
44 static BOOL window_class_registered = FALSE;
45
46
47 static void
48 display_balloon_text (HWND hwnd, HDC hdc, const char *text)
49 {
50 RECT rc;
51 memset (&rc, 0, sizeof (rc));
52 GetClientRect(hwnd, &rc);
53
54 POINT pts[3];
55 pts[0].x = rc.left + BT_IOFFSET;
56 pts[0].y = rc.top;
57 pts[1].x = pts[0].x;
58 pts[1].y = pts[0].y + BT_IOFFSET;
59 pts[2].x = pts[1].x + BT_IOFFSET;
60 pts[2].y = pts[1].y;
61
62 // we merge three regions here:
63 // 1) basis
64 // 2) rounded box
65 // 3) arrow
66 HRGN hrgn = CreateRectRgn(0, 0, 0, 0);
67 HRGN hrgn1 = CreateRoundRectRgn(rc.left,
68 rc.top + BT_IOFFSET,
69 rc.right,
70 rc.bottom,
71 15, 15);
72 HRGN hrgn2 = CreatePolygonRgn(&pts[0], 3, ALTERNATE);
73 CombineRgn(hrgn, hrgn1, hrgn2, RGN_OR);
74
75 // fill the region and draw a frame around it
76 FillRgn (hdc, hrgn, GetSysColorBrush(COLOR_INFOBK));
77 FrameRgn (hdc, hrgn, (HBRUSH)GetStockObject (DKGRAY_BRUSH), 1, 1);
78
79 rc.top = rc.top + BT_IOFFSET*2;
80 rc.bottom = rc.bottom - BT_IOFFSET;
81 rc.left = rc.left + BT_IOFFSET;
82 rc.right = rc.right - BT_IOFFSET;
83
84 // FIXME: calculate best position
85 HICON hicon = LoadIcon (NULL, glob_msg.icon_name);
86 if (hicon != NULL) {
87 DrawIconEx (hdc, 5, 20, hicon, 28, 28, 0, NULL, DI_NORMAL);
88 DestroyIcon (hicon);
89 }
90
91 SetTextColor (hdc, GetSysColor (COLOR_INFOTEXT));
92 DrawText (hdc, text, strlen (text), &rc, DT_VCENTER + DT_NOCLIP);
93 }
94
95
96 // window procedure for the balloon tip.
97 static LRESULT CALLBACK
98 window_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
99 {
100 switch (msg) {
101 case WM_PAINT:
102 RECT rc;
103 GetWindowRect (hwnd, &rc);
104
105 POINT curpos;
106 curpos.x = glob_msg.pos.x;
107 curpos.y = glob_msg.pos.y;
108
109 rc.right = curpos.x - BT_IOFFSET + 6 + rc.right - rc.left;
110 rc.bottom = curpos.y + 20 + rc.bottom - rc.top;
111 rc.left = curpos.x - BT_IOFFSET + 6;
112 rc.top = curpos.y + 20;
113 MoveWindow (hwnd, rc.left, rc.top, rc.right - rc.left,
114 rc.bottom - rc.top, FALSE);
115
116 HDC hdc;
117 PAINTSTRUCT ps;
118 hdc = BeginPaint (hwnd, &ps);
119
120 LOGFONT lf;
121 memset (&lf, 0, sizeof (lf));
122 lf.lfHeight = 13;
123 lf.lfWeight = FW_NORMAL;
124 lf.lfQuality = ANTIALIASED_QUALITY;
125 strcpy (lf.lfFaceName, "MS Sans Serif");
126
127 HFONT hfont;
128 hfont = CreateFontIndirect(&lf);
129 HFONT hfont_old;
130 hfont_old = (HFONT)SelectObject(ps.hdc, hfont);
131
132 DrawText (ps.hdc, glob_msg.text, strlen (glob_msg.text),
133 &rc, DT_VCENTER+DT_NOCLIP+DT_CALCRECT);
134 rc.right = rc.right + 2*BT_IOFFSET;
135 rc.bottom = rc.bottom + 3*BT_IOFFSET;
136
137 ShowWindow (hwnd, SW_SHOWNA);
138 MoveWindow(hwnd, rc.left, rc.top, rc.right - rc.left,
139 rc.bottom - rc.top, TRUE);
140 SetBkMode(ps.hdc, TRANSPARENT);
141 display_balloon_text (hwnd, ps.hdc, glob_msg.text);
142
143 // restore old font object
144 SelectObject(ps.hdc, hfont_old);
145 DeleteObject (hfont);
146 EndPaint (hwnd, &ps);
147 break;
148
149 case WM_LBUTTONUP:
150 ShowWindow (hwnd, SW_HIDE);
151 break;
152
153 default:
154 return DefWindowProc (hwnd, msg, wparam, lparam);
155 }
156
157 return FALSE;
158 }
159
160
161 /* Callback procedure to hide the baloon window after the
162 time has been expired */
163 static VOID CALLBACK
164 popup_timer_proc (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
165 {
166 ShowWindow (hwnd, SW_HIDE);
167 }
168
169
170 /* Register our new window class */
171 static void
172 register_window_class (HINSTANCE hinst)
173 {
174 WNDCLASS wclass;
175 memset (&wclass, 0, sizeof (wclass));
176 wclass.style = CS_HREDRAW | CS_VREDRAW;
177 wclass.lpfnWndProc = window_proc;
178 wclass.hInstance = hinst;
179 wclass.lpszClassName = BT_WINDOWNAME;
180
181 if (!RegisterClass (&wclass))
182 abort ();
183 }
184
185
186 static LPCTSTR
187 format_text (LPCTSTR string)
188 {
189 const int off = 12;
190 static char buf[2048];
191 int n = strlen (string), pos=0, i;
192
193 memset (buf, 0, DIM (buf));
194 // FIXME: rewrite the function
195 if (n > 1600)
196 abort ();
197
198 buf[pos++] = '\n';
199 for (i=0; i < off; i++)
200 buf[pos++] = ' ';
201 for (i=0; i < n; i++) {
202 buf[pos++] = string[i];
203 if (string[i] == '\n') {
204 for (int j=0; j < off; j++)
205 buf[pos++] = ' ';
206 }
207 }
208 buf[pos++] = '\n';
209 return buf;
210 }
211
212
213 /* Display a baloon message box at the given X- Y-coordinates */
214 HWND
215 show_balloon_msg_pos (HWND hparwnd, int millis, int x, int y,
216 LPCTSTR string, LPCTSTR icon_name)
217 {
218 if (!window_class_registered) {
219 register_window_class (glob_hinst);
220 window_class_registered = TRUE;
221 }
222
223 // if no icon is requsted, print the text as it is.
224 if (!icon_name)
225 glob_msg.text = string;
226 else
227 glob_msg.text = format_text (string);
228 glob_msg.icon_name = icon_name;
229
230 if (x > 0 && y > 0) { // use specific coordinates
231 glob_msg.pos.x = x;
232 glob_msg.pos.y = y;
233 }
234 else { // point to the lower left region of the control
235 RECT rect;
236 GetWindowRect (hparwnd, &rect);
237 glob_msg.pos.x = rect.left;
238 glob_msg.pos.y = rect.bottom - 20;
239 }
240
241 // we use a persistent window for the balloon messages
242 // instead of destroy/create we hide the window whenever it
243 // is unused.
244 if (!glob_msg.hwnd) {
245 glob_msg.hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
246 BT_WINDOWNAME, BT_WINDOWNAME,
247 WS_POPUP, 1, 1, 1, 1,
248 NULL, NULL, glob_hinst, NULL);
249 if (!glob_msg.hwnd)
250 BUG (0);
251 }
252
253 // ensure 'parent' never loses focus.
254 HWND hwnd = glob_msg.hwnd;
255 ShowWindow (hwnd, SW_SHOW);
256 UpdateWindow (hwnd);
257 EnableWindow (hparwnd, TRUE);
258 SetActiveWindow (NULL);
259
260 // show message for a fixed amount of time
261 SetTimer (hwnd, BT_TIMER_IDENTIFIER, millis, popup_timer_proc);
262
263 return hwnd;
264 }
265
266
267 /* Show message at the default position for 5 seconds */
268 void
269 show_balloon_msg (HWND hparwnd, LPCTSTR string, LPCTSTR icon_name)
270 {
271 show_balloon_msg_pos (hparwnd, 5000, 0, 0, string ,icon_name);
272 }
273
274
275 /* Disable the message box (hide the window) */
276 void
277 balloon_msg_disable (void)
278 {
279 ShowWindow (glob_msg.hwnd, SW_HIDE);
280 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26