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