2 * Copyright (c) 2002 Robert Collins.
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.
9 * A copy of the GNU General Public License can be found at
12 * Written by Robert Collins <robertc@hotmail.com>
21 #include "PickPackageLine.h"
22 #include "PickCategoryLine.h"
23 #include "package_db.h"
24 #include "package_version.h"
29 #include "LogSingleton.h"
33 static PickView::Header pkg_headers
[] = {
34 {"Current", 0, 0, true},
36 {"Bin?", 0, 0, false},
37 {"Src?", 0, 0, false},
38 {"Categories", 0, 0, true},
40 {"Package", 0, 0, true},
44 static PickView::Header cat_headers
[] = {
45 {"Category", 0, 0, true},
46 {"Current", 0, 0, true},
48 {"Bin?", 0, 0, false},
49 {"Src?", 0, 0, false},
51 {"Package", 0, 0, true},
55 ATOM
PickView::WindowClassAtom
= 0;
57 // DoInsertItem - inserts an item into a header control.
58 // Returns the index of the new item.
59 // hwndHeader - handle to the header control.
60 // iInsertAfter - index of the previous item.
61 // nWidth - width of the new item.
62 // lpsz - address of the item string.
64 DoInsertItem (HWND hwndHeader
, int iInsertAfter
, int nWidth
, LPSTR lpsz
)
69 hdi
.mask
= HDI_TEXT
| HDI_FORMAT
| HDI_WIDTH
;
72 hdi
.cchTextMax
= lstrlen (hdi
.pszText
);
73 hdi
.fmt
= HDF_LEFT
| HDF_STRING
;
75 index
= SendMessage (hwndHeader
, HDM_INSERTITEM
,
76 (WPARAM
) iInsertAfter
, (LPARAM
) & hdi
);
82 PickView::set_header_column_order (views vm
)
84 if (vm
== views::PackageFull
|| vm
== views::PackagePending
85 || vm
== views::PackageKeeps
|| vm
== views::PackageSkips
86 || vm
== views::PackageUserPicked
)
88 headers
= pkg_headers
;
91 bintick_col
= new_col
+ 1;
92 srctick_col
= bintick_col
+ 1;
93 cat_col
= srctick_col
+ 1;
94 size_col
= cat_col
+ 1;
95 pkg_col
= size_col
+ 1;
98 else if (vm
== views::Category
)
100 headers
= cat_headers
;
103 new_col
= current_col
+ 1;
104 bintick_col
= new_col
+ 1;
105 srctick_col
= bintick_col
+ 1;
106 size_col
= srctick_col
+ 1;
107 pkg_col
= size_col
+ 1;
116 PickView::set_headers ()
118 if (set_header_column_order (view_mode
) == -1)
120 while (int n
= SendMessage (listheader
, HDM_GETITEMCOUNT
, 0, 0))
122 SendMessage (listheader
, HDM_DELETEITEM
, n
- 1, 0);
125 for (i
= 0; i
<= last_col
; i
++)
126 DoInsertItem (listheader
, i
, headers
[i
].width
, (char *) headers
[i
].text
);
130 PickView::note_width (PickView::Header
*hdrs
, HDC dc
,
131 const std::string
& string
, int addend
, int column
)
136 GetTextExtentPoint32 (dc
, string
.c_str(), string
.size(), &s
);
137 if (hdrs
[column
].width
< s
.cx
+ addend
)
138 hdrs
[column
].width
= s
.cx
+ addend
;
142 PickView::setViewMode (views mode
)
149 if (view_mode
== PickView::views::Category
)
151 contents
.ShowLabel (true);
152 /* start collapsed. TODO: make this a chooser flag */
153 for (packagedb::categoriesType::iterator n
=
154 packagedb::categories
.begin(); n
!= packagedb::categories
.end();
156 insert_category (&*n
, (*n
).first
.c_str()[0] == '.'
157 ? CATEGORY_EXPANDED
: CATEGORY_COLLAPSED
);
161 contents
.ShowLabel (false);
162 // iterate through every package
163 for (packagedb::packagecollection::iterator i
= db
.packages
.begin ();
164 i
!= db
.packages
.end (); ++i
)
166 packagemeta
& pkg
= *(i
->second
);
171 if ( // "Full" : everything
172 (view_mode
== PickView::views::PackageFull
)
174 // "Pending" : packages that are being added/removed/upgraded
175 || (view_mode
== PickView::views::PackagePending
&&
176 ((!pkg
.desired
&& pkg
.installed
) || // uninstall
178 (pkg
.desired
.picked () || // install bin
179 pkg
.desired
.sourcePackage ().picked ())))) // src
181 // "Up to date" : installed packages that will not be changed
182 || (view_mode
== PickView::views::PackageKeeps
&&
183 (pkg
.installed
&& pkg
.desired
&& !pkg
.desired
.picked ()
184 && !pkg
.desired
.sourcePackage ().picked ()))
187 || (view_mode
== PickView::views::PackageSkips
&&
188 (!pkg
.desired
&& !pkg
.installed
))
190 // "UserPick" : installed packages that were picked by user
191 || (view_mode
== PickView::views::PackageUserPicked
&&
192 (pkg
.installed
&& pkg
.user_picked
)))
194 // Filter by package name
195 if (packageFilterString
.empty ()
196 || StrStrI (pkg
.name
.c_str (), packageFilterString
.c_str ()))
202 RECT r
= GetClientRect ();
204 memset (&si
, 0, sizeof (si
));
205 si
.cbSize
= sizeof (si
);
206 si
.fMask
= SIF_ALL
| SIF_DISABLENOSCROLL
;
208 si
.nMax
= headers
[last_col
].x
+ headers
[last_col
].width
; // + HMARGIN;
210 SetScrollInfo (GetHWND(), SB_HORZ
, &si
, TRUE
);
212 si
.nMax
= contents
.itemcount () * row_height
;
213 si
.nPage
= r
.bottom
- header_height
;
214 SetScrollInfo (GetHWND(), SB_VERT
, &si
, TRUE
);
216 scroll_ulc_x
= scroll_ulc_y
= 0;
218 InvalidateRect (GetHWND(), &r
, TRUE
);
222 PickView::getViewMode ()
228 PickView::mode_caption (views mode
)
232 case views::PackageFull
:
234 case views::PackagePending
:
236 case views::PackageKeeps
:
238 case views::PackageSkips
:
239 return "Not Installed";
240 case views::PackageUserPicked
:
242 case views::Category
:
249 /* meant to be called on packagemeta::categories */
251 isObsolete (set
<std::string
, casecompare_lt_op
> &categories
)
253 set
<std::string
, casecompare_lt_op
>::const_iterator i
;
255 for (i
= categories
.begin (); i
!= categories
.end (); ++i
)
262 isObsolete (const std::string
& catname
)
264 if (casecompare(catname
, "ZZZRemovedPackages") == 0
265 || casecompare(catname
, "_", 1) == 0)
270 /* Sets the mode for showing/hiding obsolete junk packages. */
272 PickView::setObsolete (bool doit
)
280 PickView::insert_pkg (packagemeta
& pkg
)
282 if (!showObsolete
&& isObsolete (pkg
.categories
))
285 PickLine
& line
= *new PickPackageLine (*this, pkg
);
286 contents
.insert (line
);
290 PickView::insert_category (Category
*cat
, bool collapsed
)
293 if (casecompare(cat
->first
, "All") == 0 ||
294 (!showObsolete
&& isObsolete (cat
->first
)))
296 PickCategoryLine
& catline
= *new PickCategoryLine (*this, *cat
, 1, collapsed
);
297 int packageCount
= 0;
298 for (vector
<packagemeta
*>::iterator i
= cat
->second
.begin ();
299 i
!= cat
->second
.end () ; ++i
)
301 if (packageFilterString
.empty () \
303 && StrStrI ((*i
)->name
.c_str (), packageFilterString
.c_str ())))
305 PickLine
& line
= *new PickPackageLine (*this, **i
);
306 catline
.insert (line
);
311 if (packageFilterString
.empty () || packageCount
)
312 contents
.insert (catline
);
318 PickView::click (int row
, int x
)
320 return contents
.click (0, row
, x
);
325 PickView::scroll (HWND hwnd
, int which
, int *var
, int code
, int howmany
= 1)
328 si
.cbSize
= sizeof (si
);
329 si
.fMask
= SIF_ALL
| SIF_DISABLENOSCROLL
;
330 GetScrollInfo (hwnd
, which
, &si
);
335 si
.nPos
= si
.nTrackPos
;
337 case SB_THUMBPOSITION
:
346 si
.nPos
+= (row_height
* howmany
);
349 si
.nPos
-= (row_height
* howmany
);
352 si
.nPos
+= si
.nPage
* 9 / 10;
355 si
.nPos
-= si
.nPage
* 9 / 10;
359 if ((int) si
.nPos
< 0)
361 if (si
.nPos
+ si
.nPage
> (unsigned int) si
.nMax
)
362 si
.nPos
= si
.nMax
- si
.nPage
;
365 SetScrollInfo (hwnd
, which
, &si
, TRUE
);
367 int ox
= scroll_ulc_x
;
368 int oy
= scroll_ulc_y
;
372 ::GetClientRect (hwnd
, &cr
);
374 sr
.top
+= header_height
;
376 ScrollWindow (hwnd
, ox
- scroll_ulc_x
, oy
- scroll_ulc_y
, &sr
, &sr
);
380 ScrollWindow (hwnd, ox - scroll_ulc_x, 0, &sr, &sr);
382 if (ox
- scroll_ulc_x
)
384 ::GetClientRect (listheader
, &cr
);
386 // UpdateWindow (htmp);
387 ::MoveWindow (listheader
, -scroll_ulc_x
, 0,
388 headers
[last_col
].x
+
389 headers
[last_col
].width
, header_height
, TRUE
);
394 /* this means to make the 'category' column wide enough to fit the first 'n'
395 categories for each package. */
396 #define NUM_CATEGORY_COL_WIDTH 2
399 PickView::init_headers (HDC dc
)
403 for (i
= 0; headers
[i
].text
; i
++)
405 headers
[i
].width
= 0;
409 // A margin of 3*GetSystemMetrics(SM_CXEDGE) is used at each side of the
410 // header text. (Probably should use that rather than hard-coding HMARGIN
412 int addend
= 2*3*GetSystemMetrics(SM_CXEDGE
);
414 // accommodate widths of the 'bin' and 'src' checkbox columns
415 note_width (headers
, dc
, headers
[bintick_col
].text
, addend
, bintick_col
);
416 note_width (headers
, dc
, headers
[srctick_col
].text
, addend
, srctick_col
);
418 // accomodate the width of each category name
420 for (packagedb::categoriesType::iterator n
= packagedb::categories
.begin();
421 n
!= packagedb::categories
.end(); ++n
)
423 if (!showObsolete
&& isObsolete (n
->first
))
425 note_width (headers
, dc
, n
->first
, HMARGIN
, cat_col
);
428 /* For each package, accomodate the width of the installed version in the
429 current_col, the widths of all other versions in the new_col, and the
430 width of the sdesc for the pkg_col. Also, if this is not a Category
431 view, adjust the 'category' column so that the first NUM_CATEGORY_COL_WIDTH
432 categories from each package fits. */
433 for (packagedb::packagecollection::iterator n
= db
.packages
.begin ();
434 n
!= db
.packages
.end (); ++n
)
436 packagemeta
& pkg
= *(n
->second
);
437 if (!showObsolete
&& isObsolete (pkg
.categories
))
440 note_width (headers
, dc
, pkg
.installed
.Canonical_version (),
441 HMARGIN
, current_col
);
442 for (set
<packageversion
>::iterator i
= pkg
.versions
.begin ();
443 i
!= pkg
.versions
.end (); ++i
)
445 if (*i
!= pkg
.installed
)
446 note_width (headers
, dc
, i
->Canonical_version (),
447 HMARGIN
+ SPIN_WIDTH
, new_col
);
448 std::string z
= format_1000s(i
->source ()->size
);
449 note_width (headers
, dc
, z
, HMARGIN
, size_col
);
450 z
= format_1000s(i
->sourcePackage ().source ()->size
);
451 note_width (headers
, dc
, z
, HMARGIN
, size_col
);
453 std::string s
= pkg
.name
;
454 if (pkg
.SDesc ().size())
455 s
+= std::string (": ") + std::string(pkg
.SDesc ());
456 note_width (headers
, dc
, s
, HMARGIN
, pkg_col
);
458 if (view_mode
!= PickView::views::Category
&& pkg
.categories
.size () > 2)
460 std::string
compound_cat("");
461 std::set
<std::string
, casecompare_lt_op
>::const_iterator cat
;
464 for (cnt
= 0, cat
= pkg
.categories
.begin ();
465 cnt
< NUM_CATEGORY_COL_WIDTH
&& cat
!= pkg
.categories
.end ();
468 if (casecompare(*cat
, "All") == 0)
470 if (compound_cat
.size ())
471 compound_cat
+= ", ";
472 compound_cat
+= *cat
;
475 note_width (headers
, dc
, compound_cat
, HMARGIN
, cat_col
);
479 // ensure that the new_col is wide enough for all the labels
480 const char *captions
[] = { "Uninstall", "Skip", "Reinstall", "Retrieve",
481 "Source", "Keep", NULL
};
482 for (int i
= 0; captions
[i
]; i
++)
483 note_width (headers
, dc
, captions
[i
], HMARGIN
+ SPIN_WIDTH
, new_col
);
485 // finally, compute the actual x values based on widths
487 for (i
= 1; i
<= last_col
; i
++)
488 headers
[i
].x
= headers
[i
- 1].x
+ headers
[i
- 1].width
;
489 // and allow for resizing to ensure the last column reaches
490 // all the way to the end of the chooser box.
491 headers
[last_col
].width
+= total_delta_x
;
494 PickView::PickView (Category
&cat
) : deftrust (TRUST_CURR
),
495 contents (*this, cat
, 0, false, true), showObsolete (false),
496 packageFilterString (), hasWindowRect (false), total_delta_x (0)
501 PickView::init(views _mode
)
503 HDC dc
= GetDC (GetHWND());
504 sysfont
= GetStockObject (DEFAULT_GUI_FONT
);
505 SelectObject (dc
, sysfont
);
506 GetTextMetrics (dc
, &tm
);
508 bitmap_dc
= CreateCompatibleDC (dc
);
509 #define LI(x) LoadImage (hinstance, MAKEINTRESOURCE (x), IMAGE_BITMAP, 0, 0, 0);
510 bm_spin
= LI (IDB_SPIN
);
511 bm_checkyes
= LI (IDB_CHECK_YES
);
512 bm_checkno
= LI (IDB_CHECK_NO
);
513 bm_checkna
= LI (IDB_CHECK_NA
);
514 bm_treeplus
= LI (IDB_TREE_PLUS
);
515 bm_treeminus
= LI (IDB_TREE_MINUS
);
517 icon_dc
= CreateCompatibleDC (dc
);
518 bm_icon
= CreateCompatibleBitmap (dc
, 11, 11);
519 SelectObject (icon_dc
, bm_icon
);
520 rect_icon
= CreateRectRgn (0, 0, 11, 11);
522 row_height
= (tm
.tmHeight
+ tm
.tmExternalLeading
+ ROW_MARGIN
);
523 int irh
= tm
.tmExternalLeading
+ tm
.tmDescent
+ 11 + ROW_MARGIN
;
524 if (row_height
< irh
)
530 // Ensure that the common control DLL is loaded, and then create
531 // the header control.
532 INITCOMMONCONTROLSEX controlinfo
= { sizeof (INITCOMMONCONTROLSEX
),
533 ICC_LISTVIEW_CLASSES
};
534 InitCommonControlsEx (&controlinfo
);
536 if ((listheader
= CreateWindowEx (0, WC_HEADER
, (LPCTSTR
) NULL
,
537 WS_CHILD
| WS_BORDER
| CCS_NORESIZE
|
539 HDS_HORZ
, 0, 0, 0, 0, GetHWND(),
540 (HMENU
) IDC_CHOOSE_LISTHEADER
, hinstance
,
541 (LPVOID
) NULL
)) == NULL
)
542 // FIXME: throw an exception
545 // Retrieve the bounding rectangle of the parent window's
546 // client area, and then request size and position values
547 // from the header control.
548 RECT rcParent
= GetClientRect ();
552 if (!SendMessage (listheader
, HDM_LAYOUT
, 0, (LPARAM
) & hdl
))
553 // FIXME: throw an exception
556 // Set the font of the listheader, but don't redraw, because its not shown
557 // yet.This message does not return a value, so we are not checking it as we
559 SendMessage (listheader
, WM_SETFONT
, (WPARAM
) sysfont
, FALSE
);
561 // Set the size, position, and visibility of the header control.
562 SetWindowPos (listheader
, wp
.hwndInsertAfter
, wp
.x
, wp
.y
,
563 wp
.cx
, wp
.cy
, wp
.flags
| SWP_SHOWWINDOW
);
565 header_height
= wp
.cy
;
566 ReleaseDC (GetHWND (), dc
);
572 PickView::~PickView()
574 DeleteDC (bitmap_dc
);
575 DeleteObject (bm_spin
);
576 DeleteObject (bm_checkyes
);
577 DeleteObject (bm_checkno
);
578 DeleteObject (bm_checkna
);
579 DeleteObject (bm_treeplus
);
580 DeleteObject (bm_treeminus
);
581 DeleteObject (rect_icon
);
582 DeleteObject (bm_icon
);
586 bool PickView::registerWindowClass ()
588 if (WindowClassAtom
!= 0)
591 // We're not registered yet
594 wc
.cbSize
= sizeof (wc
);
595 // Some sensible style defaults
596 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;
597 // Our default window procedure. This replaces itself
598 // on the first call with the simpler Window::WindowProcReflector().
599 wc
.lpfnWndProc
= Window::FirstWindowProcReflector
;
602 // One pointer to REFLECTION_INFO in the extra window instance bytes
605 wc
.hInstance
= hinstance
; //GetInstance ();
606 // Use a bunch of system defaults for the GUI elements
607 wc
.hIcon
= LoadIcon (0, IDI_APPLICATION
);
609 wc
.hCursor
= LoadCursor (0, IDC_ARROW
);
610 wc
.hbrBackground
= NULL
;
612 wc
.lpszMenuName
= NULL
;
613 // We'll get a little crazy here with the class name
614 wc
.lpszClassName
= "listview";
616 // All set, try to register
617 WindowClassAtom
= RegisterClassEx (&wc
);
618 if (WindowClassAtom
== 0)
619 Log (LOG_BABBLE
) << "Failed to register listview " << GetLastError () << endLog
;
620 return WindowClassAtom
!= 0;
624 PickView::list_vscroll (HWND hwnd
, HWND hctl
, UINT code
, int pos
)
626 scroll (hwnd
, SB_VERT
, &scroll_ulc_y
, code
);
631 PickView::list_hscroll (HWND hwnd
, HWND hctl
, UINT code
, int pos
)
633 scroll (hwnd
, SB_HORZ
, &scroll_ulc_x
, code
);
638 PickView::set_vscroll_info (const RECT
&r
)
641 memset (&si
, 0, sizeof (si
));
642 si
.cbSize
= sizeof (si
);
643 si
.fMask
= SIF_ALL
| SIF_DISABLENOSCROLL
; /* SIF_RANGE was giving strange behaviour */
646 si
.nMax
= contents
.itemcount () * row_height
;
647 si
.nPage
= r
.bottom
- header_height
;
649 /* if we are under the minimum display count ,
650 * set the offset to 0
652 if ((unsigned int) si
.nMax
<= si
.nPage
)
654 si
.nPos
= scroll_ulc_y
;
656 SetScrollInfo (GetHWND(), SB_VERT
, &si
, TRUE
);
660 PickView::list_click (HWND hwnd
, BOOL dblclk
, int x
, int y
, UINT hitCode
)
662 int row
, refresh
__attribute__ ((unused
));
664 if (contents
.itemcount () == 0)
667 if (y
< header_height
)
670 y
+= scroll_ulc_y
- header_height
;
672 row
= (y
+ ROW_MARGIN
/ 2) / row_height
;
674 if (row
< 0 || row
>= contents
.itemcount ())
677 refresh
= click (row
, x
);
679 // XXX we need a method to query the database to see if more
680 // than just one package has changed! Until then...
685 RECT r
= GetClientRect ();
686 set_vscroll_info (r
);
687 InvalidateRect (GetHWND(), &r
, TRUE
);
694 headers
[new_col
].x
- scroll_ulc_x
;
696 headers
[src_col
+ 1].x
- scroll_ulc_x
;
698 header_height
+ row
* row_height
-
700 rect
.bottom
= rect
.top
+ row_height
;
701 InvalidateRect (hwnd
, &rect
, TRUE
);
709 * PickView::listview_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
712 PickView::WindowProc (UINT message
, WPARAM wParam
, LPARAM lParam
)
720 list_hscroll (GetHWND(), (HWND
)lParam
, LOWORD(wParam
), HIWORD(wParam
));
723 list_vscroll (GetHWND(), (HWND
)lParam
, LOWORD(wParam
), HIWORD(wParam
));
726 // this is how many 'notches' the wheel scrolled, forward/up = positive
727 wheel_notches
= GET_WHEEL_DELTA_WPARAM(wParam
) / 120;
729 // determine how many lines the user has configred for a mouse scroll
730 SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0, &wheel_lines
, 0);
732 if (wheel_lines
== 0) // do no scrolling
734 else if (wheel_lines
== WHEEL_PAGESCROLL
)
735 scroll (GetHWND (), SB_VERT
, &scroll_ulc_y
, (wheel_notches
> 0) ?
736 SB_PAGEUP
: SB_PAGEDOWN
);
738 scroll (GetHWND (), SB_VERT
, &scroll_ulc_y
, (wheel_notches
> 0) ?
739 SB_LINEUP
: SB_LINEDOWN
, wheel_lines
* abs (wheel_notches
));
742 list_click (GetHWND(), FALSE
, LOWORD(lParam
), HIWORD(lParam
), wParam
);
749 // pnmh = (LPNMHDR) lParam
750 LPNMHEADER phdr
= (LPNMHEADER
) lParam
;
751 switch (phdr
->hdr
.code
)
753 case HDN_ITEMCHANGED
:
754 if (phdr
->hdr
.hwndFrom
== ListHeader ())
756 if (phdr
->pitem
&& phdr
->pitem
->mask
& HDI_WIDTH
)
757 headers
[phdr
->iItem
].width
= phdr
->pitem
->cxy
;
759 for (int i
= 1; i
<= last_col
; i
++)
760 headers
[i
].x
= headers
[i
- 1].x
+ headers
[i
- 1].width
;
762 RECT r
= GetClientRect ();
764 si
.cbSize
= sizeof (si
);
765 si
.fMask
= SIF_ALL
| SIF_DISABLENOSCROLL
;
766 GetScrollInfo (GetHWND(), SB_HORZ
, &si
);
768 int oldMax
= si
.nMax
;
769 si
.nMax
= headers
[last_col
].x
+ headers
[last_col
].width
;
770 if (si
.nTrackPos
&& oldMax
> si
.nMax
)
771 si
.nTrackPos
+= si
.nMax
- oldMax
;
774 SetScrollInfo (GetHWND(), SB_HORZ
, &si
, TRUE
);
775 InvalidateRect (GetHWND(), &r
, TRUE
);
776 if (si
.nTrackPos
&& oldMax
> si
.nMax
)
777 scroll (GetHWND(), SB_HORZ
, &scroll_ulc_x
, SB_THUMBTRACK
);
785 // Note: WM_SIZE msgs only appear when 'just' scrolling the window
786 RECT windowRect
= GetWindowRect ();
790 if ((dx
= windowRect
.right
- windowRect
.left
-
791 lastWindowRect
.width ()) != 0)
793 cat_headers
[set_header_column_order (views::Category
)].width
+= dx
;
794 pkg_headers
[set_header_column_order (views::PackagePending
)].width
+= dx
;
795 set_header_column_order (view_mode
);
797 ::MoveWindow (listheader
, -scroll_ulc_x
, 0,
798 headers
[last_col
].x
+
799 headers
[last_col
].width
, header_height
, TRUE
);
802 if (windowRect
.bottom
- windowRect
.top
- lastWindowRect
.height ())
803 set_vscroll_info (GetClientRect ());
806 hasWindowRect
= true;
808 lastWindowRect
= windowRect
;
813 // default: can't handle this message
814 return DefWindowProc (GetHWND(), message
, wParam
, lParam
);
818 // Turn black into foreground color and white into background color by
819 // 1) Filling a square with ~(FG^BG)
820 // 2) Blitting the bitmap on it with NOTSRCERASE (white->black; black->FG^BG)
821 // 3) Blitting the result on BG with SRCINVERT (white->BG; black->FG)
823 PickView::DrawIcon (HDC hdc
, int x
, int y
, HANDLE hIcon
)
825 SelectObject (bitmap_dc
, hIcon
);
826 FillRgn (icon_dc
, rect_icon
, bg_fg_brush
);
827 BitBlt (icon_dc
, 0, 0, 11, 11, bitmap_dc
, 0, 0, NOTSRCERASE
);
828 BitBlt (hdc
, x
, y
, 11, 11, icon_dc
, 0, 0, SRCINVERT
);
829 ///////////// On WinNT-based systems, we could've done the below instead
830 ///////////// See http://support.microsoft.com/default.aspx?scid=kb;en-us;79212
831 // SelectObject (hdc, GetSysColorBrush (COLOR_WINDOWTEXT));
832 // HBITMAP bm_icon = CreateBitmap (11, 11, 1, 1, NULL);
833 // SelectObject (icon_dc, bm_icon);
834 // BitBlt (icon_dc, 0, 0, 11, 11, bitmap_dc, 0, 0, SRCCOPY);
835 // MaskBlt (hdc, x2, by, 11, 11, bitmap_dc, 0, 0, bm_icon, 0, 0, MAKEROP4 (SRCAND, PATCOPY));
836 // DeleteObject (bm_icon);
840 PickView::paint (HWND hwnd
)
842 // we want to retrieve the update region before calling BeginPaint,
843 // because after we do that the update region is validated and we can
844 // no longer retrieve it
845 HRGN hUpdRgn
= CreateRectRgn (0, 0, 0, 0);
847 if (GetUpdateRgn (hwnd
, hUpdRgn
, FALSE
) == 0)
853 // tell the system that we're going to begin painting our window
854 // it will prevent further WM_PAINT messages from arriving until we're
855 // done, and if any part of our window was invalidated while we are
856 // painting, it will retrigger us so that we can fix it
858 HDC hdc
= BeginPaint (hwnd
, &ps
);
860 SelectObject (hdc
, sysfont
);
861 SetTextColor (hdc
, GetSysColor (COLOR_WINDOWTEXT
));
862 SetBkColor (hdc
, GetSysColor (COLOR_WINDOW
));
863 FillRgn (hdc
, hUpdRgn
, GetSysColorBrush(COLOR_WINDOW
));
865 COLORREF clr
= ~GetSysColor (COLOR_WINDOW
) ^ GetSysColor (COLOR_WINDOWTEXT
);
866 clr
= RGB (GetRValue (clr
), GetGValue (clr
), GetBValue (clr
)); // reconvert
867 bg_fg_brush
= CreateSolidBrush (clr
);
870 ::GetClientRect (hwnd
, &cr
);
872 int x
= cr
.left
- scroll_ulc_x
;
873 int y
= cr
.top
- scroll_ulc_y
+ header_height
;
875 contents
.paint (hdc
, hUpdRgn
, x
, y
, 0, (view_mode
==
876 PickView::views::Category
) ? 0 : 1);
878 if (contents
.itemcount () == 0)
880 static const char *msg
= "Nothing to Install/Update";
881 if (source
== IDC_SOURCE_DOWNLOAD
)
882 msg
= "Nothing to Download";
883 TextOut (hdc
, x
+ HMARGIN
, y
, msg
, strlen (msg
));
886 DeleteObject (hUpdRgn
);
887 DeleteObject (bg_fg_brush
);
888 EndPaint (hwnd
, &ps
);
893 PickView::Create (Window
* parent
, DWORD Style
, RECT
*r
)
896 // First register the window class, if we haven't already
897 if (!registerWindowClass ())
899 // Registration failed
903 // Save our parent, we'll probably need it eventually.
906 // Create the window instance
907 CreateWindowEx (// Extended Style
909 // window class atom (name)
910 "listview", //MAKEINTATOM(WindowClassAtom),
911 "listviewwindow", // no title-bar string yet
914 r
? r
->left
: CW_USEDEFAULT
,
915 r
? r
->top
: CW_USEDEFAULT
,
916 r
? r
->right
- r
->left
+ 1 : CW_USEDEFAULT
,
917 r
? r
->bottom
- r
->top
+ 1 : CW_USEDEFAULT
,
919 parent
== NULL
? (HWND
)NULL
: parent
->GetHWND (),
921 (HMENU
) MAKEINTRESOURCE (IDC_CHOOSE_LIST
),
922 // The application instance
924 // The this ptr, which we'll use to set up
925 // the WindowProc reflection.
926 reinterpret_cast<void *>((Window
*)this));
927 if (GetHWND() == NULL
)
929 Log (LOG_BABBLE
) << "Failed to create PickView " << GetLastError () << endLog
;
937 PickView::defaultTrust (trusts trust
)
939 this->deftrust
= trust
;
942 db
.defaultTrust(trust
);
944 // force the picker to redraw
945 RECT r
= GetClientRect ();
946 InvalidateRect (this->GetHWND(), &r
, TRUE
);
949 /* This recalculates all column widths and resets the view */
953 HDC dc
= GetDC (GetHWND ());
955 // we must set the font of the DC here, otherwise the width calculations
956 // will be off because the system will use the wrong font metrics
957 sysfont
= GetStockObject (DEFAULT_GUI_FONT
);
958 SelectObject (dc
, sysfont
);
960 // init headers for the current mode
964 // save the current mode
965 views cur_view_mode
= view_mode
;
967 // switch to the other type and do those headers
968 view_mode
= (view_mode
== PickView::views::Category
) ?
969 PickView::views::PackageFull
: PickView::views::Category
;
972 ReleaseDC (GetHWND (), dc
);
974 view_mode
= cur_view_mode
;
975 setViewMode (view_mode
);