diff --git a/src/core/Query/PlaylistSave.cpp b/src/core/Query/PlaylistSave.cpp index 52b9b4cf4..2a5eb0d07 100644 --- a/src/core/Query/PlaylistSave.cpp +++ b/src/core/Query/PlaylistSave.cpp @@ -60,7 +60,7 @@ void Query::PlaylistSave::SavePlaylist(int playlistId,utfstring playlistName,mus this->playlistName = playlistName; for(int i(0);itracks.push_back(track->id); } @@ -122,3 +122,4 @@ bool Query::PlaylistSave::RunCallbacks(Library::Base *oLibrary){ return false; } + diff --git a/src/core/Query/SortTracks.cpp b/src/core/Query/SortTracks.cpp index 67fcf4703..1f760f460 100644 --- a/src/core/Query/SortTracks.cpp +++ b/src/core/Query/SortTracks.cpp @@ -187,7 +187,7 @@ void Query::SortTracks::AddTracks(std::vector &tracks){ void Query::SortTracks::AddTracks(musik::core::tracklist::IRandomAccess &tracks){ this->tracksToSort.reserve(this->tracksToSort.size()+tracks.Size()); for(int i(0);itracksToSort.push_back(tracks.Track(i)->id); + this->tracksToSort.push_back(tracks[i]->id); } } @@ -196,3 +196,4 @@ void Query::SortTracks::SortByMetaKeys(std::list metaKeys){ this->sortMetaKeys = metaKeys; } + diff --git a/src/core/pch.hpp b/src/core/pch.hpp index d05db1804..1788c89bd 100644 --- a/src/core/pch.hpp +++ b/src/core/pch.hpp @@ -37,6 +37,10 @@ // Precompiled headers #pragma once +#pragma warning (disable : 4996 4018 4482) + + + #include "config.h" #include @@ -64,4 +68,3 @@ #include "vld/vld.h" -#pragma warning (disable : 4996 4018 4482) diff --git a/src/core/tracklist/IRandomAccess.h b/src/core/tracklist/IRandomAccess.h index c1b643c25..bb34ab846 100644 --- a/src/core/tracklist/IRandomAccess.h +++ b/src/core/tracklist/IRandomAccess.h @@ -38,7 +38,9 @@ #include "core/tracklist/IBase.h" #include + #include +#include 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 TracklistInfoEvent; + TracklistInfoEvent TracklistInfoUpdated; + + typedef sigslot::signal1 TracksEvent; + TracksEvent TracksUpdated; + + typedef sigslot::signal1&> TrackMetaEvent; + TrackMetaEvent TrackMetaUpdated; }; typedef boost::shared_ptr IRandomAccessPtr; @@ -66,3 +84,4 @@ namespace musik{ namespace core{ } } + diff --git a/src/core/tracklist/Standard.cpp b/src/core/tracklist/Standard.cpp index b511b61f5..a1915ccd6 100644 --- a/src/core/tracklist/Standard.cpp +++ b/src/core/tracklist/Standard.cpp @@ -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 && positiontracks.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 && positiontracks.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);ihintedRows;++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);ihintedRows;++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(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(this->trackCache); - - if( indexTrack.find(track) == indexTrack.end() ) - return false; - - return true; -} void Standard::OnTracksMetaFromQuery(musik::core::TrackVector *metaTracks){ std::vector updateTrackPositions; - CacheIndexTrack& indexTrack = boost::multi_index::get(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);itracks.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);itracks.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; +} diff --git a/src/core/tracklist/Standard.h b/src/core/tracklist/Standard.h index 872ea9560..2a705e1c9 100644 --- a/src/core/tracklist/Standard.h +++ b/src/core/tracklist/Standard.h @@ -43,14 +43,12 @@ #include #include +#include #include #include -#include -#include -#include -#include +#include + -#include ////////////////////////////////////////////////////////////////////////////// @@ -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 TracksEvent; - TracksEvent OnTracks; - typedef sigslot::signal1&> 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 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_MEMBER(CacheTrack,int,position)> MultiIndexPosition; - typedef boost::multi_index::ordered_non_unique,BOOST_MULTI_INDEX_MEMBER(CacheTrack,musik::core::TrackPtr,track)> MultiIndexTrack; - typedef boost::multi_index::indexed_by MultiIndexBy; - - typedef boost::multi_index::multi_index_container TrackCache; - - /*boost::multi_index::sequenced,*/ - + typedef boost::bimap TrackCache; TrackCache trackCache; - typedef boost::multi_index::index::type CacheIndexTrack; - typedef boost::multi_index::index::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 diff --git a/src/cube/MetadataFilterController.cpp b/src/cube/MetadataFilterController.cpp index c6ee23820..b13bfe98e 100644 --- a/src/cube/MetadataFilterController.cpp +++ b/src/cube/MetadataFilterController.cpp @@ -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); + } +} diff --git a/src/cube/MetadataFilterController.hpp b/src/cube/MetadataFilterController.hpp index 0a6ecbe63..b89f90828 100644 --- a/src/cube/MetadataFilterController.hpp +++ b/src/cube/MetadataFilterController.hpp @@ -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; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/src/cube/MetadataFilterModel.cpp b/src/cube/MetadataFilterModel.cpp index 368b8208c..660cda10b 100644 --- a/src/cube/MetadataFilterModel.cpp +++ b/src/cube/MetadataFilterModel.cpp @@ -48,6 +48,8 @@ #include #include +#include + 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);*/ +} diff --git a/src/cube/MetadataFilterModel.hpp b/src/cube/MetadataFilterModel.hpp index 988151926..56ed93e08 100644 --- a/src/cube/MetadataFilterModel.hpp +++ b/src/cube/MetadataFilterModel.hpp @@ -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; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/src/cube/TracklistController.cpp b/src/cube/TracklistController.cpp index 5f2fefa6e..0d4237c94 100644 --- a/src/cube/TracklistController.cpp +++ b/src/cube/TracklistController.cpp @@ -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); } } diff --git a/src/cube/TracklistModel.cpp b/src/cube/TracklistModel.cpp index f20666f0f..cdfba7fe3 100644 --- a/src/cube/TracklistModel.cpp +++ b/src/cube/TracklistModel.cpp @@ -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 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{ diff --git a/src/cube/pch.hpp b/src/cube/pch.hpp index e9e235845..2bd052120 100644 --- a/src/cube/pch.hpp +++ b/src/cube/pch.hpp @@ -38,9 +38,12 @@ #pragma once +//extern "C" void tss_cleanup_implemented(void){} + ////////////////////////////////////////////////////////////////////////////// // dependencies ////////////////////////////////////////////////////////////////////////////// +#pragma warning (disable : 4996 4018 4482) #include #include @@ -55,4 +58,4 @@ #include "vld/vld.h" -////////////////////////////////////////////////////////////////////////////// \ No newline at end of file +////////////////////////////////////////////////////////////////////////////// diff --git a/src/win32cpp/Container.hpp b/src/win32cpp/Container.hpp index d35a51f88..97b557e3a 100644 --- a/src/win32cpp/Container.hpp +++ b/src/win32cpp/Container.hpp @@ -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; diff --git a/src/win32cpp/ProgressBar.cpp b/src/win32cpp/ProgressBar.cpp new file mode 100644 index 000000000..13d4d8ed9 --- /dev/null +++ b/src/win32cpp/ProgressBar.cpp @@ -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 +#include +#include + +////////////////////////////////////////////////////////////////////////////// + +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; +} \ No newline at end of file diff --git a/src/win32cpp/ProgressBar.hpp b/src/win32cpp/ProgressBar.hpp new file mode 100644 index 000000000..e6cfc5e02 --- /dev/null +++ b/src/win32cpp/ProgressBar.hpp @@ -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 + +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 \ No newline at end of file diff --git a/src/win32cpp/Splitter.cpp b/src/win32cpp/Splitter.cpp index 70cc4a58d..a8ff71d18 100644 --- a/src/win32cpp/Splitter.cpp +++ b/src/win32cpp/Splitter.cpp @@ -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; diff --git a/src/win32cpp/Splitter.hpp b/src/win32cpp/Splitter.hpp index b218effb3..4df9e054d 100644 --- a/src/win32cpp/Splitter.hpp +++ b/src/win32cpp/Splitter.hpp @@ -41,6 +41,7 @@ ////////////////////////////////////////////////////////////////////////////// #include +#include 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 \ No newline at end of file +} // win32cpp diff --git a/src/win32cpp/Window.cpp b/src/win32cpp/Window.cpp index 6d04e4217..31939c310 100644 --- a/src/win32cpp/Window.cpp +++ b/src/win32cpp/Window.cpp @@ -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 diff --git a/src/win32cpp/Window.hpp b/src/win32cpp/Window.hpp index 37b3061a8..52d60a715 100644 --- a/src/win32cpp/Window.hpp +++ b/src/win32cpp/Window.hpp @@ -83,6 +83,7 @@ enum MouseEventFlags /*! */ typedef sigslot::signal2 ParentChangedEvent; /*! */ typedef sigslot::signal1 TimerEvent; /*! */ typedef sigslot::signal3 KeyEvent; +/*! */ typedef sigslot::signal2 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); diff --git a/src/win32cpp/win32cpp.vcproj b/src/win32cpp/win32cpp.vcproj index c7f184849..01b46ebb4 100644 --- a/src/win32cpp/win32cpp.vcproj +++ b/src/win32cpp/win32cpp.vcproj @@ -332,6 +332,14 @@ RelativePath=".\ListView.hpp" > + + + +