TracklistInfoView now fully working.

musik::core::tracklist::Standard is rewritten using boost::bimap instead of boost::multi_index.
win32cpp updated.
Started on MetadataFilterView filtering.
Fixed some pragma warnings in PCH files.
This commit is contained in:
Daniel Önnerby 2008-05-14 07:56:41 +00:00
parent d7025b15da
commit a9b137a9a8
21 changed files with 599 additions and 233 deletions

View File

@ -60,7 +60,7 @@ void Query::PlaylistSave::SavePlaylist(int playlistId,utfstring playlistName,mus
this->playlistName = playlistName;
for(int i(0);i<tracklist.Size();++i){
musik::core::TrackPtr track=tracklist.Track(i);
musik::core::TrackPtr track=tracklist[i];
if(track){
this->tracks.push_back(track->id);
}
@ -122,3 +122,4 @@ bool Query::PlaylistSave::RunCallbacks(Library::Base *oLibrary){
return false;
}

View File

@ -187,7 +187,7 @@ void Query::SortTracks::AddTracks(std::vector<int> &tracks){
void Query::SortTracks::AddTracks(musik::core::tracklist::IRandomAccess &tracks){
this->tracksToSort.reserve(this->tracksToSort.size()+tracks.Size());
for(int i(0);i<tracks.Size();++i){
this->tracksToSort.push_back(tracks.Track(i)->id);
this->tracksToSort.push_back(tracks[i]->id);
}
}
@ -196,3 +196,4 @@ void Query::SortTracks::SortByMetaKeys(std::list<std::string> metaKeys){
this->sortMetaKeys = metaKeys;
}

View File

@ -37,6 +37,10 @@
// Precompiled headers
#pragma once
#pragma warning (disable : 4996 4018 4482)
#include "config.h"
#include <boost/asio.hpp>
@ -64,4 +68,3 @@
#include "vld/vld.h"
#pragma warning (disable : 4996 4018 4482)

View File

@ -38,7 +38,9 @@
#include "core/tracklist/IBase.h"
#include <core/Library/Base.h>
#include <boost/shared_ptr.hpp>
#include <sigslot/sigslot.h>
namespace musik{ namespace core{
namespace tracklist {
@ -46,18 +48,34 @@ namespace musik{ namespace core{
public:
~IRandomAccess(void){};
virtual musik::core::TrackPtr operator [](int position) = 0;
virtual int Size() = 0;
virtual void SetCurrentPosition(int position) = 0;
virtual int CurrentPosition() = 0;
virtual int Size() = 0;
virtual musik::core::TrackPtr operator [](int position) = 0;
virtual musik::core::TrackPtr TrackWithMetadata(int position)=0;
virtual void SetLibrary(musik::core::LibraryPtr setLibrary) = 0;
virtual musik::core::LibraryPtr Library() = 0;
virtual void CopyTracks(musik::core::tracklist::IRandomAccess &tracklist) = 0;
virtual void AppendTracks(musik::core::tracklist::IRandomAccess &tracklist) = 0;
virtual bool CopyTracks(musik::core::tracklist::IRandomAccess &tracklist) = 0;
virtual bool AppendTracks(musik::core::tracklist::IRandomAccess &tracklist) = 0;
virtual musik::core::TrackPtr Track(int position)=0;
virtual void AddRequestedMetakey(const char* metakey) = 0;
virtual void RemoveRequestedMetakey(const char* metakey) = 0;
virtual UINT64 Duration() = 0;
virtual UINT64 Filesize() = 0;
/////////////////////////////////////////////////////////////////////////
typedef sigslot::signal3<UINT64,UINT64,UINT64> TracklistInfoEvent;
TracklistInfoEvent TracklistInfoUpdated;
typedef sigslot::signal1<bool> TracksEvent;
TracksEvent TracksUpdated;
typedef sigslot::signal1<std::vector<int>&> TrackMetaEvent;
TrackMetaEvent TrackMetaUpdated;
};
typedef boost::shared_ptr<IRandomAccess> IRandomAccessPtr;
@ -66,3 +84,4 @@ namespace musik{ namespace core{
} }

View File

@ -40,9 +40,13 @@
using namespace musik::core::tracklist;
Standard::Standard(void) : currentPosition(0),hintedRows(10){
Standard::Standard(void)
:currentPosition(0)
,hintedRows(10)
,infoDuration(0)
,infoFilesize(0)
{
this->trackQuery.OnTracksEvent.connect(this,&Standard::OnTracksMetaFromQuery);
}
@ -50,7 +54,7 @@ Standard::~Standard(void){
}
musik::core::TrackPtr Standard::CurrentTrack(){
return this->Track(this->currentPosition);
return (*this)[this->currentPosition];
}
@ -66,25 +70,17 @@ musik::core::TrackPtr Standard::PreviousTrack(){
}
musik::core::TrackPtr Standard::TrackWithMetadata(int position){
this->LoadTrack(position);
return (*this)[position];
}
musik::core::TrackPtr Standard::operator [](int position){
if(position>=0 && position<this->tracks.size())
this->LoadTrack(position);
return this->tracks[position];
if(position==-1)
this->LoadTrack(0);
return this->tracks.front();
return musik::core::TrackPtr();
}
musik::core::TrackPtr Standard::Track(int position){
if(position>=0 && position<this->tracks.size())
return this->tracks[position];
if(position==-1)
if(position==-1 && this->tracks.size()>0)
return this->tracks.front();
return musik::core::TrackPtr();
@ -121,6 +117,7 @@ int Standard::CurrentPosition(){
void Standard::ConnectToQuery(musik::core::Query::ListBase &listQuery){
listQuery.OnTrackEvent().connect(this,&Standard::OnTracksFromQuery);
listQuery.OnTrackInfoEvent().connect(this,&Standard::OnTracksInfoFromQuery);
}
@ -139,75 +136,64 @@ void Standard::OnTracksFromQuery(musik::core::TrackVector *newTracks,bool clear)
this->trackCache.clear();
this->SetCurrentPosition(-1); // undefined
this->tracks = *newTracks;
this->OnTracks(true);
this->TracksUpdated(true);
}else{
this->tracks.insert(this->tracks.end(),newTracks->begin(),newTracks->end());
this->OnTracks(false);
this->TracksUpdated(false);
}
}
void Standard::LoadTrack(int position){
int trackCount(0);
if(!this->InCache(position)){
// Not in cache
// Lets load the hinted number of tracks forward
int trackCount(0);
for(int i(position);i<position+this->hintedRows;++i){
if(!this->InCache(i)){
// Not in cache, load the track and add to Cache
musik::core::TrackPtr track = this->Track(i);
if(track){
this->trackCache.insert(CacheTrack(track,i));
++trackCount;
this->trackQuery.RequestTrack(track);
}
}
for(int i(position);i<position+this->hintedRows;++i){
if(this->QueryForTrack(i)){
++trackCount;
}
if(trackCount && this->library){
this->library->AddQuery(this->trackQuery,musik::core::Query::Prioritize);
this->trackQuery.Clear();
}
}
if(trackCount && this->library){
this->library->AddQuery(this->trackQuery,musik::core::Query::Prioritize);
this->trackQuery.Clear();
}
}
bool Standard::QueryForTrack(int position){
TrackCache::left_map::iterator trackIterator = this->trackCache.left.find(position);
if(trackIterator==this->trackCache.left.end()){
// Not in cache, lets find the track
musik::core::TrackPtr track = (*this)[position];
if(track){
// Track is also a valid track, lets add it to the cache
this->trackCache.insert( TrackCache::value_type(position,track) );
// finally, lets add it to the query
this->trackQuery.RequestTrack(track);
return true;
}
}
return false;
}
void Standard::HintNumberOfRows(int rows){
this->hintedRows = rows;
}
bool Standard::InCache(int position){
CacheIndexPosition& indexPosition = boost::multi_index::get<tagPosition>(this->trackCache);
if( indexPosition.find(position) == indexPosition.end() )
return false;
return true;
}
bool Standard::InCache(musik::core::TrackPtr track){
CacheIndexTrack& indexTrack = boost::multi_index::get<tagTrack>(this->trackCache);
if( indexTrack.find(track) == indexTrack.end() )
return false;
return true;
}
void Standard::OnTracksMetaFromQuery(musik::core::TrackVector *metaTracks){
std::vector<int> updateTrackPositions;
CacheIndexTrack& indexTrack = boost::multi_index::get<tagTrack>(this->trackCache);
for(musik::core::TrackVector::iterator track=metaTracks->begin();track!=metaTracks->end();++track){
CacheIndexTrack::iterator cacheTrackIterator = indexTrack.find(*track);
if(cacheTrackIterator!=indexTrack.end()){
updateTrackPositions.push_back(cacheTrackIterator->position);
TrackCache::right_map::iterator trackPosition = this->trackCache.right.find(*track);
if(trackPosition!=this->trackCache.right.end()){
updateTrackPositions.push_back(trackPosition->second);
}
}
this->OnTrackMeta(updateTrackPositions);
this->TrackMetaUpdated(updateTrackPositions);
}
@ -222,22 +208,26 @@ void Standard::RemoveRequestedMetakey(const char* metakey){
this->trackQuery.RequestMetakeys(this->requestedMetaKeys);
}
void Standard::CopyTracks(musik::core::tracklist::IRandomAccess &tracklist){
bool Standard::CopyTracks(musik::core::tracklist::IRandomAccess &tracklist){
if(this!=&tracklist){ // Do not copy to itself
this->trackCache.clear();
this->SetLibrary(tracklist.Library());
this->tracks.clear();
this->tracks.reserve(tracklist.Size());
for(int i(0);i<tracklist.Size();++i){
this->tracks.push_back(tracklist.Track(i)->Copy());
this->tracks.push_back(tracklist[i]->Copy());
}
this->SetCurrentPosition(tracklist.CurrentPosition());
this->OnTracks(true);
this->TracksUpdated(true);
this->infoDuration = tracklist.Duration();
this->infoFilesize = tracklist.Filesize();
this->TracklistInfoUpdated(this->tracks.size(),this->infoDuration,this->infoFilesize);
}
return true;
}
void Standard::AppendTracks(musik::core::tracklist::IRandomAccess &tracklist){
bool Standard::AppendTracks(musik::core::tracklist::IRandomAccess &tracklist){
if(!this->library){
this->SetLibrary(tracklist.Library());
}
@ -245,10 +235,23 @@ void Standard::AppendTracks(musik::core::tracklist::IRandomAccess &tracklist){
this->tracks.reserve(this->tracks.size()+tracklist.Size());
for(int i(0);i<tracklist.Size();++i){
this->tracks.push_back(tracklist.Track(i)->Copy());
this->tracks.push_back(tracklist[i]->Copy());
}
this->OnTracks(false);
this->TracksUpdated(false);
return true;
}
void Standard::OnTracksInfoFromQuery(UINT64 tracks,UINT64 duration,UINT64 filesize){
this->infoDuration = duration;
this->infoFilesize = filesize;
this->TracklistInfoUpdated(tracks,duration,filesize);
}
UINT64 Standard::Duration(){
return this->infoDuration;
}
UINT64 Standard::Filesize(){
return this->infoFilesize;
}

View File

@ -43,14 +43,12 @@
#include <core/Query/TrackMetadata.h>
#include <core/Library/Base.h>
#include <set>
#include <sigslot/sigslot.h>
#include <boost/shared_ptr.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/bimap.hpp>
#include <set>
//////////////////////////////////////////////////////////////////////////////
@ -70,80 +68,56 @@ namespace musik{ namespace core{
musik::core::TrackPtr NextTrack();
musik::core::TrackPtr PreviousTrack();
musik::core::TrackPtr operator [](int position);
int Size();
void SetCurrentPosition(int position);
int CurrentPosition();
virtual void SetCurrentPosition(int position);
virtual int CurrentPosition();
virtual int Size();
virtual musik::core::TrackPtr operator [](int position);
virtual musik::core::TrackPtr TrackWithMetadata(int position);
virtual void SetLibrary(musik::core::LibraryPtr setLibrary);
virtual musik::core::LibraryPtr Library();
virtual bool CopyTracks(musik::core::tracklist::IRandomAccess &tracklist);
virtual bool AppendTracks(musik::core::tracklist::IRandomAccess &tracklist);
virtual void AddRequestedMetakey(const char* metakey);
virtual void RemoveRequestedMetakey(const char* metakey);
virtual UINT64 Duration();
virtual UINT64 Filesize();
/////////////////////////////////////////////////////////////////////
void ConnectToQuery(musik::core::Query::ListBase &listQuery);
void SetLibrary(musik::core::LibraryPtr setLibrary);
musik::core::LibraryPtr Library();
void HintNumberOfRows(int rows);
void AddRequestedMetakey(const char* metakey);
void RemoveRequestedMetakey(const char* metakey);
private:
void CopyTracks(musik::core::tracklist::IRandomAccess &tracklist);
void AppendTracks(musik::core::tracklist::IRandomAccess &tracklist);
typedef sigslot::signal1<bool> TracksEvent;
TracksEvent OnTracks;
typedef sigslot::signal1<std::vector<int>&> TrackMetaEvent;
TrackMetaEvent OnTrackMeta;
protected:
musik::core::TrackPtr Track(int position);
void LoadTrack(int position);
bool QueryForTrack(int position);
void OnTracksFromQuery(musik::core::TrackVector *newTracks,bool clear);
void OnTracksMetaFromQuery(musik::core::TrackVector *metaTracks);
void OnTracksInfoFromQuery(UINT64 tracks,UINT64 duration,UINT64 filesize);
std::set<std::string> requestedMetaKeys;
void LoadTrack(int position);
int currentPosition;
musik::core::LibraryPtr library;
musik::core::TrackVector tracks;
musik::core::Query::TrackMetadata trackQuery;
void OnTracksFromQuery(musik::core::TrackVector *newTracks,bool clear);
void OnTracksMetaFromQuery(musik::core::TrackVector *metaTracks);
int hintedRows;
musik::core::LibraryPtr library;
musik::core::TrackVector tracks;
musik::core::Query::TrackMetadata trackQuery;
struct CacheTrack{
CacheTrack(musik::core::TrackPtr track,int position) :
track(track),
position(position)
{
};
int position;
musik::core::TrackPtr track;
};
struct tagPosition{};
struct tagTrack{};
struct tagPrio{};
typedef boost::multi_index::ordered_unique<boost::multi_index::tag<tagPosition>,BOOST_MULTI_INDEX_MEMBER(CacheTrack,int,position)> MultiIndexPosition;
typedef boost::multi_index::ordered_non_unique<boost::multi_index::tag<tagTrack>,BOOST_MULTI_INDEX_MEMBER(CacheTrack,musik::core::TrackPtr,track)> MultiIndexTrack;
typedef boost::multi_index::indexed_by<MultiIndexPosition,MultiIndexTrack> MultiIndexBy;
typedef boost::multi_index::multi_index_container<CacheTrack,MultiIndexBy> TrackCache;
/*boost::multi_index::sequenced<tagPrio>,*/
typedef boost::bimap<int,musik::core::TrackPtr> TrackCache;
TrackCache trackCache;
typedef boost::multi_index::index<TrackCache,tagTrack>::type CacheIndexTrack;
typedef boost::multi_index::index<TrackCache,tagPosition>::type CacheIndexPosition;
int infoDuration;
int infoFilesize;
bool InCache(int position);
bool InCache(musik::core::TrackPtr track);
// bool InCache(int position);
// bool InCache(musik::core::TrackPtr track);
};
}
} } // musik::core

View File

@ -112,9 +112,18 @@ void MetadataFilterController::OnViewCreated(Window* window)
this->listView.Resized.connect(
this, &MetadataFilterController::OnResized);
this->listView.Char.connect(this,&MetadataFilterController::OnChar);
}
void MetadataFilterController:: OnResized(Window* window, Size size)
void MetadataFilterController::OnResized(Window* window, Size size)
{
this->listView.SetColumnWidth(this->mainColumn, this->listView.ClientSize().width);
}
void MetadataFilterController::OnChar(Window* window,VirtualKeyCode keyCode, KeyEventFlags keyFlags){
if(keyCode){
win32cpp::RedrawLock drawLock(window);
((MetadataFilterModel*)this->model.get())->OnChar((wchar_t)keyCode);
}
}

View File

@ -55,23 +55,29 @@ class BrowseController;
class MetadataFilterController : public EventHandler
{
private: typedef ListView::ColumnRef ColumnRef;
private: typedef ListView::ModelRef ModelRef;
private:
typedef ListView::ColumnRef ColumnRef;
typedef ListView::ModelRef ModelRef;
public: /*ctor*/ MetadataFilterController(ListView& listView, const uistring& metdataKey,BrowseController *browseController);
public:
/*ctor*/ MetadataFilterController(ListView& listView, const uistring& metdataKey,BrowseController *browseController);
protected: void OnViewCreated(Window* window);
protected: void OnResized(Window* window, Size size);
protected: void OnSelectionChanged(ListView* listView);
protected:
friend class MetadataFilterModel;
BrowseController *parent;
uistring metadataKey;
std::string metadataKeyA;
protected:
void OnViewCreated(Window* window);
void OnResized(Window* window, Size size);
void OnSelectionChanged(ListView* listView);
void OnChar(Window* window,VirtualKeyCode keyCode, KeyEventFlags keyFlags);
protected: ListView& listView;
protected: ModelRef model;
protected: ColumnRef mainColumn;
uistring currentFilter;
friend class MetadataFilterModel;
BrowseController *parent;
uistring metadataKey;
std::string metadataKeyA;
ListView& listView;
ModelRef model;
ColumnRef mainColumn;
};
//////////////////////////////////////////////////////////////////////////////

View File

@ -48,6 +48,8 @@
#include <cube/MetadataFilterController.hpp>
#include <cube/BrowseController.hpp>
#include <boost/algorithm/string.hpp>
using namespace musik::cube;
//////////////////////////////////////////////////////////////////////////////
@ -67,8 +69,8 @@ uistring MetadataFilterModel::CellValueToString(int rowIndex, ListView::Colum
return (format(_T("All (%1% %2%)")) % this->metadata.size() % this->controller->metadataKey).str();
}
if(rowIndex<=this->metadata.size()){
return win32cpp::Escape(this->metadata[rowIndex-1]->value);
if(rowIndex<=this->metadataFiltered.size()){
return win32cpp::Escape(this->metadataFiltered[rowIndex-1]->value);
}else{
return uistring();
}
@ -77,10 +79,29 @@ uistring MetadataFilterModel::CellValueToString(int rowIndex, ListView::Colum
void MetadataFilterModel::OnMetadata(musik::core::MetadataValueVector* metadata,bool clear){
if(clear){
this->SetRowCount(0);
this->metadata = *metadata;
this->metadata = *metadata;
this->metadataFiltered = *metadata;
this->filter.clear();
}else{
this->metadata.insert(this->metadata.end(),metadata->begin(),metadata->end());
this->metadataFiltered.insert(this->metadataFiltered.end(),metadata->begin(),metadata->end());
}
this->SetRowCount(this->metadata.size()+1);
this->SetRowCount(this->metadataFiltered.size()+1);
this->InvalidateData(0); // Invalidate the "All" count
}
void MetadataFilterModel::OnChar(wchar_t key){
/* if(key){
this->filter += key;
// Lets filter
this->metadataFiltered.clear();
for(musik::core::MetadataValueVector::iterator meta=this->metadata.begin();meta!=this->metadata.end();++meta){
if(boost::ifind_first( (*meta)->value, this->filter) ){
this->metadataFiltered.push_back(*meta);
}
}
}
this->SetRowCount(0);
this->SetRowCount(this->metadataFiltered.size()+1);*/
}

View File

@ -55,12 +55,22 @@ class MetadataFilterController;
class MetadataFilterModel: public ListView::Model, public EventHandler
{
public: /*ctor*/ MetadataFilterModel(MetadataFilterController *controller);
public: virtual uistring CellValueToString(int rowIndex, ListView::ColumnRef column);
protected: void OnMetadata(musik::core::MetadataValueVector* metadata,bool clear);
public:
/*ctor*/ MetadataFilterModel(MetadataFilterController *controller);
virtual uistring CellValueToString(int rowIndex, ListView::ColumnRef column);
protected:
void OnMetadata(musik::core::MetadataValueVector* metadata,bool clear);
MetadataFilterController *controller;
public:
musik::core::MetadataValueVector metadata;
musik::core::MetadataValueVector metadataFiltered;
void OnChar(wchar_t key);
uistring filter;
protected: MetadataFilterController *controller;
public: musik::core::MetadataValueVector metadata;
};
//////////////////////////////////////////////////////////////////////////////

View File

@ -58,8 +58,11 @@ using namespace musik::cube;
? this->OnViewCreated(&view)
: this->view.Created.connect(this, &TracklistController::OnViewCreated);
if(connectedQuery){
connectedQuery->OnTrackInfoEvent().connect(this,&TracklistController::OnTracklistInfo);
// Connect the tracklists TracklistInfoUpdated
TracklistModel* model = (TracklistModel*)this->model.get();
if(model){
model->tracklist->TracklistInfoUpdated.connect(this,&TracklistController::OnTracklistInfo);
}
}

View File

@ -64,8 +64,8 @@ using namespace musik::cube;
this->SetRowCount(0);
this->tracklist->OnTracks.connect(this,&TracklistModel::OnTracks);
this->tracklist->OnTrackMeta.connect(this,&TracklistModel::OnTrackMeta);
this->tracklist->TracksUpdated.connect(this,&TracklistModel::OnTracks);
this->tracklist->TrackMetaUpdated.connect(this,&TracklistModel::OnTrackMeta);
this->tracklist->SetLibrary(musik::core::LibraryFactory::GetCurrentLibrary());
if(connectedQuery){
@ -81,7 +81,7 @@ uistring TracklistModel::CellValueToString(int rowIndex, ColumnRef co
typedef boost::basic_format<uichar> format;
// return (format(_T("%1% %2%")) % column->Name() % (rowIndex + 1)).str();
musik::core::TrackPtr track = (*this->tracklist)[rowIndex];
musik::core::TrackPtr track = this->tracklist->TrackWithMetadata(rowIndex);
if(!track){
return _T("");
}else{

View File

@ -38,9 +38,12 @@
#pragma once
//extern "C" void tss_cleanup_implemented(void){}
//////////////////////////////////////////////////////////////////////////////
// dependencies
//////////////////////////////////////////////////////////////////////////////
#pragma warning (disable : 4996 4018 4482)
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
@ -55,4 +58,4 @@
#include "vld/vld.h"
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

View File

@ -232,13 +232,6 @@ WindowType* Container::RemoveChild(WindowType* window)
allChildren.erase(
std::find(allChildren.begin(), allChildren.end(), window));
// set the MainWindow as the new parent, but do not add it as
// a child. we do this so the child control doesn't get into
// a bad state, but does not get automatically destroyed by the
// main window. the once a child has been removed from a Container
// it is the user's responsibility to clean it up.
Window::SetParent(window, Application::Instance().MainWindow());
this->OnChildRemoved(window);
return window;

View File

@ -0,0 +1,197 @@
//////////////////////////////////////////////////////////////////////////////
//
// License Agreement:
//
// The following are Copyright © 2007, Casey Langen
//
// Sources and Binaries of: win32cpp
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of the author nor the names of other contributors may
// be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////
#include <pch.hpp>
#include <win32cpp/Win32Config.hpp>
#include <win32cpp/ProgressBar.hpp>
//////////////////////////////////////////////////////////////////////////////
using namespace win32cpp;
//////////////////////////////////////////////////////////////////////////////
///\brief
///Constructor.
///
///\param width
///The width of the edit box
///\param height
///The height of the edit box
/*ctor*/ ProgressBar::ProgressBar(int width, int height)
: base()
, width(width)
, height(height)
//, caption(caption)
{
this->caption = _T("Progress Bar");
}
/*dtor*/ ProgressBar::~ProgressBar()
{
}
HWND ProgressBar::Create(Window* parent)
{
HINSTANCE hInstance = Application::Instance();
// create the window
DWORD style = WS_CHILD | WS_VISIBLE;
DWORD styleEx = this->styleEx;
//
HWND hwnd = CreateWindowEx(
0, // ExStyle
PROGRESS_CLASS, // Class name
this->caption.c_str(), // Window name
style, // Style
0, // X
0, // Y
this->width, // Width
this->height, // Height
parent->Handle(), // Parent
NULL, // Menu
hInstance, // Instance
NULL); // lParam
DWORD error = GetLastError();
if (hwnd)
{
::SetWindowText(hwnd, this->caption.c_str());
}
return hwnd;
}
LRESULT ProgressBar::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
WORD notifyHeader = HIWORD(wParam);
switch (notifyHeader)
{
/*case EN_CHANGE:
this->OnChanged();
return 0; // 0 = processed*/
}
}
break;
}
return this->DefaultWindowProc(message, wParam, lParam);
}
///\brief
///Sets the progress bar to have a smooth bar
void ProgressBar::SetMarqueeStyle()
{
SetWindowLongPtr(this->Handle(), GWL_STYLE, GetWindowLongPtr(this->Handle(), GWL_STYLE) | PBS_MARQUEE);
SetWindowPos(this->Handle(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
return;
}
///\brief
///Sets the progress bar to have a smooth bar
void ProgressBar::SetSmoothStyle()
{
SetWindowLongPtr(this->Handle(), GWL_STYLE, GetWindowLongPtr(this->Handle(), GWL_STYLE) | PBS_SMOOTH);
SetWindowPos(this->Handle(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
return;
}
///\brief
///Sets the progress bar to have a smooth bar
void ProgressBar::SetVerticalStyle()
{
SetWindowLongPtr(this->Handle(), GWL_STYLE, GetWindowLongPtr(this->Handle(), GWL_STYLE) | PBS_VERTICAL);
SetWindowPos(this->Handle(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
return;
}
///\brief
///Sets the progress bar to have a marquee style (Windows XP or above)
///\param set
///Boolean to say whether to marquee or not
///\param delay
///Time in milliseconds between animation updates
void ProgressBar::StartMarquee(bool set, unsigned int delay)
{
this->SendMessage(PBM_SETMARQUEE, (WPARAM)set, (LPARAM)delay);
return;
}
///\brief
///Sets the min and max values of the progress bar
///\param min
///The minimum value (unsigned)
///\param max
///The maximum value (unsigned)
DWORD ProgressBar::SetRange(unsigned int min, unsigned int max)
{
DWORD prevrange = this->SendMessage(PBM_SETRANGE, 0, MAKELPARAM(min,max));
return prevrange;
}
///\brief
///Sets the current position of the progress bar
///\param pos
///The new position of the progress bar
void ProgressBar::SetPos(int pos)
{
this->SendMessage(PBM_SETPOS, pos, 0 /*must be 0. Not used*/);
return;
}
///\brief
///Sets the current position of the progress bar
///\param pos
///The new step increment
void ProgressBar::SetStepIncrement(int inc)
{
this->SendMessage(PBM_SETSTEP, inc, 0 /*must be 0. Not used*/);
return;
}
///\brief
///Steps the progress bar forward once. Default step is 10
void ProgressBar::Step()
{
this->SendMessage(PBM_STEPIT, 0, 0);
return;
}

View File

@ -0,0 +1,82 @@
//////////////////////////////////////////////////////////////////////////////
//
// License Agreement:
//
// The following are Copyright © 2007, Casey Langen
//
// Sources and Binaries of: win32cpp
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of the author nor the names of other contributors may
// be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once
//////////////////////////////////////////////////////////////////////////////
#include <win32cpp/Window.hpp>
namespace win32cpp {
//////////////////////////////////////////////////////////////////////////////
class ProgressBar; // forward decl
///\brief
///A progress bar.
class ProgressBar: public Window
{
private: // types
typedef Window base;
public: // constructors, methods
/*ctor*/ ProgressBar(int width, int height);
/*dtor*/ ~ProgressBar();
void SetMarqueeStyle();
void SetSmoothStyle();
void SetVerticalStyle();
void StartMarquee(bool set, unsigned int delay);
DWORD SetRange(unsigned int min, unsigned int max);
void SetPos(int pos);
void SetStepIncrement(int inc);
void Step();
protected: // methods
virtual HWND Create(Window* parent);
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
protected: // instance data
uistring caption;
int width;
int height;
DWORD styleEx;
};
} //win32cpp

View File

@ -75,6 +75,7 @@ HCURSOR Splitter::sArrowCursor = ::LoadCursor(0, MAKEINTRESOURCE(IDC_ARROW));
, anchor(direction == SplitColumn ? AnchorLeft : AnchorTop)
, minAnchorSize(-1)
, maxAnchorSize(-1)
, sizeFromMouse(-1)
{
}
@ -193,37 +194,63 @@ const Window* Splitter::Child2()
return this->child2;
}
void Splitter::Layout(int child1Size)
void Splitter::LayoutFromMouse()
{
Rect clientRect = this->ClientRect();
int clientSize = (this->direction == SplitRow
? clientRect.size.height
: clientRect.size.width);
bool child1IsAnchor = (this->anchor == AnchorLeft || this->anchor == AnchorTop);
int control1Size = this->sizeFromMouse;
int control2Size = clientSize - control1Size - this->gripperSize;
control2Size = max(control2Size, 0);
this->anchorSize = (child1IsAnchor ? control1Size : control2Size);
// done! set this back for the next call to Layout()
this->sizeFromMouse = -1;
this->Layout();
}
void Splitter::Layout()
{
if (this->sizeFromMouse != -1)
{
this->LayoutFromMouse();
return;
}
Rect clientRect = this->ClientRect();
//
int clientSize = (this->direction == SplitRow
? clientRect.size.height
: clientRect.size.width);
int anchorSize = (child1Size == -1 ? this->anchorSize : child1Size);
int splitterPos = this->anchorSize;
//
if (anchorSize <= -1)
if (splitterPos <= -1)
{
anchorSize = (clientSize / 2);
splitterPos = (clientSize / 2);
}
else
{
// don't allow the split to go beyond the window boundries
anchorSize = min(anchorSize, clientSize - this->gripperSize);
splitterPos = min(splitterPos, clientSize - this->gripperSize);
}
// size the windows in their split direction
bool child1IsAnchor = (this->anchor == AnchorLeft || this->anchor == AnchorTop);
child1IsAnchor |= (child1Size != -1);
if (this->minAnchorSize >= 0) anchorSize = max(this->minAnchorSize, anchorSize);
if (this->maxAnchorSize >= 0) anchorSize = min(this->maxAnchorSize, anchorSize);
if (this->minAnchorSize >= 0) splitterPos = max(this->minAnchorSize, splitterPos);
if (this->maxAnchorSize >= 0) splitterPos = min(this->maxAnchorSize, splitterPos);
int nonAnchorSize = clientSize - (anchorSize + this->gripperSize);
int nonAnchorSize = clientSize - (splitterPos + this->gripperSize);
//
int control1Size = child1IsAnchor ? anchorSize : nonAnchorSize;
int control2Size = child1IsAnchor ? nonAnchorSize : anchorSize;
int control1Size = child1IsAnchor ? splitterPos : nonAnchorSize;
int control2Size = child1IsAnchor ? nonAnchorSize : splitterPos;
if (this->direction == SplitColumn)
{
@ -238,9 +265,18 @@ void Splitter::Layout(int child1Size)
child2Frame->MoveTo(clientRect.location.x, control1Size + this->gripperSize);
}
if (child1Size != -1)
// remember our splitter rect
if (this->direction == SplitColumn)
{
this->anchorSize = anchorSize;
this->splitRect = Rect(
Point(control1Size, 0),
Size(this->gripperSize, clientRect.size.height));
}
else
{
this->splitRect = Rect(
Point(0, control1Size),
Size(clientRect.size.width, this->gripperSize));
}
}
@ -321,9 +357,10 @@ void Splitter::OnMouseMoved(MouseEventFlags flags, const Point& location)
// do this because we may be redrawing complex child controls (including other
// splitters) unnecessarily.
RedrawLock redrawLock(Application::Instance().MainWindow());
this->Layout(position);
this->sizeFromMouse = position;
this->Layout();
}
else if ( ! ::PointInRect(this->CursorPosition(), this->SplitterRect()))
else if ( ! ::PointInRect(this->CursorPosition(), this->splitRect))
{
this->EndMouseCapture();
}
@ -343,7 +380,10 @@ void Splitter::OnMouseButtonDown(MouseEventFlags flags, const Point& location
return;
}
this->isDragging = true;
if (::PointInRect(this->CursorPosition(), this->splitRect))
{
this->isDragging = true;
}
}
void Splitter::OnMouseExit()
@ -356,38 +396,6 @@ void Splitter::OnMouseEnter()
this->BeginMouseCapture();
}
Rect Splitter::SplitterRect()
{
Rect splitterRect;
bool child1IsAnchor = (this->anchor == AnchorLeft || this->anchor == AnchorTop);
bool isHoriz = (this->direction == SplitColumn);
int clientSize = isHoriz
? this->WindowSize().height
: this->WindowSize().width;
splitterRect.size = Size(
isHoriz ? this->gripperSize : clientSize,
isHoriz ? clientSize : this->gripperSize);
int nonAnchorSize = clientSize - (this->anchorSize + this->gripperSize);
int location = child1IsAnchor ? this->anchorSize : nonAnchorSize;
if (location == -1)
{
location = (isHoriz
? this->WindowSize().width
: this->WindowSize().height) / 2;
}
splitterRect.location = Point(
isHoriz ? location : 0,
isHoriz ? 0 : location);
return splitterRect;
}
void Splitter::OnMouseButtonUp(MouseEventFlags flags, const Point& location)
{
this->isDragging = false;

View File

@ -41,6 +41,7 @@
//////////////////////////////////////////////////////////////////////////////
#include <win32cpp/Container.hpp>
#include <win32cpp/ILayout.hpp>
namespace win32cpp {
@ -85,7 +86,7 @@ const int DisableConstraint = -1;
///children stationary or "anchored," while allowing the other to be resized
///to fill the new space. The anchor can be set via Splitter::SetAnchor by
///specifying a win32cpp::AnchorDirection.
class Splitter: public Panel
class Splitter: public Panel, public ILayout
{
private: // types
typedef Panel base;
@ -109,7 +110,6 @@ public: // methods
protected: // methods
void SetSizeCursor();
Rect SplitterRect();
int AnchorSizeFromMouse(int splitPosition, const Size& newSize);
void BeginMouseCapture();
void EndMouseCapture();
@ -117,7 +117,8 @@ protected: // methods
// overrides
virtual bool AddChildWindow(Window* window);
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
virtual void Layout(int child1Size = -1);
virtual void Layout();
virtual void LayoutFromMouse();
virtual void OnResized(const Size& newSize);
virtual void OnMouseMoved(MouseEventFlags flags, const Point& location);
virtual void OnMouseButtonDown(MouseEventFlags flags, const Point& location);
@ -131,9 +132,11 @@ private: // instance data
Frame *child1Frame, *child2Frame;
int gripperSize, anchorSize;
int minAnchorSize, maxAnchorSize;
int sizeFromMouse;
bool isDragging, isSizable;
SplitDirection direction;
AnchorDirection anchor;
Rect splitRect;
private: // class data
static HCURSOR sHSizeCursor, sVSizeCursor, sArrowCursor;
@ -141,4 +144,4 @@ private: // class data
//////////////////////////////////////////////////////////////////////////////
} // win32cpp
} // win32cpp

View File

@ -674,7 +674,7 @@ bool Window::MoveTo(const Point& location)
location.y,
windowRect.right - windowRect.left,
windowRect.bottom - windowRect.top,
TRUE);
this->Visible());
if (result)
{
@ -732,7 +732,7 @@ bool Window::Resize(const Size& size)
topLeft.y,
saneSize.width,
saneSize.height,
TRUE);
this->Visible());
if (result)
{
@ -791,10 +791,19 @@ bool Window::SetCaption(const uistring& caption)
return true;
}
if ((this->windowHandle) && (::SetWindowText(this->windowHandle, caption.c_str())))
if (this->windowHandle)
{
this->OnCaptionChanged();
return true;
BOOL success = (BOOL) ::SendMessage(
this->windowHandle,
WM_SETTEXT,
0,
(LPARAM) caption.c_str());
if (success)
{
this->OnCaptionChanged();
return true;
}
}
return false;
@ -1087,6 +1096,7 @@ void Window::SetVisible(bool visible)
if (this->Handle())
{
::ShowWindow(this->Handle(), visible ? SW_SHOW : SW_HIDE);
this->OnVisibilityChangedBase(visible);
}
}
@ -1395,6 +1405,13 @@ bool Window::OnCharBase(VirtualKeyCode keyCode, KeyEventFlags flags)
return result;
}
void Window::OnVisibilityChangedBase(bool visible)
{
this->OnVisibilityChanged(visible);
EMIT_SIGNAL_IF_NOT_SUPPRESSED(this->VisibilityChanged, this, visible);
}
void Window::OnThemeChanged()
{
// If we're the first window to notice the theme change then update

View File

@ -83,6 +83,7 @@ enum MouseEventFlags
/*! */ typedef sigslot::signal2<Window* /*old*/, Window* /*new*/> ParentChangedEvent;
/*! */ typedef sigslot::signal1<unsigned int> TimerEvent;
/*! */ typedef sigslot::signal3<Window*, VirtualKeyCode, KeyEventFlags> KeyEvent;
/*! */ typedef sigslot::signal2<Window*, bool> VisibilityChangedEvent;
///\brief
///Window is the abstract base class for all controls.
@ -173,6 +174,8 @@ public: // events
///\brief Emitted when a control has requested to focus the previous control. This
///generally shouldn't be handled explicitly unless absolutely necessary.
FocusEvent RequestFocusPrev;
///\brief Emitted when a Window's visibility has changed
VisibilityChangedEvent VisibilityChanged;
public: // ctor, dtor
/*ctor*/ Window();
@ -250,6 +253,7 @@ protected: // methods
bool OnKeyDownBase(VirtualKeyCode keyCode, KeyEventFlags flags);
bool OnKeyUpBase(VirtualKeyCode keyCode, KeyEventFlags flags);
bool OnCharBase(VirtualKeyCode keyCode, KeyEventFlags flags);
void OnVisibilityChangedBase(bool visible);
// win32 event wrappers (virtual methods, for derived class use)
virtual void OnDestroyed() { }
@ -277,6 +281,7 @@ protected: // methods
virtual void OnRequestFocusPrev();
virtual void OnRequestFocusNext();
virtual HBRUSH OnControlColor(HDC hdc);
virtual void OnVisibilityChanged(bool visible) { }
// window proc related
virtual LRESULT PreWindowProcBase(UINT message, WPARAM wParam, LPARAM lParam, bool& discardMessage);

View File

@ -332,6 +332,14 @@
RelativePath=".\ListView.hpp"
>
</File>
<File
RelativePath=".\ProgressBar.cpp"
>
</File>
<File
RelativePath=".\ProgressBar.hpp"
>
</File>
<File
RelativePath=".\Window.cpp"
>