]> cygwin.com Git - cygwin-apps/setup.git/blame - PickView.cc
* res.rc: Move spash icon slightly. Fix copyright.
[cygwin-apps/setup.git] / PickView.cc
CommitLineData
97647369
RC
1/*
2 * Copyright (c) 2002 Robert Collins.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by Robert Collins <robertc@hotmail.com>
13 *
14 */
15
16#include "PickView.h"
2e0aaec9
BD
17#include <algorithm>
18#include <limits.h>
97647369 19#include <commctrl.h>
1789ef54 20#include <shlwapi.h>
97647369
RC
21#include "PickPackageLine.h"
22#include "PickCategoryLine.h"
23#include "package_db.h"
24#include "package_version.h"
25#include "dialog.h"
26#include "resource.h"
693916f8
RC
27/* For 'source' */
28#include "state.h"
29#include "LogSingleton.h"
97647369 30
6625e635 31using namespace std;
97647369
RC
32
33static PickView::Header pkg_headers[] = {
82306ac2
BD
34 {"Current", 0, 0, true},
35 {"New", 0, 0, true},
36 {"Bin?", 0, 0, false},
37 {"Src?", 0, 0, false},
38 {"Categories", 0, 0, true},
0ac305ec 39 {"Size", 0, 0, true},
82306ac2
BD
40 {"Package", 0, 0, true},
41 {0, 0, 0, false}
97647369
RC
42};
43
44static PickView::Header cat_headers[] = {
82306ac2
BD
45 {"Category", 0, 0, true},
46 {"Current", 0, 0, true},
47 {"New", 0, 0, true},
48 {"Bin?", 0, 0, false},
49 {"Src?", 0, 0, false},
0ac305ec 50 {"Size", 0, 0, true},
82306ac2
BD
51 {"Package", 0, 0, true},
52 {0, 0, 0, false}
97647369
RC
53};
54
55// PickView:: views
56const PickView::views PickView::views::Unknown (0);
57const PickView::views PickView::views::PackageFull (1);
e0aec95e
MB
58const PickView::views PickView::views::Package (2);
59const PickView::views PickView::views::PackageKeeps (3);
60const PickView::views PickView::views::PackageSkips = PickView::views (4);
61const PickView::views PickView::views::Category (5);
97647369 62
693916f8
RC
63ATOM PickView::WindowClassAtom = 0;
64
97647369
RC
65// DoInsertItem - inserts an item into a header control.
66// Returns the index of the new item.
67// hwndHeader - handle to the header control.
68// iInsertAfter - index of the previous item.
69// nWidth - width of the new item.
70// lpsz - address of the item string.
71static int
72DoInsertItem (HWND hwndHeader, int iInsertAfter, int nWidth, LPSTR lpsz)
73{
74 HDITEM hdi;
75 int index;
76
77 hdi.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH;
78 hdi.pszText = lpsz;
79 hdi.cxy = nWidth;
80 hdi.cchTextMax = lstrlen (hdi.pszText);
81 hdi.fmt = HDF_LEFT | HDF_STRING;
82
83 index = SendMessage (hwndHeader, HDM_INSERTITEM,
84 (WPARAM) iInsertAfter, (LPARAM) & hdi);
85
86 return index;
87}
88
0baffe9a
DK
89int
90PickView::set_header_column_order (views vm)
97647369 91{
0baffe9a
DK
92 if (vm == views::Unknown)
93 return -1;
94 else if (vm == views::PackageFull || vm == views::Package
95 || vm == views::PackageKeeps || vm == views::PackageSkips)
97647369
RC
96 {
97 headers = pkg_headers;
98 current_col = 0;
99 new_col = 1;
2fa7c5a4
RC
100 bintick_col = new_col + 1;
101 srctick_col = bintick_col + 1;
102 cat_col = srctick_col + 1;
0ac305ec
BD
103 size_col = cat_col + 1;
104 pkg_col = size_col + 1;
931f2755 105 last_col = pkg_col;
97647369 106 }
0baffe9a 107 else if (vm == views::Category)
97647369
RC
108 {
109 headers = cat_headers;
0baffe9a 110 cat_col = 0;
97647369 111 current_col = 1;
2fa7c5a4
RC
112 new_col = current_col + 1;
113 bintick_col = new_col + 1;
114 srctick_col = bintick_col + 1;
0ac305ec
BD
115 size_col = srctick_col + 1;
116 pkg_col = size_col + 1;
2fa7c5a4 117 last_col = pkg_col;
97647369
RC
118 }
119 else
0baffe9a
DK
120 return -1;
121 return last_col;
122}
123
124void
125PickView::set_headers ()
126{
127 if (set_header_column_order (view_mode) == -1)
97647369
RC
128 return;
129 while (int n = SendMessage (listheader, HDM_GETITEMCOUNT, 0, 0))
130 {
131 SendMessage (listheader, HDM_DELETEITEM, n - 1, 0);
132 }
133 int i;
134 for (i = 0; i <= last_col; i++)
135 DoInsertItem (listheader, i, headers[i].width, (char *) headers[i].text);
136}
137
138void
d19f12fd
MB
139PickView::note_width (PickView::Header *hdrs, HDC dc,
140 const std::string& string, int addend, int column)
97647369 141{
82306ac2
BD
142 SIZE s = { 0, 0 };
143
144 if (string.size())
145 GetTextExtentPoint32 (dc, string.c_str(), string.size(), &s);
97647369
RC
146 if (hdrs[column].width < s.cx + addend)
147 hdrs[column].width = s.cx + addend;
148}
149
150void
82306ac2 151PickView::cycleViewMode ()
97647369 152{
82306ac2 153 setViewMode (++view_mode);
97647369
RC
154}
155
525531ca 156void
82306ac2 157PickView::setViewMode (views mode)
525531ca 158{
82306ac2
BD
159 view_mode = mode;
160 set_headers ();
525531ca 161 packagedb db;
82306ac2
BD
162
163 contents.empty ();
164 if (view_mode == PickView::views::Category)
525531ca 165 {
82306ac2
BD
166 contents.ShowLabel (true);
167 /* start collapsed. TODO: make this a chooser flag */
168 for (packagedb::categoriesType::iterator n =
169 packagedb::categories.begin(); n != packagedb::categories.end();
170 ++n)
7c593196
IP
171 insert_category (&*n, (*n).first.c_str()[0] == '.'
172 ? CATEGORY_EXPANDED : CATEGORY_COLLAPSED);
525531ca 173 }
82306ac2 174 else
525531ca 175 {
82306ac2
BD
176 contents.ShowLabel (false);
177 // iterate through every package
263157cb 178 for (packagedb::packagecollection::iterator i = db.packages.begin ();
82306ac2
BD
179 i != db.packages.end (); ++i)
180 {
263157cb 181 packagemeta & pkg = *(i->second);
82306ac2
BD
182
183 if ( // "Full" : everything
184 (view_mode == PickView::views::PackageFull)
185
5a2eaf00 186 // "Pending" : packages that are being added/removed/upgraded
82306ac2
BD
187 || (view_mode == PickView::views::Package &&
188 ((!pkg.desired && pkg.installed) || // uninstall
189 (pkg.desired &&
190 (pkg.desired.picked () || // install bin
191 pkg.desired.sourcePackage ().picked ())))) // src
192
193 // "Up to date" : installed packages that will not be changed
194 || (view_mode == PickView::views::PackageKeeps &&
195 (pkg.installed && pkg.desired && !pkg.desired.picked ()
196 && !pkg.desired.sourcePackage ().picked ()))
197
198 // "Not installed"
199 || (view_mode == PickView::views::PackageSkips &&
200 (!pkg.desired && !pkg.installed)))
059906b3
DK
201 {
202 // Filter by package name
203 if (packageFilterString.empty ()
1789ef54 204 || StrStrI (pkg.name.c_str (), packageFilterString.c_str ()))
059906b3
DK
205 insert_pkg (pkg);
206 }
82306ac2 207 }
525531ca
RC
208 }
209
bb8e2353 210 RECT r = GetClientRect ();
525531ca
RC
211 SCROLLINFO si;
212 memset (&si, 0, sizeof (si));
213 si.cbSize = sizeof (si);
214 si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
215 si.nMin = 0;
216 si.nMax = headers[last_col].x + headers[last_col].width; // + HMARGIN;
217 si.nPage = r.right;
218 SetScrollInfo (GetHWND(), SB_HORZ, &si, TRUE);
219
220 si.nMax = contents.itemcount () * row_height;
221 si.nPage = r.bottom - header_height;
222 SetScrollInfo (GetHWND(), SB_VERT, &si, TRUE);
223
224 scroll_ulc_x = scroll_ulc_y = 0;
225
226 InvalidateRect (GetHWND(), &r, TRUE);
227}
228
97647369
RC
229const char *
230PickView::mode_caption ()
231{
232 return view_mode.caption ();
233}
234
235const char *
236PickView::views::caption ()
237{
238 switch (_value)
239 {
240 case 1:
241 return "Full";
242 case 2:
5a2eaf00 243 return "Pending";
97647369 244 case 3:
e0aec95e
MB
245 return "Up To Date";
246 case 4:
247 return "Not Installed";
248 case 5:
97647369
RC
249 return "Category";
250 default:
251 return "";
252 }
253}
254
82306ac2
BD
255/* meant to be called on packagemeta::categories */
256bool
d19f12fd 257isObsolete (set <std::string, casecompare_lt_op> &categories)
82306ac2 258{
d19f12fd 259 set <std::string, casecompare_lt_op>::const_iterator i;
82306ac2
BD
260
261 for (i = categories.begin (); i != categories.end (); ++i)
262 if (isObsolete (*i))
263 return true;
264 return false;
265}
266
267bool
d19f12fd 268isObsolete (const std::string& catname)
82306ac2 269{
afa76033
MB
270 if (casecompare(catname, "ZZZRemovedPackages") == 0
271 || casecompare(catname, "_", 1) == 0)
82306ac2
BD
272 return true;
273 return false;
274}
275
276/* Sets the mode for showing/hiding obsolete junk packages. */
277void
278PickView::setObsolete (bool doit)
279{
280 showObsolete = doit;
281 refresh ();
282}
283
284
97647369
RC
285void
286PickView::insert_pkg (packagemeta & pkg)
287{
82306ac2
BD
288 if (!showObsolete && isObsolete (pkg.categories))
289 return;
290
97647369
RC
291 if (view_mode != views::Category)
292 {
49cf3899 293 PickLine & line = *new PickPackageLine (*this, pkg);
97647369
RC
294 contents.insert (line);
295 }
296 else
297 {
d19f12fd 298 for (set <std::string, casecompare_lt_op>::const_iterator x
405d7186 299 = pkg.categories.begin (); x != pkg.categories.end (); ++x)
97647369 300 {
405d7186 301 // Special case - yuck
afa76033 302 if (casecompare(*x, "All") == 0)
405d7186
RC
303 continue;
304
82306ac2 305 packagedb db;
405d7186 306 PickCategoryLine & catline =
82306ac2 307 *new PickCategoryLine (*this, *db.categories.find (*x), 1);
405d7186
RC
308 PickLine & line = *new PickPackageLine(*this, pkg);
309 catline.insert (line);
310 contents.insert (catline);
97647369
RC
311 }
312 }
313}
314
315void
82306ac2 316PickView::insert_category (Category *cat, bool collapsed)
97647369 317{
0cf68afd 318 // Urk, special case
afa76033 319 if (casecompare(cat->first, "All") == 0 ||
82306ac2 320 (!showObsolete && isObsolete (cat->first)))
97647369
RC
321 return;
322 PickCategoryLine & catline = *new PickCategoryLine (*this, *cat, 1, collapsed);
059906b3 323 int packageCount = 0;
0cf68afd
RC
324 for (vector <packagemeta *>::iterator i = cat->second.begin ();
325 i != cat->second.end () ; ++i)
97647369 326 {
059906b3 327 if (packageFilterString.empty () \
1789ef54
CV
328 || (*i
329 && StrStrI ((*i)->name.c_str (), packageFilterString.c_str ())))
059906b3
DK
330 {
331 PickLine & line = *new PickPackageLine (*this, **i);
332 catline.insert (line);
333 packageCount++;
334 }
97647369 335 }
059906b3
DK
336
337 if (packageFilterString.empty () || packageCount)
338 contents.insert (catline);
339 else
340 delete &catline;
97647369
RC
341}
342
97647369
RC
343PickView::views&
344PickView::views::operator++ ()
345{
346 ++_value;
347 if (_value > Category._value)
348 _value = 1;
349 return *this;
350}
351
352int
353PickView::click (int row, int x)
354{
355 return contents.click (0, row, x);
356}
357
358
359void
82306ac2 360PickView::scroll (HWND hwnd, int which, int *var, int code, int howmany = 1)
97647369
RC
361{
362 SCROLLINFO si;
363 si.cbSize = sizeof (si);
e0aec95e 364 si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
97647369
RC
365 GetScrollInfo (hwnd, which, &si);
366
367 switch (code)
368 {
369 case SB_THUMBTRACK:
370 si.nPos = si.nTrackPos;
371 break;
372 case SB_THUMBPOSITION:
373 break;
374 case SB_BOTTOM:
375 si.nPos = si.nMax;
376 break;
377 case SB_TOP:
378 si.nPos = 0;
379 break;
380 case SB_LINEDOWN:
82306ac2 381 si.nPos += (row_height * howmany);
97647369
RC
382 break;
383 case SB_LINEUP:
82306ac2 384 si.nPos -= (row_height * howmany);
97647369
RC
385 break;
386 case SB_PAGEDOWN:
387 si.nPos += si.nPage * 9 / 10;
388 break;
389 case SB_PAGEUP:
390 si.nPos -= si.nPage * 9 / 10;
391 break;
392 }
393
394 if ((int) si.nPos < 0)
395 si.nPos = 0;
396 if (si.nPos + si.nPage > (unsigned int) si.nMax)
397 si.nPos = si.nMax - si.nPage;
398
399 si.fMask = SIF_POS;
400 SetScrollInfo (hwnd, which, &si, TRUE);
401
402 int ox = scroll_ulc_x;
403 int oy = scroll_ulc_y;
404 *var = si.nPos;
405
406 RECT cr, sr;
693916f8 407 ::GetClientRect (hwnd, &cr);
97647369
RC
408 sr = cr;
409 sr.top += header_height;
410 UpdateWindow (hwnd);
411 ScrollWindow (hwnd, ox - scroll_ulc_x, oy - scroll_ulc_y, &sr, &sr);
412 /*
413 sr.bottom = sr.top;
414 sr.top = cr.top;
415 ScrollWindow (hwnd, ox - scroll_ulc_x, 0, &sr, &sr);
416 */
417 if (ox - scroll_ulc_x)
418 {
693916f8 419 ::GetClientRect (listheader, &cr);
97647369
RC
420 sr = cr;
421// UpdateWindow (htmp);
693916f8 422 ::MoveWindow (listheader, -scroll_ulc_x, 0,
97647369
RC
423 headers[last_col].x +
424 headers[last_col].width, header_height, TRUE);
425 }
426 UpdateWindow (hwnd);
427}
428
82306ac2
BD
429/* this means to make the 'category' column wide enough to fit the first 'n'
430 categories for each package. */
431#define NUM_CATEGORY_COL_WIDTH 2
432
97647369
RC
433void
434PickView::init_headers (HDC dc)
435{
436 int i;
437
438 for (i = 0; headers[i].text; i++)
439 {
440 headers[i].width = 0;
441 headers[i].x = 0;
442 }
443
82306ac2 444 // accomodate widths of the 'bin' and 'src' checkbox columns
8300be9c
MB
445 // FIXME: What's up with the "0"? It's probably a mistake, and should be
446 // "". It used to be written as 0, and was subject to a bizarre implicit
447 // conversion by the unwise String(int) constructor.
448 note_width (headers, dc, "0", HMARGIN + 11, bintick_col);
449 note_width (headers, dc, "0", HMARGIN + 11, srctick_col);
82306ac2
BD
450
451 // accomodate the width of each category name
97647369 452 packagedb db;
0cf68afd
RC
453 for (packagedb::categoriesType::iterator n = packagedb::categories.begin();
454 n != packagedb::categories.end(); ++n)
82306ac2
BD
455 {
456 if (!showObsolete && isObsolete (n->first))
457 continue;
458 note_width (headers, dc, n->first, HMARGIN, cat_col);
459 }
460
461 /* For each package, accomodate the width of the installed version in the
462 current_col, the widths of all other versions in the new_col, and the
463 width of the sdesc for the pkg_col. Also, if this is not a Category
464 view, adjust the 'category' column so that the first NUM_CATEGORY_COL_WIDTH
465 categories from each package fits. */
263157cb 466 for (packagedb::packagecollection::iterator n = db.packages.begin ();
cfae3b8d 467 n != db.packages.end (); ++n)
97647369 468 {
263157cb 469 packagemeta & pkg = *(n->second);
82306ac2
BD
470 if (!showObsolete && isObsolete (pkg.categories))
471 continue;
97647369 472 if (pkg.installed)
3c196821 473 note_width (headers, dc, pkg.installed.Canonical_version (),
97647369 474 HMARGIN, current_col);
82306ac2
BD
475 for (set<packageversion>::iterator i = pkg.versions.begin ();
476 i != pkg.versions.end (); ++i)
0ac305ec
BD
477 {
478 if (*i != pkg.installed)
479 note_width (headers, dc, i->Canonical_version (),
480 HMARGIN + SPIN_WIDTH, new_col);
d19f12fd 481 std::string z = format_1000s(packageversion(*i).source ()->size);
0ac305ec
BD
482 note_width (headers, dc, z, HMARGIN, size_col);
483 z = format_1000s(packageversion(i->sourcePackage ()).source ()->size);
484 note_width (headers, dc, z, HMARGIN, size_col);
485 }
d19f12fd 486 std::string s = pkg.name;
3c054baf 487 if (pkg.SDesc ().size())
d19f12fd 488 s += std::string (": ") + std::string(pkg.SDesc ());
3c054baf 489 note_width (headers, dc, s, HMARGIN, pkg_col);
82306ac2
BD
490
491 if (view_mode != PickView::views::Category && pkg.categories.size () > 2)
492 {
d19f12fd
MB
493 std::string compound_cat("");
494 std::set<std::string, casecompare_lt_op>::const_iterator cat;
82306ac2
BD
495 size_t cnt;
496
497 for (cnt = 0, cat = pkg.categories.begin ();
498 cnt < NUM_CATEGORY_COL_WIDTH && cat != pkg.categories.end ();
499 ++cat)
500 {
afa76033 501 if (casecompare(*cat, "All") == 0)
82306ac2
BD
502 continue;
503 if (compound_cat.size ())
504 compound_cat += ", ";
505 compound_cat += *cat;
506 cnt++;
507 }
508 note_width (headers, dc, compound_cat, HMARGIN, cat_col);
509 }
97647369 510 }
82306ac2
BD
511
512 // ensure that the new_col is wide enough for all the labels
513 const char *captions[] = { "Uninstall", "Skip", "Reinstall", "Retrieve",
514 "Source", "Keep", NULL };
515 for (int i = 0; captions[i]; i++)
516 note_width (headers, dc, captions[i], HMARGIN + SPIN_WIDTH, new_col);
517
518 // finally, compute the actual x values based on widths
97647369
RC
519 headers[0].x = 0;
520 for (i = 1; i <= last_col; i++)
521 headers[i].x = headers[i - 1].x + headers[i - 1].width;
0baffe9a
DK
522 // and allow for resizing to ensure the last column reaches
523 // all the way to the end of the chooser box.
524 headers[last_col].width += total_delta_x;
97647369
RC
525}
526
527
693916f8 528PickView::PickView (Category &cat) : deftrust (TRUST_UNKNOWN),
82306ac2 529contents (*this, cat, 0, false, true), showObsolete (false),
325bb73a 530packageFilterString (), hasWindowRect (false), total_delta_x (0)
97647369 531{
693916f8 532}
97647369 533
693916f8
RC
534void
535PickView::init(views _mode)
536{
537 HDC dc = GetDC (GetHWND());
97647369
RC
538 sysfont = GetStockObject (DEFAULT_GUI_FONT);
539 SelectObject (dc, sysfont);
540 GetTextMetrics (dc, &tm);
541
542 bitmap_dc = CreateCompatibleDC (dc);
82306ac2
BD
543#define LI(x) LoadImage (hinstance, MAKEINTRESOURCE (x), IMAGE_BITMAP, 0, 0, 0);
544 bm_spin = LI (IDB_SPIN);
545 bm_checkyes = LI (IDB_CHECK_YES);
546 bm_checkno = LI (IDB_CHECK_NO);
547 bm_checkna = LI (IDB_CHECK_NA);
548 bm_treeplus = LI (IDB_TREE_PLUS);
549 bm_treeminus = LI (IDB_TREE_MINUS);
550#undef LI
3d4c5ebb
IP
551 icon_dc = CreateCompatibleDC (dc);
552 bm_icon = CreateCompatibleBitmap (dc, 11, 11);
553 SelectObject (icon_dc, bm_icon);
554 rect_icon = CreateRectRgn (0, 0, 11, 11);
97647369
RC
555
556 row_height = (tm.tmHeight + tm.tmExternalLeading + ROW_MARGIN);
82306ac2 557 int irh = tm.tmExternalLeading + tm.tmDescent + 11 + ROW_MARGIN;
97647369
RC
558 if (row_height < irh)
559 row_height = irh;
560
97647369
RC
561 HDLAYOUT hdl;
562 WINDOWPOS wp;
563
564 // Ensure that the common control DLL is loaded, and then create
565 // the header control.
82306ac2
BD
566 INITCOMMONCONTROLSEX controlinfo = { sizeof (INITCOMMONCONTROLSEX),
567 ICC_LISTVIEW_CLASSES };
97647369
RC
568 InitCommonControlsEx (&controlinfo);
569
570 if ((listheader = CreateWindowEx (0, WC_HEADER, (LPCTSTR) NULL,
571 WS_CHILD | WS_BORDER | CCS_NORESIZE |
572 // | HDS_BUTTONS
693916f8 573 HDS_HORZ, 0, 0, 0, 0, GetHWND(),
97647369
RC
574 (HMENU) IDC_CHOOSE_LISTHEADER, hinstance,
575 (LPVOID) NULL)) == NULL)
576 // FIXME: throw an exception
577 exit (10);
578
579 // Retrieve the bounding rectangle of the parent window's
580 // client area, and then request size and position values
581 // from the header control.
bb8e2353 582 RECT rcParent = GetClientRect ();
97647369
RC
583
584 hdl.prc = &rcParent;
585 hdl.pwpos = &wp;
586 if (!SendMessage (listheader, HDM_LAYOUT, 0, (LPARAM) & hdl))
587 // FIXME: throw an exception
588 exit (11);
589
09130e58
RC
590 // Set the font of the listheader, but don't redraw, because its not shown
591 // yet.This message does not return a value, so we are not checking it as we
592 // do above.
593 SendMessage (listheader, WM_SETFONT, (WPARAM) sysfont, FALSE);
97647369
RC
594
595 // Set the size, position, and visibility of the header control.
596 SetWindowPos (listheader, wp.hwndInsertAfter, wp.x, wp.y,
597 wp.cx, wp.cy, wp.flags | SWP_SHOWWINDOW);
598
599 header_height = wp.cy;
82306ac2 600 ReleaseDC (GetHWND (), dc);
97647369
RC
601
602 view_mode = _mode;
82306ac2 603 refresh ();
97647369 604}
49cf3899
RC
605
606PickView::~PickView()
607{
3d4c5ebb
IP
608 DeleteDC (bitmap_dc);
609 DeleteObject (bm_spin);
610 DeleteObject (bm_checkyes);
611 DeleteObject (bm_checkno);
612 DeleteObject (bm_checkna);
613 DeleteObject (bm_treeplus);
614 DeleteObject (bm_treeminus);
615 DeleteObject (rect_icon);
616 DeleteObject (bm_icon);
617 DeleteDC (icon_dc);
49cf3899 618}
693916f8
RC
619
620bool PickView::registerWindowClass ()
621{
622 if (WindowClassAtom != 0)
623 return true;
624
625 // We're not registered yet
626 WNDCLASSEX wc;
627
628 wc.cbSize = sizeof (wc);
629 // Some sensible style defaults
630 wc.style = CS_HREDRAW | CS_VREDRAW;
631 // Our default window procedure. This replaces itself
632 // on the first call with the simpler Window::WindowProcReflector().
633 wc.lpfnWndProc = Window::FirstWindowProcReflector;
634 // No class bytes
635 wc.cbClsExtra = 0;
636 // One pointer to REFLECTION_INFO in the extra window instance bytes
637 wc.cbWndExtra = 4;
638 // The app instance
639 wc.hInstance = hinstance; //GetInstance ();
640 // Use a bunch of system defaults for the GUI elements
641 wc.hIcon = LoadIcon (0, IDI_APPLICATION);
642 wc.hIconSm = NULL;
643 wc.hCursor = LoadCursor (0, IDC_ARROW);
82306ac2 644 wc.hbrBackground = NULL;
693916f8
RC
645 // No menu
646 wc.lpszMenuName = NULL;
647 // We'll get a little crazy here with the class name
648 wc.lpszClassName = "listview";
649
650 // All set, try to register
651 WindowClassAtom = RegisterClassEx (&wc);
652 if (WindowClassAtom == 0)
653 log (LOG_BABBLE) << "Failed to register listview " << GetLastError () << endLog;
654 return WindowClassAtom != 0;
655}
656
657LRESULT CALLBACK
658PickView::list_vscroll (HWND hwnd, HWND hctl, UINT code, int pos)
659{
d2be933d 660 scroll (hwnd, SB_VERT, &scroll_ulc_y, code);
693916f8
RC
661 return 0;
662}
663
664LRESULT CALLBACK
665PickView::list_hscroll (HWND hwnd, HWND hctl, UINT code, int pos)
666{
d2be933d 667 scroll (hwnd, SB_HORZ, &scroll_ulc_x, code);
693916f8
RC
668 return 0;
669}
670
325bb73a
DK
671void
672PickView::set_vscroll_info (const RECT &r)
673{
674 SCROLLINFO si;
675 memset (&si, 0, sizeof (si));
676 si.cbSize = sizeof (si);
677 si.fMask = SIF_ALL | SIF_DISABLENOSCROLL; /* SIF_RANGE was giving strange behaviour */
678 si.nMin = 0;
679
680 si.nMax = contents.itemcount () * row_height;
681 si.nPage = r.bottom - header_height;
682
683 /* if we are under the minimum display count ,
684 * set the offset to 0
685 */
686 if ((unsigned int) si.nMax <= si.nPage)
687 scroll_ulc_y = 0;
688 si.nPos = scroll_ulc_y;
689
690 SetScrollInfo (GetHWND(), SB_VERT, &si, TRUE);
691}
692
693916f8
RC
693LRESULT CALLBACK
694PickView::list_click (HWND hwnd, BOOL dblclk, int x, int y, UINT hitCode)
695{
696 int row, refresh;
697
d2be933d 698 if (contents.itemcount () == 0)
693916f8
RC
699 return 0;
700
d2be933d 701 if (y < header_height)
693916f8 702 return 0;
d2be933d
RC
703 x += scroll_ulc_x;
704 y += scroll_ulc_y - header_height;
693916f8 705
d2be933d 706 row = (y + ROW_MARGIN / 2) / row_height;
693916f8 707
d2be933d 708 if (row < 0 || row >= contents.itemcount ())
693916f8
RC
709 return 0;
710
d2be933d 711 refresh = click (row, x);
693916f8 712
325bb73a 713 // XXX we need a method to query the database to see if more
693916f8
RC
714 // than just one package has changed! Until then...
715#if 0
716 if (refresh)
717 {
718#endif
bb8e2353 719 RECT r = GetClientRect ();
325bb73a 720 set_vscroll_info (r);
9c9cfce7 721 InvalidateRect (GetHWND(), &r, TRUE);
693916f8
RC
722#if 0
723 }
724 else
725 {
726 RECT rect;
727 rect.left =
d2be933d 728 headers[new_col].x - scroll_ulc_x;
693916f8 729 rect.right =
d2be933d 730 headers[src_col + 1].x - scroll_ulc_x;
693916f8 731 rect.top =
d2be933d
RC
732 header_height + row * row_height -
733 scroll_ulc_y;
734 rect.bottom = rect.top + row_height;
693916f8
RC
735 InvalidateRect (hwnd, &rect, TRUE);
736 }
737#endif
738 return 0;
739}
740
741/*
742 * LRESULT CALLBACK
743 * PickView::listview_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
744 */
745LRESULT
746PickView::WindowProc (UINT message, WPARAM wParam, LPARAM lParam)
747{
82306ac2
BD
748 int wheel_notches;
749 UINT wheel_lines;
750
693916f8
RC
751 switch (message)
752 {
753 case WM_HSCROLL:
4875ac88
MB
754 list_hscroll (GetHWND(), (HWND)lParam, LOWORD(wParam), HIWORD(wParam));
755 return 0;
693916f8 756 case WM_VSCROLL:
4875ac88
MB
757 list_vscroll (GetHWND(), (HWND)lParam, LOWORD(wParam), HIWORD(wParam));
758 return 0;
82306ac2
BD
759 case WM_MOUSEWHEEL:
760 // this is how many 'notches' the wheel scrolled, forward/up = positive
761 wheel_notches = GET_WHEEL_DELTA_WPARAM(wParam) / 120;
762
763 // determine how many lines the user has configred for a mouse scroll
764 SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &wheel_lines, 0);
765
766 if (wheel_lines == 0) // do no scrolling
767 return 0;
768 else if (wheel_lines == WHEEL_PAGESCROLL)
769 scroll (GetHWND (), SB_VERT, &scroll_ulc_y, (wheel_notches > 0) ?
770 SB_PAGEUP : SB_PAGEDOWN);
771 else
772 scroll (GetHWND (), SB_VERT, &scroll_ulc_y, (wheel_notches > 0) ?
773 SB_LINEUP : SB_LINEDOWN, wheel_lines * abs (wheel_notches));
774 return 0; // handled
693916f8 775 case WM_LBUTTONDOWN:
4875ac88
MB
776 list_click (GetHWND(), FALSE, LOWORD(lParam), HIWORD(lParam), wParam);
777 return 0;
693916f8
RC
778 case WM_PAINT:
779 paint (GetHWND());
780 return 0;
781 case WM_NOTIFY:
782 {
82306ac2
BD
783 // pnmh = (LPNMHDR) lParam
784 LPNMHEADER phdr = (LPNMHEADER) lParam;
785 switch (phdr->hdr.code)
786 {
787 case HDN_ITEMCHANGED:
788 if (phdr->hdr.hwndFrom == ListHeader ())
789 {
790 if (phdr->pitem && phdr->pitem->mask & HDI_WIDTH)
791 headers[phdr->iItem].width = phdr->pitem->cxy;
792
793 for (int i = 1; i <= last_col; i++)
794 headers[i].x = headers[i - 1].x + headers[i - 1].width;
795
796 RECT r = GetClientRect ();
797 SCROLLINFO si;
798 si.cbSize = sizeof (si);
799 si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
800 GetScrollInfo (GetHWND(), SB_HORZ, &si);
801
802 int oldMax = si.nMax;
803 si.nMax = headers[last_col].x + headers[last_col].width;
804 if (si.nTrackPos && oldMax > si.nMax)
805 si.nTrackPos += si.nMax - oldMax;
806
807 si.nPage = r.right;
808 SetScrollInfo (GetHWND(), SB_HORZ, &si, TRUE);
809 InvalidateRect (GetHWND(), &r, TRUE);
810 if (si.nTrackPos && oldMax > si.nMax)
811 scroll (GetHWND(), SB_HORZ, &scroll_ulc_x, SB_THUMBTRACK);
812 }
813 break;
814 }
815 }
816 break;
ee91d9be
RC
817 case WM_SIZE:
818 {
819 // Note: WM_SIZE msgs only appear when 'just' scrolling the window
325bb73a 820 RECT windowRect = GetWindowRect ();
325bb73a 821 if (hasWindowRect)
82306ac2
BD
822 {
823 int dx;
325bb73a
DK
824 if ((dx = windowRect.right - windowRect.left -
825 lastWindowRect.width ()) != 0)
82306ac2 826 {
0baffe9a
DK
827 cat_headers[set_header_column_order (views::Category)].width += dx;
828 pkg_headers[set_header_column_order (views::Package)].width += dx;
829 set_header_column_order (view_mode);
82306ac2
BD
830 set_headers ();
831 ::MoveWindow (listheader, -scroll_ulc_x, 0,
832 headers[last_col].x +
833 headers[last_col].width, header_height, TRUE);
0baffe9a 834 total_delta_x += dx;
82306ac2 835 }
325bb73a
DK
836 if (windowRect.bottom - windowRect.top - lastWindowRect.height ())
837 set_vscroll_info (GetClientRect ());
82306ac2
BD
838 }
839 else
325bb73a 840 hasWindowRect = true;
82306ac2 841
325bb73a 842 lastWindowRect = windowRect;
82306ac2 843 return 0;
ee91d9be 844 }
693916f8 845 }
82306ac2
BD
846
847 // default: can't handle this message
848 return DefWindowProc (GetHWND(), message, wParam, lParam);
693916f8
RC
849}
850
3d4c5ebb
IP
851////
852// Turn black into foreground color and white into background color by
853// 1) Filling a square with ~(FG^BG)
854// 2) Blitting the bitmap on it with NOTSRCERASE (white->black; black->FG^BG)
855// 3) Blitting the result on BG with SRCINVERT (white->BG; black->FG)
856void
857PickView::DrawIcon (HDC hdc, int x, int y, HANDLE hIcon)
858{
859 SelectObject (bitmap_dc, hIcon);
860 FillRgn (icon_dc, rect_icon, bg_fg_brush);
861 BitBlt (icon_dc, 0, 0, 11, 11, bitmap_dc, 0, 0, NOTSRCERASE);
862 BitBlt (hdc, x, y, 11, 11, icon_dc, 0, 0, SRCINVERT);
863///////////// On WinNT-based systems, we could've done the below instead
864///////////// See http://support.microsoft.com/default.aspx?scid=kb;en-us;79212
865// SelectObject (hdc, GetSysColorBrush (COLOR_WINDOWTEXT));
866// HBITMAP bm_icon = CreateBitmap (11, 11, 1, 1, NULL);
867// SelectObject (icon_dc, bm_icon);
868// BitBlt (icon_dc, 0, 0, 11, 11, bitmap_dc, 0, 0, SRCCOPY);
869// MaskBlt (hdc, x2, by, 11, 11, bitmap_dc, 0, 0, bm_icon, 0, 0, MAKEROP4 (SRCAND, PATCOPY));
870// DeleteObject (bm_icon);
871}
872
693916f8
RC
873void
874PickView::paint (HWND hwnd)
875{
82306ac2
BD
876 // we want to retrieve the update region before calling BeginPaint,
877 // because after we do that the update region is validated and we can
878 // no longer retrieve it
879 HRGN hUpdRgn = CreateRectRgn (0, 0, 0, 0);
693916f8 880
82306ac2
BD
881 if (GetUpdateRgn (hwnd, hUpdRgn, FALSE) == 0)
882 {
883 // error?
884 return;
885 }
693916f8 886
82306ac2
BD
887 // tell the system that we're going to begin painting our window
888 // it will prevent further WM_PAINT messages from arriving until we're
889 // done, and if any part of our window was invalidated while we are
890 // painting, it will retrigger us so that we can fix it
891 PAINTSTRUCT ps;
892 HDC hdc = BeginPaint (hwnd, &ps);
893
d2be933d 894 SelectObject (hdc, sysfont);
693916f8 895 SetTextColor (hdc, GetSysColor (COLOR_WINDOWTEXT));
3d4c5ebb 896 SetBkColor (hdc, GetSysColor (COLOR_WINDOW));
82306ac2 897 FillRgn (hdc, hUpdRgn, GetSysColorBrush(COLOR_WINDOW));
693916f8 898
3d4c5ebb
IP
899 COLORREF clr = ~GetSysColor (COLOR_WINDOW) ^ GetSysColor (COLOR_WINDOWTEXT);
900 clr = RGB (GetRValue (clr), GetGValue (clr), GetBValue (clr)); // reconvert
901 bg_fg_brush = CreateSolidBrush (clr);
902
693916f8
RC
903 RECT cr;
904 ::GetClientRect (hwnd, &cr);
905
82306ac2
BD
906 int x = cr.left - scroll_ulc_x;
907 int y = cr.top - scroll_ulc_y + header_height;
693916f8 908
82306ac2
BD
909 contents.paint (hdc, hUpdRgn, x, y, 0, (view_mode ==
910 PickView::views::Category) ? 0 : 1);
693916f8 911
d2be933d 912 if (contents.itemcount () == 0)
693916f8
RC
913 {
914 static const char *msg = "Nothing to Install/Update";
915 if (source == IDC_SOURCE_DOWNLOAD)
82306ac2 916 msg = "Nothing to Download";
ee91d9be 917 TextOut (hdc, x + HMARGIN, y, msg, strlen (msg));
693916f8
RC
918 }
919
82306ac2 920 DeleteObject (hUpdRgn);
3d4c5ebb 921 DeleteObject (bg_fg_brush);
693916f8
RC
922 EndPaint (hwnd, &ps);
923}
924
925
926bool
927PickView::Create (Window * parent, DWORD Style, RECT *r)
928{
929
930 // First register the window class, if we haven't already
931 if (!registerWindowClass ())
932 {
933 // Registration failed
934 return false;
935 }
936
82306ac2 937 // Save our parent, we'll probably need it eventually.
693916f8
RC
938 setParent(parent);
939
940 // Create the window instance
82306ac2
BD
941 CreateWindowEx (// Extended Style
942 WS_EX_CLIENTEDGE,
943 // window class atom (name)
944 "listview", //MAKEINTATOM(WindowClassAtom),
945 "listviewwindow", // no title-bar string yet
946 // Style bits
693916f8 947 Style,
82306ac2
BD
948 r ? r->left : CW_USEDEFAULT,
949 r ? r->top : CW_USEDEFAULT,
950 r ? r->right - r->left + 1 : CW_USEDEFAULT,
951 r ? r->bottom - r->top + 1 : CW_USEDEFAULT,
952 // Parent Window
953 parent == NULL ? (HWND)NULL : parent->GetHWND (),
954 // use class menu
955 (HMENU) MAKEINTRESOURCE (IDC_CHOOSE_LIST),
956 // The application instance
957 GetInstance (),
958 // The this ptr, which we'll use to set up
959 // the WindowProc reflection.
693916f8 960 reinterpret_cast<void *>((Window *)this));
693916f8
RC
961 if (GetHWND() == NULL)
962 {
963 log (LOG_BABBLE) << "Failed to create PickView " << GetLastError () << endLog;
964 return false;
965 }
966
967 return true;
968}
22120c90
RC
969
970void
971PickView::defaultTrust (trusts trust)
972{
973 this->deftrust = trust;
974 packagedb db;
263157cb 975 for (packagedb::packagecollection::iterator i = db.packages.begin ();
22120c90
RC
976 i != db.packages.end (); ++i)
977 {
263157cb 978 packagemeta & pkg = *(i->second);
22120c90 979 if (pkg.installed
82306ac2
BD
980 || pkg.categories.find ("Base") != pkg.categories.end ()
981 || pkg.categories.find ("Misc") != pkg.categories.end ())
982 {
983 pkg.desired = pkg.trustp (trust);
984 if (pkg.desired)
985 pkg.desired.pick (pkg.desired.accessible() &&
f38044ff 986 pkg.desired != pkg.installed, &pkg);
82306ac2 987 }
22120c90 988 else
82306ac2 989 pkg.desired = packageversion ();
22120c90 990 }
bb8e2353 991 RECT r = GetClientRect ();
22120c90
RC
992 InvalidateRect (this->GetHWND(), &r, TRUE);
993 // and then do the same for categories with no packages.
994 for (packagedb::categoriesType::iterator n = packagedb::categories.begin();
995 n != packagedb::categories.end(); ++n)
996 if (!n->second.size())
997 {
82306ac2 998 log (LOG_BABBLE) << "Removing empty category " << n->first << endLog;
22120c90
RC
999 packagedb::categories.erase (n++);
1000 }
1001}
ec2dbbf0 1002
82306ac2 1003/* This recalculates all column widths and resets the view */
ec2dbbf0
RC
1004void
1005PickView::refresh()
1006{
82306ac2
BD
1007 HDC dc = GetDC (GetHWND ());
1008
1009 // we must set the font of the DC here, otherwise the width calculations
1010 // will be off because the system will use the wrong font metrics
1011 sysfont = GetStockObject (DEFAULT_GUI_FONT);
1012 SelectObject (dc, sysfont);
1013
1014 // init headers for the current mode
1015 set_headers ();
1016 init_headers (dc);
1017
1018 // save the current mode
1019 views cur_view_mode = view_mode;
1020
1021 // switch to the other type and do those headers
1022 view_mode = (view_mode == PickView::views::Category) ?
1023 PickView::views::PackageFull : PickView::views::Category;
1024 set_headers ();
1025 init_headers (dc);
1026 ReleaseDC (GetHWND (), dc);
1027
1028 view_mode = cur_view_mode;
1029 setViewMode (view_mode);
ec2dbbf0 1030}
This page took 0.158184 seconds and 5 git commands to generate.