mirror of https://github.com/BOINC/boinc.git
- MGR: Allow Notices tab to scroll smoothly, disallow selection of items in Notices tab
svn path=/trunk/boinc/; revision=22242
This commit is contained in:
parent
cc44cb4fdb
commit
945470d3ba
|
@ -6083,3 +6083,16 @@ David 14 Aug 2010
|
|||
|
||||
sched/
|
||||
handle_request.cpp
|
||||
|
||||
Charlie 15 Aug 2010
|
||||
- MGR: Allow Notices tab to scroll smoothly, disallow selection of
|
||||
items in Notices tab.
|
||||
|
||||
clientgui/
|
||||
BOINCHtmlListBox.cpp, .h (new)
|
||||
BOINCVListBox.cpp, .h (new)
|
||||
NoticeListCtrl.cpp, .h
|
||||
ViewNotices.cpp
|
||||
mac_build/
|
||||
boinc.xcodeproj/
|
||||
project.pbxproj
|
||||
|
|
|
@ -0,0 +1,629 @@
|
|||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2008 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
// as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// BOINC is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Adapted from htmllbox.cpp by Vadim Zeitlin <vadim@wxwindows.org>
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if wxUSE_HTML
|
||||
|
||||
#include "BOINCHtmlLBox.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// constants
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const wxChar BOINCHtmlListBoxNameStr[] = wxT("BOINCHtmlListBox");
|
||||
|
||||
// ============================================================================
|
||||
// private classes
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCHtmlListBoxCache
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// this class is used by CBOINCHtmlListBox to cache the parsed representation of
|
||||
// the items to avoid doing it anew each time an item must be drawn
|
||||
class CBOINCHtmlListBoxCache
|
||||
{
|
||||
private:
|
||||
// invalidate a single item, used by Clear() and InvalidateRange()
|
||||
void InvalidateItem(size_t n)
|
||||
{
|
||||
m_items[n] = (size_t)-1;
|
||||
delete m_cells[n];
|
||||
m_cells[n] = NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
CBOINCHtmlListBoxCache()
|
||||
{
|
||||
for ( size_t n = 0; n < SIZE; n++ )
|
||||
{
|
||||
m_items[n] = (size_t)-1;
|
||||
m_cells[n] = NULL;
|
||||
}
|
||||
|
||||
m_next = 0;
|
||||
}
|
||||
|
||||
~CBOINCHtmlListBoxCache()
|
||||
{
|
||||
for ( size_t n = 0; n < SIZE; n++ )
|
||||
{
|
||||
delete m_cells[n];
|
||||
}
|
||||
}
|
||||
|
||||
// completely invalidate the cache
|
||||
void Clear()
|
||||
{
|
||||
for ( size_t n = 0; n < SIZE; n++ )
|
||||
{
|
||||
InvalidateItem(n);
|
||||
}
|
||||
}
|
||||
|
||||
// return the cached cell for this index or NULL if none
|
||||
wxHtmlCell *Get(size_t item) const
|
||||
{
|
||||
for ( size_t n = 0; n < SIZE; n++ )
|
||||
{
|
||||
if ( m_items[n] == item )
|
||||
return m_cells[n];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// returns true if we already have this item cached
|
||||
bool Has(size_t item) const { return Get(item) != NULL; }
|
||||
|
||||
// ensure that the item is cached
|
||||
void Store(size_t item, wxHtmlCell *cell)
|
||||
{
|
||||
delete m_cells[m_next];
|
||||
m_cells[m_next] = cell;
|
||||
m_items[m_next] = item;
|
||||
|
||||
// advance to the next item wrapping around if there are no more
|
||||
if ( ++m_next == SIZE )
|
||||
m_next = 0;
|
||||
}
|
||||
|
||||
// forget the cached value of the item(s) between the given ones (inclusive)
|
||||
void InvalidateRange(size_t from, size_t to)
|
||||
{
|
||||
for ( size_t n = 0; n < SIZE; n++ )
|
||||
{
|
||||
if ( m_items[n] >= from && m_items[n] <= to )
|
||||
{
|
||||
InvalidateItem(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// the max number of the items we cache
|
||||
enum { SIZE = 50 };
|
||||
|
||||
// the index of the LRU (oldest) cell
|
||||
size_t m_next;
|
||||
|
||||
// the parsed representation of the cached item or NULL
|
||||
wxHtmlCell *m_cells[SIZE];
|
||||
|
||||
// the index of the currently cached item (only valid if m_cells != NULL)
|
||||
size_t m_items[SIZE];
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCHtmlListBoxStyle
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// just forward wxDefaultHtmlRenderingStyle callbacks to the main class so that
|
||||
// they could be overridden by the user code
|
||||
class CBOINCHtmlListBoxStyle : public wxDefaultHtmlRenderingStyle
|
||||
{
|
||||
public:
|
||||
CBOINCHtmlListBoxStyle(const CBOINCHtmlListBox& hlbox) : m_hlbox(hlbox) { }
|
||||
|
||||
virtual wxColour GetSelectedTextColour(const wxColour& colFg)
|
||||
{
|
||||
return m_hlbox.GetSelectedTextColour(colFg);
|
||||
}
|
||||
|
||||
virtual wxColour GetSelectedTextBgColour(const wxColour& colBg)
|
||||
{
|
||||
return m_hlbox.GetSelectedTextBgColour(colBg);
|
||||
}
|
||||
|
||||
private:
|
||||
const CBOINCHtmlListBox& m_hlbox;
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CBOINCHtmlListBoxStyle)
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// event tables
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
BEGIN_EVENT_TABLE(CBOINCHtmlListBox, CBOINCVListBox)
|
||||
EVT_SIZE(CBOINCHtmlListBox::OnSize)
|
||||
EVT_MOTION(CBOINCHtmlListBox::OnMouseMove)
|
||||
EVT_LEFT_DOWN(CBOINCHtmlListBox::OnLeftDown)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
IMPLEMENT_ABSTRACT_CLASS(CBOINCHtmlListBox, CBOINCVListBox)
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCHtmlListBox creation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
CBOINCHtmlListBox::CBOINCHtmlListBox()
|
||||
: wxHtmlWindowMouseHelper(this)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
// normal constructor which calls Create() internally
|
||||
CBOINCHtmlListBox::CBOINCHtmlListBox(wxWindow *parent,
|
||||
wxWindowID id,
|
||||
const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
long style,
|
||||
const wxString& name)
|
||||
: wxHtmlWindowMouseHelper(this)
|
||||
{
|
||||
Init();
|
||||
|
||||
(void)Create(parent, id, pos, size, style, name);
|
||||
}
|
||||
|
||||
void CBOINCHtmlListBox::Init()
|
||||
{
|
||||
m_htmlParser = NULL;
|
||||
m_htmlRendStyle = new CBOINCHtmlListBoxStyle(*this);
|
||||
m_cache = new CBOINCHtmlListBoxCache;
|
||||
}
|
||||
|
||||
bool CBOINCHtmlListBox::Create(wxWindow *parent,
|
||||
wxWindowID id,
|
||||
const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
long style,
|
||||
const wxString& name)
|
||||
{
|
||||
return CBOINCVListBox::Create(parent, id, pos, size, style, name);
|
||||
}
|
||||
|
||||
CBOINCHtmlListBox::~CBOINCHtmlListBox()
|
||||
{
|
||||
delete m_cache;
|
||||
|
||||
if ( m_htmlParser )
|
||||
{
|
||||
delete m_htmlParser->GetDC();
|
||||
delete m_htmlParser;
|
||||
}
|
||||
|
||||
delete m_htmlRendStyle;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCHtmlListBox appearance
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxColour CBOINCHtmlListBox::GetSelectedTextColour(const wxColour& colFg) const
|
||||
{
|
||||
return m_htmlRendStyle->
|
||||
wxDefaultHtmlRenderingStyle::GetSelectedTextColour(colFg);
|
||||
}
|
||||
|
||||
wxColour
|
||||
CBOINCHtmlListBox::GetSelectedTextBgColour(const wxColour& WXUNUSED(colBg)) const
|
||||
{
|
||||
return GetSelectionBackground();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCHtmlListBox items markup
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxString CBOINCHtmlListBox::OnGetItemMarkup(size_t n) const
|
||||
{
|
||||
// we don't even need to wrap the value returned by OnGetItem() inside
|
||||
// "<html><body>" and "</body></html>" because wxHTML can parse it even
|
||||
// without these tags
|
||||
return OnGetItem(n);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCHtmlListBox cache handling
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void CBOINCHtmlListBox::CacheItem(size_t n) const
|
||||
{
|
||||
if ( !m_cache->Has(n) )
|
||||
{
|
||||
if ( !m_htmlParser )
|
||||
{
|
||||
CBOINCHtmlListBox *self = wxConstCast(this, CBOINCHtmlListBox);
|
||||
|
||||
self->m_htmlParser = new wxHtmlWinParser(self);
|
||||
m_htmlParser->SetDC(new wxClientDC(self));
|
||||
m_htmlParser->SetFS(&self->m_filesystem);
|
||||
#if !wxUSE_UNICODE
|
||||
if (GetFont().Ok())
|
||||
m_htmlParser->SetInputEncoding(GetFont().GetEncoding());
|
||||
#endif
|
||||
// use system's default GUI font by default:
|
||||
m_htmlParser->SetStandardFonts();
|
||||
}
|
||||
|
||||
wxHtmlContainerCell *cell = (wxHtmlContainerCell *)m_htmlParser->
|
||||
Parse(OnGetItemMarkup(n));
|
||||
wxCHECK_RET( cell, _T("wxHtmlParser::Parse() returned NULL?") );
|
||||
|
||||
// set the cell's ID to item's index so that CellCoordsToPhysical()
|
||||
// can quickly find the item:
|
||||
cell->SetId(wxString::Format(_T("%lu"), (unsigned long)n));
|
||||
|
||||
cell->Layout(GetClientSize().x - (2 * GetMargins().x));
|
||||
|
||||
m_cache->Store(n, cell);
|
||||
}
|
||||
}
|
||||
|
||||
void CBOINCHtmlListBox::OnSize(wxSizeEvent& event)
|
||||
{
|
||||
// we need to relayout all the cached cells
|
||||
m_cache->Clear();
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void CBOINCHtmlListBox::RefreshItem(size_t item)
|
||||
{
|
||||
wxRect rect;
|
||||
|
||||
m_cache->InvalidateRange(item, item);
|
||||
|
||||
GetItemRect(item, rect);
|
||||
RefreshRect(rect);
|
||||
}
|
||||
|
||||
void CBOINCHtmlListBox::RefreshItems(size_t from, size_t to)
|
||||
{
|
||||
wxRect rect;
|
||||
|
||||
m_cache->InvalidateRange(from, to);
|
||||
|
||||
for (size_t i = from; i <= to; ++i) {
|
||||
GetItemRect(i, rect);
|
||||
RefreshRect(rect);
|
||||
}
|
||||
}
|
||||
|
||||
void CBOINCHtmlListBox::SetItemCount(size_t count)
|
||||
{
|
||||
// the items are going to change, forget the old ones
|
||||
m_cache->Clear();
|
||||
|
||||
CBOINCVListBox::SetItemCount(count);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCHtmlListBox implementation of CBOINCVListBox pure virtuals
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void CBOINCHtmlListBox::OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const
|
||||
{
|
||||
CacheItem(n);
|
||||
|
||||
wxHtmlCell *cell = m_cache->Get(n);
|
||||
wxCHECK_RET( cell, _T("this cell should be cached!") );
|
||||
|
||||
wxHtmlRenderingInfo htmlRendInfo;
|
||||
|
||||
// draw the selected cell in selected state
|
||||
if ( IsSelected(n) )
|
||||
{
|
||||
wxHtmlSelection htmlSel;
|
||||
htmlSel.Set(wxPoint(0,0), cell, wxPoint(INT_MAX, INT_MAX), cell);
|
||||
htmlRendInfo.SetSelection(&htmlSel);
|
||||
if ( m_htmlRendStyle )
|
||||
htmlRendInfo.SetStyle(m_htmlRendStyle);
|
||||
htmlRendInfo.GetState().SetSelectionState(wxHTML_SEL_IN);
|
||||
}
|
||||
|
||||
// note that we can't stop drawing exactly at the window boundary as then
|
||||
// even the visible cells part could be not drawn, so always draw the
|
||||
// entire cell
|
||||
cell->Draw(dc,
|
||||
rect.x + CELL_BORDER, rect.y + CELL_BORDER,
|
||||
0, INT_MAX, htmlRendInfo);
|
||||
}
|
||||
|
||||
wxCoord CBOINCHtmlListBox::OnMeasureItem(size_t n) const
|
||||
{
|
||||
CacheItem(n);
|
||||
|
||||
wxHtmlCell *cell = m_cache->Get(n);
|
||||
wxCHECK_MSG( cell, 0, _T("this cell should be cached!") );
|
||||
|
||||
return cell->GetHeight() + cell->GetDescent() + (2 * CELL_BORDER);
|
||||
}
|
||||
|
||||
wxCoord CBOINCHtmlListBox::GetMaxItemWidth() const
|
||||
{
|
||||
wxCoord w, maxWidth = 0;
|
||||
size_t n = GetItemCount();
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
CacheItem(i);
|
||||
wxHtmlCell *cell = m_cache->Get(i);
|
||||
w = cell->GetWidth();
|
||||
if (w > maxWidth) maxWidth = w;
|
||||
}
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCHtmlListBox implementation of wxHtmlListBoxWinInterface
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void CBOINCHtmlListBox::SetHTMLWindowTitle(const wxString& WXUNUSED(title))
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
void CBOINCHtmlListBox::OnHTMLLinkClicked(const wxHtmlLinkInfo& link)
|
||||
{
|
||||
OnLinkClicked(GetItemForCell(link.GetHtmlCell()), link);
|
||||
}
|
||||
|
||||
void CBOINCHtmlListBox::OnLinkClicked(size_t WXUNUSED(n),
|
||||
const wxHtmlLinkInfo& link)
|
||||
{
|
||||
wxHtmlLinkEvent event(GetId(), link);
|
||||
GetEventHandler()->ProcessEvent(event);
|
||||
}
|
||||
|
||||
wxHtmlOpeningStatus
|
||||
CBOINCHtmlListBox::OnHTMLOpeningURL(wxHtmlURLType WXUNUSED(type),
|
||||
const wxString& WXUNUSED(url),
|
||||
wxString *WXUNUSED(redirect)) const
|
||||
{
|
||||
return wxHTML_OPEN;
|
||||
}
|
||||
|
||||
wxPoint CBOINCHtmlListBox::HTMLCoordsToWindow(wxHtmlCell *cell,
|
||||
const wxPoint& pos) const
|
||||
{
|
||||
return CellCoordsToPhysical(pos, cell);
|
||||
}
|
||||
|
||||
wxWindow* CBOINCHtmlListBox::GetHTMLWindow() { return this; }
|
||||
|
||||
wxColour CBOINCHtmlListBox::GetHTMLBackgroundColour() const
|
||||
{
|
||||
return GetBackgroundColour();
|
||||
}
|
||||
|
||||
void CBOINCHtmlListBox::SetHTMLBackgroundColour(const wxColour& WXUNUSED(clr))
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
void CBOINCHtmlListBox::SetHTMLBackgroundImage(const wxBitmap& WXUNUSED(bmpBg))
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
void CBOINCHtmlListBox::SetHTMLStatusText(const wxString& WXUNUSED(text))
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
wxCursor CBOINCHtmlListBox::GetHTMLCursor(HTMLCursor type) const
|
||||
{
|
||||
// we don't want to show text selection cursor in listboxes
|
||||
if (type == HTMLCursor_Text)
|
||||
return wxHtmlWindow::GetDefaultHTMLCursor(HTMLCursor_Default);
|
||||
|
||||
// in all other cases, use the same cursor as wxHtmlWindow:
|
||||
return wxHtmlWindow::GetDefaultHTMLCursor(type);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCHtmlListBox utilities
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int CBOINCHtmlListBox::HitTest(const wxPoint& pos)
|
||||
{
|
||||
if ( CBOINCVListBox::HitTest(pos) == wxNOT_FOUND )
|
||||
return wxNOT_FOUND;
|
||||
|
||||
int x, y;
|
||||
size_t n = GetItemCount();
|
||||
wxRect r;
|
||||
|
||||
GetViewStart(&x, &y);
|
||||
wxPoint p(-x*PIXELS_PER_HORIZONTAL_SCROLL_UNIT, -y*PIXELS_PER_VERTICAL_SCROLL_UNIT);
|
||||
p.y -= GetMargins().y + CELL_BORDER;
|
||||
p.x += GetMargins().x - CELL_BORDER;
|
||||
|
||||
r.SetTopLeft(p);
|
||||
r.SetHeight(0);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
CacheItem(i);
|
||||
wxHtmlCell *aCell = m_cache->Get(i);
|
||||
r.height = OnGetItemHeight(i);
|
||||
r.width = aCell->GetWidth();
|
||||
if (r.Contains(pos)) {
|
||||
// convert mouse coordinates to coords relative to item's wxHtmlCell:
|
||||
return i;
|
||||
}
|
||||
r.y += r.height; // + (2 * GetMargins().y);
|
||||
}
|
||||
return wxNOT_FOUND;
|
||||
}
|
||||
|
||||
void CBOINCHtmlListBox::GetItemRect(size_t item, wxRect& rect)
|
||||
{
|
||||
wxPoint pos = GetRootCellCoords(item);
|
||||
pos.x += GetMargins().x - CELL_BORDER;
|
||||
pos.y -= GetMargins().y + CELL_BORDER;
|
||||
rect.SetTopLeft(pos);
|
||||
CacheItem(item);
|
||||
wxHtmlCell *cell = m_cache->Get(item);
|
||||
rect.height = OnGetItemHeight(item);
|
||||
rect.width = cell->GetWidth();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCHtmlListBox handling of HTML links
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxPoint CBOINCHtmlListBox::GetRootCellCoords(size_t n) const
|
||||
{
|
||||
int x, y;
|
||||
// wxPoint pos(GetMargins().x - CELL_BORDER, -GetMargins().y - CELL_BORDER);
|
||||
wxPoint pos(0, 0);
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
pos.y += OnGetItemHeight(i);
|
||||
}
|
||||
GetViewStart(&x, &y);
|
||||
pos.x -= x*PIXELS_PER_HORIZONTAL_SCROLL_UNIT;
|
||||
pos.y -= y*PIXELS_PER_VERTICAL_SCROLL_UNIT;
|
||||
return pos;
|
||||
}
|
||||
|
||||
bool CBOINCHtmlListBox::PhysicalCoordsToCell(wxPoint& pos, wxHtmlCell*& cell) const
|
||||
{
|
||||
if ( CBOINCVListBox::HitTest(pos) == wxNOT_FOUND )
|
||||
return false;
|
||||
|
||||
int x, y;
|
||||
size_t n = GetItemCount();
|
||||
wxRect r;
|
||||
wxPoint p(CELL_BORDER, CELL_BORDER);
|
||||
|
||||
p += GetMargins();
|
||||
|
||||
GetViewStart(&x, &y);
|
||||
p.x -= x*PIXELS_PER_HORIZONTAL_SCROLL_UNIT;
|
||||
p.y -= y*PIXELS_PER_VERTICAL_SCROLL_UNIT;
|
||||
r.SetTopLeft(p);
|
||||
r.SetHeight(0);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
CacheItem(i);
|
||||
wxHtmlCell *aCell = m_cache->Get(i);
|
||||
r.height = aCell->GetHeight() + aCell->GetDescent() + (2 * CELL_BORDER);
|
||||
r.width = aCell->GetWidth();
|
||||
if (r.Contains(pos)) {
|
||||
cell = aCell;
|
||||
// convert mouse coordinates to coords relative to item's wxHtmlCell:
|
||||
pos -= r.GetTopLeft();
|
||||
return true;
|
||||
}
|
||||
r.y += r.height + (2 * GetMargins().y);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t CBOINCHtmlListBox::GetItemForCell(const wxHtmlCell *cell) const
|
||||
{
|
||||
wxCHECK_MSG( cell, 0, _T("no cell") );
|
||||
|
||||
cell = cell->GetRootCell();
|
||||
|
||||
wxCHECK_MSG( cell, 0, _T("no root cell") );
|
||||
|
||||
// the cell's ID contains item index, see CacheItem():
|
||||
unsigned long n;
|
||||
if ( !cell->GetId().ToULong(&n) )
|
||||
{
|
||||
wxFAIL_MSG( _T("unexpected root cell's ID") );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
wxPoint
|
||||
CBOINCHtmlListBox::CellCoordsToPhysical(const wxPoint& pos, wxHtmlCell *cell) const
|
||||
{
|
||||
return pos + GetRootCellCoords(GetItemForCell(cell));
|
||||
}
|
||||
|
||||
void CBOINCHtmlListBox::OnInternalIdle()
|
||||
{
|
||||
CBOINCVListBox::OnInternalIdle();
|
||||
|
||||
if ( wxHtmlWindowMouseHelper::DidMouseMove() )
|
||||
{
|
||||
wxPoint pos = ScreenToClient(wxGetMousePosition());
|
||||
wxHtmlCell *cell;
|
||||
|
||||
if ( !PhysicalCoordsToCell(pos, cell) )
|
||||
return;
|
||||
|
||||
wxHtmlWindowMouseHelper::HandleIdle(cell, pos);
|
||||
}
|
||||
}
|
||||
|
||||
void CBOINCHtmlListBox::OnMouseMove(wxMouseEvent& event)
|
||||
{
|
||||
wxHtmlWindowMouseHelper::HandleMouseMoved();
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void CBOINCHtmlListBox::OnLeftDown(wxMouseEvent& event)
|
||||
{
|
||||
wxPoint pos = event.GetPosition();
|
||||
wxHtmlCell *cell;
|
||||
|
||||
if ( !PhysicalCoordsToCell(pos, cell) )
|
||||
{
|
||||
event.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !wxHtmlWindowMouseHelper::HandleMouseClick(cell, pos, event) )
|
||||
{
|
||||
// no link was clicked, so let the listbox code handle the click (e.g.
|
||||
// by selecting another item in the list):
|
||||
event.Skip();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // wxUSE_HTML
|
|
@ -0,0 +1,196 @@
|
|||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2008 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
// as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// BOINC is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Adapted from htmllbox.h by Vadim Zeitlin <vadim@wxwindows.org>
|
||||
|
||||
#ifndef _HTMLLBOX_H_
|
||||
#define _HTMLLBOX_H_
|
||||
|
||||
#include "BOINCVListBox.h" // base class
|
||||
|
||||
class WXDLLIMPEXP_FWD_HTML wxHtmlCell;
|
||||
class WXDLLIMPEXP_FWD_HTML wxHtmlWinParser;
|
||||
class WXDLLIMPEXP_FWD_HTML CBOINCHtmlListBoxCache;
|
||||
class WXDLLIMPEXP_FWD_HTML CBOINCHtmlListBoxStyle;
|
||||
|
||||
extern WXDLLIMPEXP_DATA_HTML(const wxChar) BOINCHtmlListBoxNameStr[];
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCHtmlListBox
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// small border always added to the cells:
|
||||
#define CELL_BORDER 2
|
||||
|
||||
class WXDLLIMPEXP_HTML CBOINCHtmlListBox : public CBOINCVListBox,
|
||||
public wxHtmlWindowInterface,
|
||||
public wxHtmlWindowMouseHelper
|
||||
{
|
||||
DECLARE_ABSTRACT_CLASS(CBOINCHtmlListBox)
|
||||
public:
|
||||
// constructors and such
|
||||
// ---------------------
|
||||
|
||||
// default constructor, you must call Create() later
|
||||
CBOINCHtmlListBox();
|
||||
|
||||
// normal constructor which calls Create() internally
|
||||
CBOINCHtmlListBox(wxWindow *parent,
|
||||
wxWindowID id = wxID_ANY,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = 0,
|
||||
const wxString& name = BOINCHtmlListBoxNameStr);
|
||||
|
||||
// really creates the control and sets the initial number of items in it
|
||||
// (which may be changed later with SetItemCount())
|
||||
//
|
||||
// the only special style which may be specified here is wxLB_MULTIPLE
|
||||
//
|
||||
// returns true on success or false if the control couldn't be created
|
||||
bool Create(wxWindow *parent,
|
||||
wxWindowID id = wxID_ANY,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = 0,
|
||||
const wxString& name = BOINCHtmlListBoxNameStr);
|
||||
|
||||
// destructor cleans up whatever resources we use
|
||||
virtual ~CBOINCHtmlListBox();
|
||||
|
||||
// override some base class virtuals
|
||||
virtual void RefreshItem(size_t line);
|
||||
virtual void RefreshItems(size_t from, size_t to);
|
||||
virtual void SetItemCount(size_t count);
|
||||
|
||||
#if wxUSE_FILESYSTEM
|
||||
// retrieve the file system used by the wxHtmlWinParser: if you use
|
||||
// relative paths in your HTML, you should use its ChangePathTo() method
|
||||
wxFileSystem& GetFileSystem() { return m_filesystem; }
|
||||
const wxFileSystem& GetFileSystem() const { return m_filesystem; }
|
||||
#endif // wxUSE_FILESYSTEM
|
||||
|
||||
virtual void OnInternalIdle();
|
||||
|
||||
int HitTest(const wxPoint& pos);
|
||||
|
||||
void GetItemRect(size_t item, wxRect& rect) ;
|
||||
|
||||
protected:
|
||||
// this method must be implemented in the derived class and should return
|
||||
// the body (i.e. without <html>) of the HTML for the given item
|
||||
virtual wxString OnGetItem(size_t n) const = 0;
|
||||
|
||||
// this function may be overridden to decorate HTML returned by OnGetItem()
|
||||
virtual wxString OnGetItemMarkup(size_t n) const;
|
||||
|
||||
|
||||
// this method allows to customize the selection appearance: it may be used
|
||||
// to specify the colour of the text which normally has the given colour
|
||||
// colFg when it is inside the selection
|
||||
//
|
||||
// by default, the original colour is not used at all and all text has the
|
||||
// same (default for this system) colour inside selection
|
||||
virtual wxColour GetSelectedTextColour(const wxColour& colFg) const;
|
||||
|
||||
// this is the same as GetSelectedTextColour() but allows to customize the
|
||||
// background colour -- this is even more rarely used as you can change it
|
||||
// globally using SetSelectionBackground()
|
||||
virtual wxColour GetSelectedTextBgColour(const wxColour& colBg) const;
|
||||
|
||||
|
||||
// These functions are not supposed to be overridden by our descendants
|
||||
virtual void OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const;
|
||||
virtual wxCoord OnMeasureItem(size_t n) const;
|
||||
virtual wxCoord GetMaxItemWidth() const;
|
||||
|
||||
// This method may be overriden to handle clicking on a link in
|
||||
// the listbox. By default, clicking links is ignored.
|
||||
virtual void OnLinkClicked(size_t n, const wxHtmlLinkInfo& link);
|
||||
|
||||
// event handlers
|
||||
void OnSize(wxSizeEvent& event);
|
||||
void OnMouseMove(wxMouseEvent& event);
|
||||
void OnLeftDown(wxMouseEvent& event);
|
||||
|
||||
|
||||
// common part of all ctors
|
||||
void Init();
|
||||
|
||||
// ensure that the given item is cached
|
||||
void CacheItem(size_t n) const;
|
||||
|
||||
private:
|
||||
// wxHtmlWindowInterface methods:
|
||||
virtual void SetHTMLWindowTitle(const wxString& title);
|
||||
virtual void OnHTMLLinkClicked(const wxHtmlLinkInfo& link);
|
||||
virtual wxHtmlOpeningStatus OnHTMLOpeningURL(wxHtmlURLType type,
|
||||
const wxString& url,
|
||||
wxString *redirect) const;
|
||||
virtual wxPoint HTMLCoordsToWindow(wxHtmlCell *cell,
|
||||
const wxPoint& pos) const;
|
||||
virtual wxWindow* GetHTMLWindow();
|
||||
virtual wxColour GetHTMLBackgroundColour() const;
|
||||
virtual void SetHTMLBackgroundColour(const wxColour& clr);
|
||||
virtual void SetHTMLBackgroundImage(const wxBitmap& bmpBg);
|
||||
virtual void SetHTMLStatusText(const wxString& text);
|
||||
virtual wxCursor GetHTMLCursor(HTMLCursor type) const;
|
||||
|
||||
// returns index of item that contains given HTML cell
|
||||
size_t GetItemForCell(const wxHtmlCell *cell) const;
|
||||
|
||||
// return physical coordinates of root wxHtmlCell of n-th item
|
||||
wxPoint GetRootCellCoords(size_t n) const;
|
||||
|
||||
// Converts physical coordinates stored in @a pos into coordinates
|
||||
// relative to the root cell of the item under mouse cursor, if any. If no
|
||||
// cell is found under the cursor, returns false. Otherwise stores the new
|
||||
// coordinates back into @a pos and pointer to the cell under cursor into
|
||||
// @a cell and returns true.
|
||||
bool PhysicalCoordsToCell(wxPoint& pos, wxHtmlCell*& cell) const;
|
||||
|
||||
// The opposite of PhysicalCoordsToCell: converts coordinates relative to
|
||||
// given cell to physical coordinates in the window
|
||||
wxPoint CellCoordsToPhysical(const wxPoint& pos, wxHtmlCell *cell) const;
|
||||
|
||||
private:
|
||||
// this class caches the pre-parsed HTML to speed up display
|
||||
CBOINCHtmlListBoxCache *m_cache;
|
||||
|
||||
// HTML parser we use
|
||||
wxHtmlWinParser *m_htmlParser;
|
||||
|
||||
#if wxUSE_FILESYSTEM
|
||||
// file system used by m_htmlParser
|
||||
wxFileSystem m_filesystem;
|
||||
#endif // wxUSE_FILESYSTEM
|
||||
|
||||
// rendering style for the parser which allows us to customize our colours
|
||||
CBOINCHtmlListBoxStyle *m_htmlRendStyle;
|
||||
|
||||
|
||||
// it calls our GetSelectedTextColour() and GetSelectedTextBgColour()
|
||||
friend class CBOINCHtmlListBoxStyle;
|
||||
friend class wxHtmlListBoxWinInterface;
|
||||
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
DECLARE_NO_COPY_CLASS(CBOINCHtmlListBox)
|
||||
};
|
||||
|
||||
#endif // _WX_HTMLLBOX_H_
|
||||
|
|
@ -0,0 +1,690 @@
|
|||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2008 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
// as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// BOINC is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Adapted from vlbox.cpp by Vadim Zeitlin <vadim@wxwindows.org>
|
||||
|
||||
// ============================================================================
|
||||
// declarations
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// headers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if wxUSE_LISTBOX
|
||||
|
||||
#include "BOINCVListBox.h"
|
||||
|
||||
#include "wx/selstore.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// event tables
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
BEGIN_EVENT_TABLE(CBOINCVListBox, wxScrolledWindow)
|
||||
EVT_PAINT(CBOINCVListBox::OnPaint)
|
||||
EVT_SIZE(CBOINCVListBox::OnSize)
|
||||
|
||||
#if ALLOW_NOTICES_SELECTION
|
||||
EVT_KEY_DOWN(CBOINCVListBox::OnKeyDown)
|
||||
EVT_LEFT_DOWN(CBOINCVListBox::OnLeftDown)
|
||||
EVT_LEFT_DCLICK(CBOINCVListBox::OnLeftDClick)
|
||||
#endif // ALLOW_NOTICES_SELECTION
|
||||
END_EVENT_TABLE()
|
||||
|
||||
// ============================================================================
|
||||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
IMPLEMENT_ABSTRACT_CLASS(CBOINCVListBox, wxScrolledWindow)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCVListBox creation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void CBOINCVListBox::Init()
|
||||
{
|
||||
m_current =
|
||||
m_anchor = wxNOT_FOUND;
|
||||
m_selStore = NULL;
|
||||
m_iItemCount = 0;
|
||||
}
|
||||
|
||||
bool CBOINCVListBox::Create(wxWindow *parent,
|
||||
wxWindowID id,
|
||||
const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
long style,
|
||||
const wxString& name)
|
||||
{
|
||||
style |= wxWANTS_CHARS | wxFULL_REPAINT_ON_RESIZE;
|
||||
if ( !wxScrolledWindow::Create(parent, id, pos, size, style, name) )
|
||||
return false;
|
||||
|
||||
if ( style & wxLB_MULTIPLE )
|
||||
m_selStore = new wxSelectionStore;
|
||||
|
||||
// make sure the native widget has the right colour since we do
|
||||
// transparent drawing by default
|
||||
SetBackgroundColour(GetBackgroundColour());
|
||||
m_colBgSel = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
|
||||
|
||||
// flicker-free drawing requires this
|
||||
SetBackgroundStyle(wxBG_STYLE_CUSTOM);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CBOINCVListBox::~CBOINCVListBox()
|
||||
{
|
||||
delete m_selStore;
|
||||
}
|
||||
|
||||
void CBOINCVListBox::SetItemCount(size_t count)
|
||||
{
|
||||
// don't leave the current index invalid
|
||||
if ( m_current != wxNOT_FOUND && (size_t)m_current >= count )
|
||||
m_current = count - 1; // also ok when count == 0 as wxNOT_FOUND == -1
|
||||
|
||||
if ( m_selStore )
|
||||
{
|
||||
// tell the selection store that our number of items has changed
|
||||
m_selStore->SetItemCount(count);
|
||||
}
|
||||
|
||||
m_iItemCount = count;
|
||||
|
||||
UpdateScrollbar();
|
||||
}
|
||||
|
||||
|
||||
void CBOINCVListBox::UpdateScrollbar() {
|
||||
// do sum up their heights
|
||||
int height = 0, width = GetMaxItemWidth();
|
||||
for ( int i = 0; i < m_iItemCount; ++i )
|
||||
{
|
||||
height += OnGetItemHeight(i);
|
||||
}
|
||||
|
||||
SetVirtualSize(width, height);
|
||||
SetScrollRate(0, PIXELS_PER_VERTICAL_SCROLL_UNIT);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if ALLOW_NOTICES_SELECTION
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// selection handling
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool CBOINCVListBox::IsSelected(size_t line) const
|
||||
{
|
||||
return m_selStore ? m_selStore->IsSelected(line) : (int)line == m_current;
|
||||
}
|
||||
|
||||
bool CBOINCVListBox::Select(size_t item, bool select)
|
||||
{
|
||||
wxCHECK_MSG( m_selStore, false,
|
||||
_T("Select() may only be used with multiselection listbox") );
|
||||
|
||||
wxCHECK_MSG( item < GetItemCount(), false,
|
||||
_T("Select(): invalid item index") );
|
||||
|
||||
bool changed = m_selStore->SelectItem(item, select);
|
||||
if ( changed )
|
||||
{
|
||||
// selection really changed
|
||||
RefreshItem(item);
|
||||
}
|
||||
|
||||
DoSetCurrent(item);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool CBOINCVListBox::SelectRange(size_t from, size_t to)
|
||||
{
|
||||
wxCHECK_MSG( m_selStore, false,
|
||||
_T("SelectRange() may only be used with multiselection listbox") );
|
||||
|
||||
// make sure items are in correct order
|
||||
if ( from > to )
|
||||
{
|
||||
size_t tmp = from;
|
||||
from = to;
|
||||
to = tmp;
|
||||
}
|
||||
|
||||
wxCHECK_MSG( to < GetItemCount(), false,
|
||||
_T("SelectRange(): invalid item index") );
|
||||
|
||||
wxArrayInt changed;
|
||||
if ( !m_selStore->SelectRange(from, to, true, &changed) )
|
||||
{
|
||||
// too many items have changed, we didn't record them in changed array
|
||||
// so we have no choice but to refresh everything between from and to
|
||||
RefreshItems(from, to);
|
||||
}
|
||||
else // we've got the indices of the changed items
|
||||
{
|
||||
const size_t count = changed.GetCount();
|
||||
if ( !count )
|
||||
{
|
||||
// nothing changed
|
||||
return false;
|
||||
}
|
||||
|
||||
// refresh just the lines which have really changed
|
||||
for ( size_t n = 0; n < count; n++ )
|
||||
{
|
||||
RefreshItem(changed[n]);
|
||||
}
|
||||
}
|
||||
|
||||
// something changed
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBOINCVListBox::DoSelectAll(bool select)
|
||||
{
|
||||
wxCHECK_MSG( m_selStore, false,
|
||||
_T("SelectAll may only be used with multiselection listbox") );
|
||||
|
||||
size_t count = GetItemCount();
|
||||
if ( count )
|
||||
{
|
||||
wxArrayInt changed;
|
||||
if ( !m_selStore->SelectRange(0, count - 1, select) ||
|
||||
!changed.IsEmpty() )
|
||||
{
|
||||
Refresh();
|
||||
|
||||
// something changed
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBOINCVListBox::DoSetCurrent(int current)
|
||||
{
|
||||
wxASSERT_MSG( current == wxNOT_FOUND ||
|
||||
(current >= 0 && (size_t)current < GetItemCount()),
|
||||
_T("CBOINCVListBox::DoSetCurrent(): invalid item index") );
|
||||
|
||||
if ( current == m_current )
|
||||
{
|
||||
// nothing to do
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( m_current != wxNOT_FOUND )
|
||||
RefreshItem(m_current);
|
||||
|
||||
m_current = current;
|
||||
|
||||
if ( m_current != wxNOT_FOUND )
|
||||
{
|
||||
// if the line is not visible at all, we scroll it into view but we
|
||||
// don't need to refresh it -- it will be redrawn anyhow
|
||||
if ( !IsVisible(m_current) )
|
||||
{
|
||||
ScrollToLine(m_current);
|
||||
}
|
||||
else // line is at least partly visible
|
||||
{
|
||||
// it is, indeed, only partly visible, so scroll it into view to
|
||||
// make it entirely visible
|
||||
while ( (size_t)m_current == GetLastVisibleLine() &&
|
||||
ScrollToLine(GetVisibleBegin()+1) ) ;
|
||||
|
||||
// but in any case refresh it as even if it was only partly visible
|
||||
// before we need to redraw it entirely as its background changed
|
||||
RefreshItem(m_current);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBOINCVListBox::SendSelectedEvent()
|
||||
{
|
||||
wxASSERT_MSG( m_current != wxNOT_FOUND,
|
||||
_T("SendSelectedEvent() shouldn't be called") );
|
||||
|
||||
wxCommandEvent event(wxEVT_COMMAND_LISTBOX_SELECTED, GetId());
|
||||
event.SetEventObject(this);
|
||||
event.SetInt(m_current);
|
||||
|
||||
(void)GetEventHandler()->ProcessEvent(event);
|
||||
}
|
||||
|
||||
void CBOINCVListBox::SetSelection(int selection)
|
||||
{
|
||||
wxCHECK_RET( selection == wxNOT_FOUND ||
|
||||
(selection >= 0 && (size_t)selection < GetItemCount()),
|
||||
_T("CBOINCVListBox::SetSelection(): invalid item index") );
|
||||
|
||||
if ( HasMultipleSelection() )
|
||||
{
|
||||
if (selection != wxNOT_FOUND)
|
||||
Select(selection);
|
||||
else
|
||||
DeselectAll();
|
||||
m_anchor = selection;
|
||||
}
|
||||
|
||||
DoSetCurrent(selection);
|
||||
}
|
||||
|
||||
size_t CBOINCVListBox::GetSelectedCount() const
|
||||
{
|
||||
return m_selStore ? m_selStore->GetSelectedCount()
|
||||
: m_current == wxNOT_FOUND ? 0 : 1;
|
||||
}
|
||||
|
||||
int CBOINCVListBox::GetFirstSelected(unsigned long& cookie) const
|
||||
{
|
||||
cookie = 0;
|
||||
|
||||
return GetNextSelected(cookie);
|
||||
}
|
||||
|
||||
int CBOINCVListBox::GetNextSelected(unsigned long& cookie) const
|
||||
{
|
||||
wxCHECK_MSG( m_selStore, wxNOT_FOUND,
|
||||
_T("GetFirst/NextSelected() may only be used with multiselection listboxes") );
|
||||
|
||||
while ( cookie < GetItemCount() )
|
||||
{
|
||||
if ( IsSelected(cookie++) )
|
||||
return cookie - 1;
|
||||
}
|
||||
|
||||
return wxNOT_FOUND;
|
||||
}
|
||||
|
||||
#endif // ALLOW_NOTICES_SELECTION
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCVListBox appearance parameters
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void CBOINCVListBox::SetMargins(const wxPoint& pt)
|
||||
{
|
||||
if ( pt != m_ptMargins )
|
||||
{
|
||||
m_ptMargins = pt;
|
||||
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void CBOINCVListBox::SetSelectionBackground(const wxColour& col)
|
||||
{
|
||||
m_colBgSel = col;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCVListBox painting
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxCoord CBOINCVListBox::OnGetItemHeight(size_t item) const
|
||||
{
|
||||
return OnMeasureItem(item) + (2 * m_ptMargins.y);
|
||||
}
|
||||
|
||||
void CBOINCVListBox::OnDrawSeparator(wxDC& WXUNUSED(dc),
|
||||
wxRect& WXUNUSED(rect),
|
||||
size_t WXUNUSED(n)) const
|
||||
{
|
||||
}
|
||||
|
||||
void CBOINCVListBox::OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const
|
||||
{
|
||||
#if ALLOW_NOTICES_SELECTION
|
||||
// we need to render selected and current items differently
|
||||
const bool isSelected = IsSelected(n),
|
||||
isCurrent = IsCurrent(n);
|
||||
if ( isSelected || isCurrent )
|
||||
{
|
||||
if ( isSelected )
|
||||
{
|
||||
dc.SetBrush(wxBrush(m_colBgSel, wxSOLID));
|
||||
}
|
||||
else // !selected
|
||||
{
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
}
|
||||
|
||||
dc.SetPen(*(isCurrent ? wxBLACK_PEN : wxTRANSPARENT_PEN));
|
||||
|
||||
dc.DrawRectangle(rect);
|
||||
}
|
||||
//else: do nothing for the normal items
|
||||
#endif // ALLOW_NOTICES_SELECTION
|
||||
}
|
||||
|
||||
void CBOINCVListBox::OnPaint(wxPaintEvent& WXUNUSED(event))
|
||||
{
|
||||
int x, y;
|
||||
int itemMax;
|
||||
wxRect rectItem;
|
||||
wxSize clientSize = GetClientSize();
|
||||
|
||||
wxAutoBufferedPaintDC dc(this);
|
||||
DoPrepareDC(dc);
|
||||
|
||||
// the update rectangle
|
||||
wxRect rectUpdate = GetUpdateClientRect();
|
||||
GetViewStart(&x, &y);
|
||||
rectUpdate.x += x*PIXELS_PER_HORIZONTAL_SCROLL_UNIT;
|
||||
rectUpdate.y += y*PIXELS_PER_VERTICAL_SCROLL_UNIT;
|
||||
|
||||
// fill it with background colour
|
||||
dc.SetBackground(GetBackgroundColour());
|
||||
dc.Clear();
|
||||
|
||||
// the bounding rectangle of the current item
|
||||
rectItem.width = clientSize.x;
|
||||
|
||||
// iterate over all items
|
||||
itemMax = GetItemCount();
|
||||
for ( int item = 0; item < itemMax; item++ )
|
||||
{
|
||||
const wxCoord hItem = OnGetItemHeight(item);
|
||||
|
||||
rectItem.height = hItem;
|
||||
|
||||
// and draw the ones which intersect the update rect
|
||||
if ( rectItem.Intersects(rectUpdate) )
|
||||
{
|
||||
// don't allow drawing outside of the items rectangle
|
||||
wxDCClipper clip(dc, rectItem);
|
||||
|
||||
wxRect rect = rectItem;
|
||||
OnDrawBackground(dc, rect, item);
|
||||
|
||||
OnDrawSeparator(dc, rect, item);
|
||||
|
||||
rect.Deflate(m_ptMargins.x, m_ptMargins.y);
|
||||
OnDrawItem(dc, rect, item);
|
||||
}
|
||||
else // no intersection
|
||||
{
|
||||
if ( rectItem.GetTop() > rectUpdate.GetBottom() )
|
||||
{
|
||||
// we are already below the update rect, no need to continue
|
||||
// further
|
||||
break;
|
||||
}
|
||||
//else: the next item may intersect the update rect
|
||||
}
|
||||
|
||||
rectItem.y += hItem;
|
||||
}
|
||||
}
|
||||
|
||||
void CBOINCVListBox::OnSize(wxSizeEvent& event)
|
||||
{
|
||||
UpdateScrollbar();
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
#if ALLOW_NOTICES_SELECTION
|
||||
|
||||
// ============================================================================
|
||||
// CBOINCVListBox keyboard/mouse handling
|
||||
// ============================================================================
|
||||
|
||||
void CBOINCVListBox::DoHandleItemClick(int item, int flags)
|
||||
{
|
||||
// has anything worth telling the client code about happened?
|
||||
bool notify = false;
|
||||
|
||||
if ( HasMultipleSelection() )
|
||||
{
|
||||
// select the iteem clicked?
|
||||
bool select = true;
|
||||
|
||||
// NB: the keyboard interface we implement here corresponds to
|
||||
// wxLB_EXTENDED rather than wxLB_MULTIPLE but this one makes more
|
||||
// sense IMHO
|
||||
if ( flags & ItemClick_Shift )
|
||||
{
|
||||
if ( m_current != wxNOT_FOUND )
|
||||
{
|
||||
if ( m_anchor == wxNOT_FOUND )
|
||||
m_anchor = m_current;
|
||||
|
||||
select = false;
|
||||
|
||||
// only the range from the selection anchor to new m_current
|
||||
// must be selected
|
||||
if ( DeselectAll() )
|
||||
notify = true;
|
||||
|
||||
if ( SelectRange(m_anchor, item) )
|
||||
notify = true;
|
||||
}
|
||||
//else: treat it as ordinary click/keypress
|
||||
}
|
||||
else // Shift not pressed
|
||||
{
|
||||
m_anchor = item;
|
||||
|
||||
if ( flags & ItemClick_Ctrl )
|
||||
{
|
||||
select = false;
|
||||
|
||||
if ( !(flags & ItemClick_Kbd) )
|
||||
{
|
||||
Toggle(item);
|
||||
|
||||
// the status of the item has definitely changed
|
||||
notify = true;
|
||||
}
|
||||
//else: Ctrl-arrow pressed, don't change selection
|
||||
}
|
||||
//else: behave as in single selection case
|
||||
}
|
||||
|
||||
if ( select )
|
||||
{
|
||||
// make the clicked item the only selection
|
||||
if ( DeselectAll() )
|
||||
notify = true;
|
||||
|
||||
if ( Select(item) )
|
||||
notify = true;
|
||||
}
|
||||
}
|
||||
|
||||
// in any case the item should become the current one
|
||||
if ( DoSetCurrent(item) )
|
||||
{
|
||||
if ( !HasMultipleSelection() )
|
||||
{
|
||||
// this has also changed the selection for single selection case
|
||||
notify = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( notify )
|
||||
{
|
||||
// notify the user about the selection change
|
||||
SendSelectedEvent();
|
||||
}
|
||||
//else: nothing changed at all
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// keyboard handling
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void CBOINCVListBox::OnKeyDown(wxKeyEvent& event)
|
||||
{
|
||||
// flags for DoHandleItemClick()
|
||||
int flags = ItemClick_Kbd;
|
||||
|
||||
int current;
|
||||
switch ( event.GetKeyCode() )
|
||||
{
|
||||
case WXK_HOME:
|
||||
current = 0;
|
||||
break;
|
||||
|
||||
case WXK_END:
|
||||
current = GetLineCount() - 1;
|
||||
break;
|
||||
|
||||
case WXK_DOWN:
|
||||
if ( m_current == (int)GetLineCount() - 1 )
|
||||
return;
|
||||
|
||||
current = m_current + 1;
|
||||
break;
|
||||
|
||||
case WXK_UP:
|
||||
if ( m_current == wxNOT_FOUND )
|
||||
current = GetLineCount() - 1;
|
||||
else if ( m_current != 0 )
|
||||
current = m_current - 1;
|
||||
else // m_current == 0
|
||||
return;
|
||||
break;
|
||||
|
||||
case WXK_PAGEDOWN:
|
||||
PageDown();
|
||||
current = GetFirstVisibleLine();
|
||||
break;
|
||||
|
||||
case WXK_PAGEUP:
|
||||
if ( m_current == (int)GetFirstVisibleLine() )
|
||||
{
|
||||
PageUp();
|
||||
}
|
||||
|
||||
current = GetFirstVisibleLine();
|
||||
break;
|
||||
|
||||
case WXK_SPACE:
|
||||
// hack: pressing space should work like a mouse click rather than
|
||||
// like a keyboard arrow press, so trick DoHandleItemClick() in
|
||||
// thinking we were clicked
|
||||
flags &= ~ItemClick_Kbd;
|
||||
current = m_current;
|
||||
break;
|
||||
|
||||
#ifdef __WXMSW__
|
||||
case WXK_TAB:
|
||||
// Since we are using wxWANTS_CHARS we need to send navigation
|
||||
// events for the tabs on MSW
|
||||
{
|
||||
wxNavigationKeyEvent ne;
|
||||
ne.SetDirection(!event.ShiftDown());
|
||||
ne.SetCurrentFocus(this);
|
||||
ne.SetEventObject(this);
|
||||
GetParent()->GetEventHandler()->ProcessEvent(ne);
|
||||
}
|
||||
// fall through to default
|
||||
#endif
|
||||
default:
|
||||
event.Skip();
|
||||
current = 0; // just to silent the stupid compiler warnings
|
||||
wxUnusedVar(current);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( event.ShiftDown() )
|
||||
flags |= ItemClick_Shift;
|
||||
if ( event.ControlDown() )
|
||||
flags |= ItemClick_Ctrl;
|
||||
|
||||
DoHandleItemClick(current, flags);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCVListBox mouse handling
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void CBOINCVListBox::OnLeftDown(wxMouseEvent& event)
|
||||
{
|
||||
SetFocus();
|
||||
|
||||
int item = HitTest(event.GetPosition());
|
||||
|
||||
if ( item != wxNOT_FOUND )
|
||||
{
|
||||
int flags = 0;
|
||||
if ( event.ShiftDown() )
|
||||
flags |= ItemClick_Shift;
|
||||
|
||||
// under Mac Apple-click is used in the same way as Ctrl-click
|
||||
// elsewhere
|
||||
#ifdef __WXMAC__
|
||||
if ( event.MetaDown() )
|
||||
#else
|
||||
if ( event.ControlDown() )
|
||||
#endif
|
||||
flags |= ItemClick_Ctrl;
|
||||
|
||||
DoHandleItemClick(item, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void CBOINCVListBox::OnLeftDClick(wxMouseEvent& eventMouse)
|
||||
{
|
||||
int item = HitTest(eventMouse.GetPosition());
|
||||
if ( item != wxNOT_FOUND )
|
||||
{
|
||||
|
||||
// if item double-clicked was not yet selected, then treat
|
||||
// this event as a left-click instead
|
||||
if ( item == m_current )
|
||||
{
|
||||
wxCommandEvent event(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, GetId());
|
||||
event.SetEventObject(this);
|
||||
event.SetInt(item);
|
||||
|
||||
(void)GetEventHandler()->ProcessEvent(event);
|
||||
}
|
||||
else
|
||||
{
|
||||
OnLeftDown(eventMouse);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ALLOW_NOTICES_SELECTION
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// use the same default attributes as wxListBox
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
//static
|
||||
wxVisualAttributes
|
||||
CBOINCVListBox::GetClassDefaultAttributes(wxWindowVariant variant)
|
||||
{
|
||||
return wxListBox::GetClassDefaultAttributes(variant);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,340 @@
|
|||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2008 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
// as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// BOINC is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Adapted from vlbox.h by Vadim Zeitlin <vadim@wxwindows.org>
|
||||
|
||||
#ifndef _VLBOX_H_
|
||||
#define _VLBOX_H_
|
||||
|
||||
//#include "wx/vscroll.h" // base class
|
||||
//#include "wx/bitmap.h"
|
||||
|
||||
class WXDLLIMPEXP_FWD_CORE wxSelectionStore;
|
||||
|
||||
#define BOINCVListBoxNameStr _T("BOINCVListBox")
|
||||
|
||||
#define ALLOW_NOTICES_SELECTION false
|
||||
|
||||
#define PIXELS_PER_VERTICAL_SCROLL_UNIT 10
|
||||
#define PIXELS_PER_HORIZONTAL_SCROLL_UNIT 10
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CBOINCVListBox
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
This class has two main differences from a regular listbox: it can have an
|
||||
arbitrarily huge number of items because it doesn't store them itself but
|
||||
uses OnDrawItem() callback to draw them and its items can have variable
|
||||
height as determined by OnMeasureItem().
|
||||
|
||||
It emits the same events as wxListBox and the same event macros may be used
|
||||
with it.
|
||||
*/
|
||||
class WXDLLEXPORT CBOINCVListBox : public wxScrolledWindow
|
||||
{
|
||||
public:
|
||||
// constructors and such
|
||||
// ---------------------
|
||||
|
||||
// default constructor, you must call Create() later
|
||||
CBOINCVListBox() { Init(); }
|
||||
|
||||
// normal constructor which calls Create() internally
|
||||
CBOINCVListBox(wxWindow *parent,
|
||||
wxWindowID id = wxID_ANY,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = 0,
|
||||
const wxString& name = BOINCVListBoxNameStr)
|
||||
{
|
||||
Init();
|
||||
|
||||
(void)Create(parent, id, pos, size, style, name);
|
||||
}
|
||||
|
||||
// really creates the control and sets the initial number of items in it
|
||||
// (which may be changed later with SetItemCount())
|
||||
//
|
||||
// the only special style which may be specified here is wxLB_MULTIPLE
|
||||
//
|
||||
// returns true on success or false if the control couldn't be created
|
||||
bool Create(wxWindow *parent,
|
||||
wxWindowID id = wxID_ANY,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = 0,
|
||||
const wxString& name = BOINCVListBoxNameStr);
|
||||
|
||||
// dtor does some internal cleanup (deletes m_selStore if any)
|
||||
virtual ~CBOINCVListBox();
|
||||
|
||||
// common part of all ctors
|
||||
void Init();
|
||||
|
||||
// accessors
|
||||
// ---------
|
||||
|
||||
// get the number of items in the control
|
||||
size_t GetItemCount() const { return m_iItemCount; }
|
||||
|
||||
// is this item the current one?
|
||||
bool IsCurrent(size_t item) const { return item == (size_t)m_current; }
|
||||
|
||||
#if ALLOW_NOTICES_SELECTION
|
||||
|
||||
// does this control use multiple selection?
|
||||
bool HasMultipleSelection() const { return m_selStore != NULL; }
|
||||
|
||||
// get the currently selected item or wxNOT_FOUND if there is no selection
|
||||
//
|
||||
// this method is only valid for the single selection listboxes
|
||||
int GetSelection() const
|
||||
{
|
||||
wxASSERT_MSG( !HasMultipleSelection(),
|
||||
_T("GetSelection() can't be used with wxLB_MULTIPLE") );
|
||||
|
||||
return m_current;
|
||||
}
|
||||
|
||||
#ifdef __WXUNIVERSAL__
|
||||
bool IsCurrent() const { return wxScrolledWindow::IsCurrent(); }
|
||||
#endif
|
||||
|
||||
// is this item selected?
|
||||
bool IsSelected(size_t item) const;
|
||||
|
||||
// get the number of the selected items (maybe 0)
|
||||
//
|
||||
// this method is valid for both single and multi selection listboxes
|
||||
size_t GetSelectedCount() const;
|
||||
|
||||
// get the first selected item, returns wxNOT_FOUND if none
|
||||
//
|
||||
// cookie is an opaque parameter which should be passed to
|
||||
// GetNextSelected() later
|
||||
//
|
||||
// this method is only valid for the multi selection listboxes
|
||||
int GetFirstSelected(unsigned long& cookie) const;
|
||||
|
||||
// get next selection item, return wxNOT_FOUND if no more
|
||||
//
|
||||
// cookie must be the same parameter that was passed to GetFirstSelected()
|
||||
// before
|
||||
//
|
||||
// this method is only valid for the multi selection listboxes
|
||||
int GetNextSelected(unsigned long& cookie) const;
|
||||
|
||||
#else
|
||||
|
||||
bool IsSelected(size_t item) const { return false; }
|
||||
|
||||
#endif // ALLOW_NOTICES_SELECTION
|
||||
|
||||
// get the margins around each item
|
||||
wxPoint GetMargins() const { return m_ptMargins; }
|
||||
|
||||
// get the background colour of selected cells
|
||||
const wxColour& GetSelectionBackground() const { return m_colBgSel; }
|
||||
|
||||
|
||||
// operations
|
||||
// ----------
|
||||
|
||||
// set the number of items to be shown in the control
|
||||
virtual void SetItemCount(size_t count);
|
||||
|
||||
// delete all items from the control
|
||||
void Clear() { SetItemCount(0); }
|
||||
|
||||
void UpdateScrollbar();
|
||||
|
||||
#if ALLOW_NOTICES_SELECTION
|
||||
|
||||
// set the selection to the specified item, if it is wxNOT_FOUND the
|
||||
// selection is unset
|
||||
//
|
||||
// this function is only valid for the single selection listboxes
|
||||
void SetSelection(int selection);
|
||||
|
||||
// selects or deselects the specified item which must be valid (i.e. not
|
||||
// equal to wxNOT_FOUND)
|
||||
//
|
||||
// return true if the items selection status has changed or false
|
||||
// otherwise
|
||||
//
|
||||
// this function is only valid for the multiple selection listboxes
|
||||
bool Select(size_t item, bool select = true);
|
||||
|
||||
// selects the items in the specified range whose end points may be given
|
||||
// in any order
|
||||
//
|
||||
// return true if any items selection status has changed, false otherwise
|
||||
//
|
||||
// this function is only valid for the single selection listboxes
|
||||
bool SelectRange(size_t from, size_t to);
|
||||
|
||||
// toggle the selection of the specified item (must be valid)
|
||||
//
|
||||
// this function is only valid for the multiple selection listboxes
|
||||
void Toggle(size_t item) { Select(item, !IsSelected(item)); }
|
||||
|
||||
// select all items in the listbox
|
||||
//
|
||||
// the return code indicates if any items were affected by this operation
|
||||
// (true) or if nothing has changed (false)
|
||||
bool SelectAll() { return DoSelectAll(true); }
|
||||
|
||||
// unselect all items in the listbox
|
||||
//
|
||||
// the return code has the same meaning as for SelectAll()
|
||||
bool DeselectAll() { return DoSelectAll(false); }
|
||||
|
||||
#else
|
||||
|
||||
void SetSelection(int selection) { };
|
||||
|
||||
|
||||
|
||||
#endif // ALLOW_NOTICES_SELECTION
|
||||
|
||||
virtual void RefreshItem(size_t line) = 0;
|
||||
virtual void RefreshItems(size_t from, size_t to) = 0;
|
||||
|
||||
// set the margins: horizontal margin is the distance between the window
|
||||
// border and the item contents while vertical margin is half of the
|
||||
// distance between items
|
||||
//
|
||||
// by default both margins are 0
|
||||
void SetMargins(const wxPoint& pt);
|
||||
void SetMargins(wxCoord x, wxCoord y) { SetMargins(wxPoint(x, y)); }
|
||||
|
||||
// change the background colour of the selected cells
|
||||
void SetSelectionBackground(const wxColour& col);
|
||||
|
||||
|
||||
virtual wxVisualAttributes GetDefaultAttributes() const
|
||||
{
|
||||
return GetClassDefaultAttributes(GetWindowVariant());
|
||||
}
|
||||
|
||||
static wxVisualAttributes
|
||||
GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL);
|
||||
|
||||
protected:
|
||||
// the derived class must implement this function to actually draw the item
|
||||
// with the given index on the provided DC
|
||||
virtual void OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const = 0;
|
||||
|
||||
// the derived class must implement this method to return the height of the
|
||||
// specified item
|
||||
virtual wxCoord OnMeasureItem(size_t n) const = 0;
|
||||
// the derived class must implement this method to return the max width of
|
||||
// all the items
|
||||
virtual wxCoord GetMaxItemWidth() const = 0;
|
||||
|
||||
// this method may be used to draw separators between the lines; note that
|
||||
// the rectangle may be modified, typically to deflate it a bit before
|
||||
// passing to OnDrawItem()
|
||||
//
|
||||
// the base class version doesn't do anything
|
||||
virtual void OnDrawSeparator(wxDC& dc, wxRect& rect, size_t n) const;
|
||||
|
||||
// this method is used to draw the items background and, maybe, a border
|
||||
// around it
|
||||
//
|
||||
// the base class version implements a reasonable default behaviour which
|
||||
// consists in drawing the selected item with the standard background
|
||||
// colour and drawing a border around the item if it is either selected or
|
||||
// current
|
||||
virtual void OnDrawBackground(wxDC& dc, const wxRect& rect, size_t n) const;
|
||||
|
||||
// we implement OnGetLineHeight() in terms of OnMeasureItem() because this
|
||||
// allows us to add borders to the items easily
|
||||
//
|
||||
// this function is not supposed to be overridden by the derived classes
|
||||
virtual wxCoord OnGetItemHeight(size_t item) const;
|
||||
|
||||
// event handlers
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
void OnSize(wxSizeEvent& event);
|
||||
|
||||
#if ALLOW_NOTICES_SELECTION
|
||||
|
||||
void OnKeyDown(wxKeyEvent& event);
|
||||
void OnLeftDown(wxMouseEvent& event);
|
||||
void OnLeftDClick(wxMouseEvent& event);
|
||||
|
||||
|
||||
// send the wxEVT_COMMAND_LISTBOX_SELECTED event
|
||||
void SendSelectedEvent();
|
||||
|
||||
// common implementation of SelectAll() and DeselectAll()
|
||||
bool DoSelectAll(bool select);
|
||||
|
||||
// change the current item (in single selection listbox it also implicitly
|
||||
// changes the selection); current may be wxNOT_FOUND in which case there
|
||||
// will be no current item any more
|
||||
//
|
||||
// return true if the current item changed, false otherwise
|
||||
bool DoSetCurrent(int current);
|
||||
|
||||
// flags for DoHandleItemClick
|
||||
enum
|
||||
{
|
||||
ItemClick_Shift = 1, // item shift-clicked
|
||||
ItemClick_Ctrl = 2, // ctrl
|
||||
ItemClick_Kbd = 4 // item selected from keyboard
|
||||
};
|
||||
|
||||
// common part of keyboard and mouse handling processing code
|
||||
void DoHandleItemClick(int item, int flags);
|
||||
|
||||
#endif // ALLOW_NOTICES_SELECTION
|
||||
|
||||
private:
|
||||
int m_iItemCount;
|
||||
|
||||
// the current item or wxNOT_FOUND
|
||||
//
|
||||
// if m_selStore == NULL this is also the selected item, otherwise the
|
||||
// selections are managed by m_selStore
|
||||
int m_current;
|
||||
|
||||
// the anchor of the selection for the multiselection listboxes:
|
||||
// shift-clicking an item extends the selection from m_anchor to the item
|
||||
// clicked, for example
|
||||
//
|
||||
// always wxNOT_FOUND for single selection listboxes
|
||||
int m_anchor;
|
||||
|
||||
// the object managing our selected items if not NULL
|
||||
wxSelectionStore *m_selStore;
|
||||
|
||||
// margins
|
||||
wxPoint m_ptMargins;
|
||||
|
||||
// the selection bg colour
|
||||
wxColour m_colBgSel;
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
DECLARE_NO_COPY_CLASS(CBOINCVListBox)
|
||||
DECLARE_ABSTRACT_CLASS(CBOINCVListBox)
|
||||
};
|
||||
|
||||
#endif // _VLBOX_H_
|
||||
|
|
@ -99,23 +99,9 @@ wxAccStatus CNoticeListCtrlAccessible::GetLocation(wxRect& rect, int elementId)
|
|||
}
|
||||
else if (pCtrl && (0 != elementId))
|
||||
{
|
||||
// List item
|
||||
wxSize cCtrlSize = pCtrl->GetClientSize();
|
||||
pCtrl->GetItemRect(elementId - 1, rect);
|
||||
pCtrl->ClientToScreen(&rect.x, &rect.y);
|
||||
|
||||
// Set the initial control postition to the absolute coords of the upper
|
||||
// left hand position of the control
|
||||
rect.SetPosition(pCtrl->GetScreenPosition());
|
||||
rect.width = cCtrlSize.GetWidth() - 1;
|
||||
rect.height = pCtrl->GetItemHeight(elementId - 1) - 1;
|
||||
|
||||
// Items can have different heights
|
||||
int firstVisibleItem = (int)pCtrl->GetFirstVisibleLine();
|
||||
int yOffset = 0;
|
||||
for (int i=firstVisibleItem; i<(elementId - 1); ++i) {
|
||||
yOffset += pCtrl->GetItemHeight((size_t)i);
|
||||
}
|
||||
rect.SetTop(rect.GetTop() + yOffset);
|
||||
rect.height -= 1;
|
||||
return wxACC_OK;
|
||||
}
|
||||
// Let the framework handle the other cases.
|
||||
|
@ -143,6 +129,8 @@ wxAccStatus CNoticeListCtrlAccessible::GetChildCount(int* childCount)
|
|||
// window (e.g. an edit control).
|
||||
wxAccStatus CNoticeListCtrlAccessible::DoDefaultAction(int childId)
|
||||
{
|
||||
#if ALLOW_NOTICES_SELECTION
|
||||
|
||||
CNoticeListCtrl* pCtrl = wxDynamicCast(GetWindow(), CNoticeListCtrl);
|
||||
CMainDocument* pDoc = wxDynamicCast(wxGetApp().GetDocument(), CMainDocument);
|
||||
if (pCtrl && (childId != wxACC_SELF))
|
||||
|
@ -168,6 +156,8 @@ wxAccStatus CNoticeListCtrlAccessible::DoDefaultAction(int childId)
|
|||
|
||||
return wxACC_OK;
|
||||
}
|
||||
|
||||
#endif // ALLOW_NOTICES_SELECTION
|
||||
|
||||
// Let the framework handle the other cases.
|
||||
return wxACC_NOT_IMPLEMENTED;
|
||||
|
@ -403,7 +393,7 @@ DEFINE_EVENT_TYPE( wxEVT_NOTICELIST_ITEM_DISPLAY )
|
|||
/*!
|
||||
* CNoticeListCtrl type definition
|
||||
*/
|
||||
IMPLEMENT_DYNAMIC_CLASS( CNoticeListCtrl, wxHtmlListBox )
|
||||
IMPLEMENT_DYNAMIC_CLASS( CNoticeListCtrl, CBOINCHtmlListBox )
|
||||
IMPLEMENT_DYNAMIC_CLASS( NoticeListCtrlEvent, wxNotifyEvent )
|
||||
|
||||
|
||||
|
@ -411,7 +401,7 @@ IMPLEMENT_DYNAMIC_CLASS( NoticeListCtrlEvent, wxNotifyEvent )
|
|||
* CNoticeListCtrl event table definition
|
||||
*/
|
||||
|
||||
BEGIN_EVENT_TABLE( CNoticeListCtrl, wxHtmlListBox )
|
||||
BEGIN_EVENT_TABLE( CNoticeListCtrl, CBOINCHtmlListBox )
|
||||
|
||||
////@begin CNoticeListCtrl event table entries
|
||||
EVT_LISTBOX(ID_LIST_NOTIFICATIONSVIEW, CNoticeListCtrl::OnSelected)
|
||||
|
@ -456,7 +446,7 @@ bool CNoticeListCtrl::Create( wxWindow* parent )
|
|||
////@end CNoticeListCtrl member initialisation
|
||||
|
||||
////@begin CNoticeListCtrl creation
|
||||
wxHtmlListBox::Create( parent, ID_LIST_NOTIFICATIONSVIEW, wxDefaultPosition, wxDefaultSize,
|
||||
CBOINCHtmlListBox::Create( parent, ID_LIST_NOTIFICATIONSVIEW, wxDefaultPosition, wxDefaultSize,
|
||||
wxSUNKEN_BORDER | wxTAB_TRAVERSAL );
|
||||
|
||||
#if wxUSE_ACCESSIBILITY
|
||||
|
@ -593,8 +583,12 @@ bool CNoticeListCtrl::UpdateUI()
|
|||
wxASSERT(pDoc);
|
||||
wxASSERT(wxDynamicCast(pDoc, CMainDocument));
|
||||
|
||||
// Call Freeze() / Thaw() only when actually needed;
|
||||
// otherwise it causes unnecessary redraws
|
||||
if (pDoc->GetNoticeCount() < 0) {
|
||||
Freeze();
|
||||
SetItemCount(0);
|
||||
Thaw();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -602,8 +596,10 @@ bool CNoticeListCtrl::UpdateUI()
|
|||
((int)GetItemCount() != pDoc->GetNoticeCount()) ||
|
||||
pDoc->notices.complete
|
||||
) {
|
||||
Freeze();
|
||||
SetItemCount(pDoc->GetNoticeCount());
|
||||
pDoc->notices.complete = false;
|
||||
Thaw();
|
||||
}
|
||||
#ifdef __WXMAC__
|
||||
// Enable accessibility only after drawing the page
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#pragma interface "NoticeListCtrl.cpp"
|
||||
#endif
|
||||
|
||||
#include "BOINCHtmlLBox.h"
|
||||
|
||||
#if wxUSE_ACCESSIBILITY || defined(__WXMAC__)
|
||||
|
||||
|
@ -85,7 +86,7 @@ public:
|
|||
* CNoticeListCtrl class declaration
|
||||
*/
|
||||
|
||||
class CNoticeListCtrl: public wxHtmlListBox
|
||||
class CNoticeListCtrl: public CBOINCHtmlListBox
|
||||
{
|
||||
DECLARE_DYNAMIC_CLASS( CNoticeListCtrl )
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
@ -112,7 +113,7 @@ public:
|
|||
|
||||
bool UpdateUI();
|
||||
|
||||
int GetItemHeight(size_t i) { return (int)OnMeasureItem(i); }
|
||||
int GetItemHeight(size_t i) { return (int)OnGetItemHeight(i); }
|
||||
|
||||
private:
|
||||
#ifdef __WXMAC__
|
||||
|
|
|
@ -138,9 +138,8 @@ void CViewNotices::OnListRender(wxTimerEvent& WXUNUSED(event)) {
|
|||
}
|
||||
}
|
||||
|
||||
m_pHtmlListPane->Freeze();
|
||||
// Don't call Freeze() / Thaw() here because it causes an unnecessary redraw
|
||||
m_pHtmlListPane->UpdateUI();
|
||||
m_pHtmlListPane->Thaw();
|
||||
|
||||
pDoc->UpdateUnreadNoticeState();
|
||||
|
||||
|
|
|
@ -169,6 +169,8 @@
|
|||
DD4E704C0BCDAC360010A522 /* browser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DD4E70490BCDAC360010A522 /* browser.cpp */; };
|
||||
DD4EC65A08A0A7AF009AA08F /* gui_rpc_client_ops.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DD73E34E08A0694000656EB1 /* gui_rpc_client_ops.cpp */; };
|
||||
DD4EC65B08A0A83F009AA08F /* gui_rpc_client_print.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DD73E34F08A0694100656EB1 /* gui_rpc_client_print.cpp */; };
|
||||
DD4FA25D121828E400154856 /* BOINCHtmlLBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DD4FA25B121828E400154856 /* BOINCHtmlLBox.cpp */; };
|
||||
DD4FA2621218290600154856 /* BOINCVListBox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DD4FA2601218290600154856 /* BOINCVListBox.cpp */; };
|
||||
DD51DC8F0A4943A300BD24E6 /* check_security.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DD6617870A3FFD8C00FFEBEB /* check_security.cpp */; };
|
||||
DD52C81108B5D44D008D9AA4 /* gui_rpc_client.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DD81C5CC07C5D7D90098A04D /* gui_rpc_client.cpp */; };
|
||||
DD52C81208B5D44E008D9AA4 /* gui_rpc_client_ops.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DD73E34E08A0694000656EB1 /* gui_rpc_client_ops.cpp */; };
|
||||
|
@ -744,6 +746,10 @@
|
|||
DD4E704A0BCDAC360010A522 /* browser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = browser.h; path = ../clientgui/browser.h; sourceTree = SOURCE_ROOT; };
|
||||
DD4EC60F08A0A083009AA08F /* texture.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = texture.cpp; sourceTree = "<group>"; };
|
||||
DD4EC61008A0A083009AA08F /* texture.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = texture.h; path = ../api/texture.h; sourceTree = SOURCE_ROOT; };
|
||||
DD4FA25B121828E400154856 /* BOINCHtmlLBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BOINCHtmlLBox.cpp; path = ../clientgui/BOINCHtmlLBox.cpp; sourceTree = SOURCE_ROOT; };
|
||||
DD4FA25C121828E400154856 /* BOINCHtmlLBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BOINCHtmlLBox.h; path = ../clientgui/BOINCHtmlLBox.h; sourceTree = SOURCE_ROOT; };
|
||||
DD4FA2601218290600154856 /* BOINCVListBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BOINCVListBox.cpp; path = ../clientgui/BOINCVListBox.cpp; sourceTree = SOURCE_ROOT; };
|
||||
DD4FA2611218290600154856 /* BOINCVListBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BOINCVListBox.h; path = ../clientgui/BOINCVListBox.h; sourceTree = SOURCE_ROOT; };
|
||||
DD531BC50C193D3800742E50 /* MacInstaller.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = MacInstaller.icns; path = ../clientgui/res/MacInstaller.icns; sourceTree = SOURCE_ROOT; };
|
||||
DD531BC70C193D5200742E50 /* MacUninstaller.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = MacUninstaller.icns; path = ../clientgui/res/MacUninstaller.icns; sourceTree = SOURCE_ROOT; };
|
||||
DD58C41808F3343F00C1DF66 /* AccountInfoPage.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = AccountInfoPage.cpp; path = ../clientgui/AccountInfoPage.cpp; sourceTree = SOURCE_ROOT; };
|
||||
|
@ -1335,6 +1341,8 @@
|
|||
DD8DD4A609D9432F0043019E /* BOINCDialupManager.h */,
|
||||
DD81C40507C5D1020098A04D /* BOINCGUIApp.cpp */,
|
||||
DD81C43B07C5D2240098A04D /* BOINCGUIApp.h */,
|
||||
DD4FA25B121828E400154856 /* BOINCHtmlLBox.cpp */,
|
||||
DD4FA25C121828E400154856 /* BOINCHtmlLBox.h */,
|
||||
DD0A87FD11D950E00067C1F2 /* BOINCInternetFSHandler.cpp */,
|
||||
DD0A87FE11D950E00067C1F2 /* BOINCInternetFSHandler.h */,
|
||||
DD81C40407C5D1020098A04D /* BOINCListCtrl.cpp */,
|
||||
|
@ -1343,6 +1351,8 @@
|
|||
DD81C43D07C5D2240098A04D /* BOINCTaskBar.h */,
|
||||
DD81C40607C5D1020098A04D /* BOINCTaskCtrl.cpp */,
|
||||
DD81C43807C5D2240098A04D /* BOINCTaskCtrl.h */,
|
||||
DD4FA2601218290600154856 /* BOINCVListBox.cpp */,
|
||||
DD4FA2611218290600154856 /* BOINCVListBox.h */,
|
||||
DD4E70490BCDAC360010A522 /* browser.cpp */,
|
||||
DD4E704A0BCDAC360010A522 /* browser.h */,
|
||||
DDCE78220A70BD29008218B6 /* common */,
|
||||
|
@ -2571,6 +2581,8 @@
|
|||
DDBB7E7611D2BCD400598DC1 /* NoticeListCtrl.cpp in Sources */,
|
||||
DD0A87FF11D950E00067C1F2 /* BOINCInternetFSHandler.cpp in Sources */,
|
||||
DDA850A41207EED900B473A6 /* WizardAttach.cpp in Sources */,
|
||||
DD4FA25D121828E400154856 /* BOINCHtmlLBox.cpp in Sources */,
|
||||
DD4FA2621218290600154856 /* BOINCVListBox.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue