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