Commit d63b9e39 authored by Gildas Bazin's avatar Gildas Bazin

* modules/gui/wxwidgets: start of a playlist_manager widget.

   This is based on code from the current playlist dialog but this dialog should eventually make use of the widget as well (when enough features have been implemented).
parent 2c366250
......@@ -9,6 +9,7 @@ SOURCES_wxwidgets = \
timer.cpp \
video.cpp \
input_manager.cpp \
playlist_manager.cpp \
dialogs.cpp \
dialogs/open.cpp \
dialogs/streamout.cpp \
......@@ -41,6 +42,7 @@ EXTRA_DIST += \
timer.hpp \
video.hpp \
input_manager.hpp \
playlist_manager.hpp \
dialogs/fileinfo.hpp \
dialogs/preferences.hpp \
dialogs/wizard.hpp \
......@@ -67,6 +69,7 @@ EXTRA_DIST += \
bitmaps/next.xpm \
bitmaps/pause.xpm \
bitmaps/playlist.xpm \
bitmaps/playlist_small.xpm \
bitmaps/play.xpm \
bitmaps/prev.xpm \
bitmaps/repeat.xpm \
......
/* XPM */
static char * playlist_small_xpm[] = {
"16 16 2 1",
" c None",
". c #000000",
" ",
" ",
" ",
" ",
" ",
" ",
" .. ....... ",
" ",
" .. ....... ",
" ",
" .. ....... ",
" ",
" .. ....... ",
" ",
" ",
" "};
......@@ -25,6 +25,7 @@
* Preamble
*****************************************************************************/
#include "interface.hpp"
#include "playlist_manager.hpp"
#include "extrapanel.hpp"
#include "timer.hpp"
#include "video.hpp"
......@@ -45,6 +46,7 @@
#include "bitmaps/slow.xpm"
#include "bitmaps/fast.xpm"
#include "bitmaps/playlist.xpm"
#include "bitmaps/playlist_small.xpm"
#include "bitmaps/speaker.xpm"
#include "bitmaps/speaker_mute.xpm"
......@@ -134,6 +136,7 @@ enum
Wizard_Event,
Playlist_Event,
PlaylistSmall_Event,
Logs_Event,
FileInfo_Event,
......@@ -167,6 +170,7 @@ BEGIN_EVENT_TABLE(Interface, wxFrame)
EVT_MENU(VLM_Event, Interface::OnShowDialog)
EVT_MENU(Playlist_Event, Interface::OnShowDialog)
EVT_MENU(PlaylistSmall_Event, Interface::OnSmallPlaylist)
EVT_MENU(Logs_Event, Interface::OnShowDialog)
EVT_MENU(FileInfo_Event, Interface::OnShowDialog)
EVT_MENU(Prefs_Event, Interface::OnShowDialog)
......@@ -215,6 +219,8 @@ Interface::Interface( intf_thread_t *_p_intf, long style ):
p_intf = _p_intf;
b_extra = VLC_FALSE;
extra_frame = 0;
b_playlist_manager = VLC_FALSE;
playlist_manager = 0;
/* Give our interface a nice little icon */
SetIcon( wxIcon( vlc_xpm ) );
......@@ -348,6 +354,8 @@ void Interface::Update()
{
/* Misc updates */
((VLCVolCtrl *)volctrl)->UpdateVolume();
if( playlist_manager ) playlist_manager->Update();
}
void Interface::OnControlEvent( wxCommandEvent& event )
......@@ -490,6 +498,7 @@ void Interface::CreateOurToolBar()
#define HELP_PLAY N_("Play")
#define HELP_PAUSE N_("Pause")
#define HELP_PLO N_("Playlist")
#define HELP_SPLO N_("Small playlist")
#define HELP_PLP N_("Previous playlist item")
#define HELP_PLN N_("Next playlist item")
#define HELP_SLOW N_("Play slower")
......@@ -533,15 +542,15 @@ void Interface::CreateOurToolBar()
toolbar->AddSeparator();
toolbar->AddTool( Playlist_Event, wxT(""), wxBitmap( playlist_xpm ),
wxU(_(HELP_PLO)) );
toolbar->AddTool( PlaylistSmall_Event, wxT(""),
wxBitmap( playlist_small_xpm ), wxU(_(HELP_SPLO)) );
}
#if !( (wxMAJOR_VERSION <= 2) && (wxMINOR_VERSION <= 6) && (wxRELEASE_NUMBER < 2) )
wxControl *p_dummy_ctrl =
new wxControl( toolbar, -1, wxDefaultPosition,
wxSize(35, 16 ), wxBORDER_NONE );
wxSize(16, 16 ), wxBORDER_NONE );
toolbar->AddControl( p_dummy_ctrl );
#endif
volctrl = new VLCVolCtrl( p_intf, toolbar );
toolbar->AddControl( volctrl );
......@@ -658,6 +667,13 @@ void Interface::SetIntfMinSize()
ms.SetWidth( ext_min_size.GetWidth() );
}
if( playlist_manager && playlist_manager->IsShown() )
{
ms.SetHeight( ms.GetHeight() + playlist_min_size.GetHeight() );
if( playlist_min_size.GetWidth() > ms.GetWidth() )
ms.SetWidth( playlist_min_size.GetWidth() );
}
SetSizeHints( ms );
}
......@@ -837,6 +853,26 @@ void Interface::OnExtended( wxCommandEvent& WXUNUSED(event) )
main_sizer->Fit( this );
}
void Interface::OnSmallPlaylist( wxCommandEvent& WXUNUSED(event) )
{
UpdateVideoWindow( p_intf, video_window );
if( !playlist_manager )
{
/* Create the extra panel */
playlist_manager = new PlaylistManager( p_intf, main_panel );
panel_sizer->Add( playlist_manager, 0, wxEXPAND , 0 );
playlist_min_size = playlist_manager->GetBestSize();
}
b_playlist_manager = !b_playlist_manager;
panel_sizer->Show( playlist_manager, b_playlist_manager );
SetIntfMinSize();
main_sizer->Layout();
main_sizer->Fit( this );
}
void Interface::OnPlayStream( wxCommandEvent& WXUNUSED(event) )
{
PlayStream();
......
......@@ -100,9 +100,6 @@ namespace wxvlc
InputManager *input_manager;
vlc_bool_t b_extra;
wxPanel *extra_frame;
wxControl *volctrl;
#ifdef wxHAS_TASK_BAR_ICON
......@@ -132,6 +129,7 @@ namespace wxvlc
void OnOpenSat( wxCommandEvent& event );
void OnExtended( wxCommandEvent& event );
void OnSmallPlaylist( wxCommandEvent& event );
void OnBookmarks( wxCommandEvent& event );
void OnShowDialog( wxCommandEvent& event );
......@@ -164,8 +162,17 @@ namespace wxvlc
wxMenu *p_video_menu;
wxMenu *p_navig_menu;
/* Extended panel */
vlc_bool_t b_extra;
wxPanel *extra_frame;
/* Playlist panel */
vlc_bool_t b_playlist_manager;
wxPanel *playlist_manager;
/* Utility dimensions */
wxSize main_min_size;
wxSize playlist_min_size;
wxSize ext_min_size;
};
......
/*****************************************************************************
* playlist_manager.cpp : wxWindows plugin for vlc
*****************************************************************************
* Copyright (C) 2000-2005 the VideoLAN team
* $Id$
*
* Authors: Olivier Teulire <ipkiss@via.ecp.fr>
* Clment Stenac <zorglub@videolan.org>
* Gildas Bazin <gbazin@videolan.org>
*
* This program is free software; you can redistribute it and/OR MODIFy
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include "playlist_manager.hpp"
#include "interface.hpp"
#include "bitmaps/type_unknown.xpm"
#include "bitmaps/type_afile.xpm"
#include "bitmaps/type_vfile.xpm"
#include "bitmaps/type_net.xpm"
#include "bitmaps/type_card.xpm"
#include "bitmaps/type_disc.xpm"
#include "bitmaps/type_cdda.xpm"
#include "bitmaps/type_directory.xpm"
#include "bitmaps/type_playlist.xpm"
#include "bitmaps/type_node.xpm"
#include <wx/dynarray.h>
#include <wx/imaglist.h>
namespace wxvlc {
/* Callback prototype */
static int PlaylistChanged( vlc_object_t *, const char *,
vlc_value_t, vlc_value_t, void * );
static int PlaylistNext( vlc_object_t *, const char *,
vlc_value_t, vlc_value_t, void * );
static int ItemChanged( vlc_object_t *, const char *,
vlc_value_t, vlc_value_t, void * );
static int ItemAppended( vlc_object_t *p_this, const char *psz_variable,
vlc_value_t oval, vlc_value_t nval, void *param );
static int ItemDeleted( vlc_object_t *p_this, const char *psz_variable,
vlc_value_t oval, vlc_value_t nval, void *param );
/*****************************************************************************
* Event Table.
*****************************************************************************/
/* IDs for the controls and the menu commands */
enum
{
TreeCtrl_Event,
UpdateItem_Event,
AppendItem_Event,
RemoveItem_Event,
};
DEFINE_LOCAL_EVENT_TYPE( wxEVT_PLAYLIST );
BEGIN_EVENT_TABLE(PlaylistManager, wxPanel)
/* Tree control events */
EVT_TREE_ITEM_ACTIVATED( TreeCtrl_Event, PlaylistManager::OnActivateItem )
/* Custom events */
EVT_COMMAND(-1, wxEVT_PLAYLIST, PlaylistManager::OnPlaylistEvent)
END_EVENT_TABLE()
/*****************************************************************************
* PlaylistItem class
****************************************************************************/
class PlaylistItem : public wxTreeItemData
{
public:
PlaylistItem( playlist_item_t *p_item ) : i_id(p_item->input.i_id) {}
int i_id;
};
/*****************************************************************************
* Constructor.
*****************************************************************************/
PlaylistManager::PlaylistManager( intf_thread_t *_p_intf, wxWindow *p_parent ):
wxPanel( p_parent, -1, wxDefaultPosition, wxSize(500,300) )
{
/* Initializations */
p_intf = _p_intf;
b_need_update = VLC_FALSE;
i_items_to_append = 0;
i_cached_item_id = -1;
i_update_counter = 0;
p_playlist = (playlist_t *)
vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
if( p_playlist == NULL ) return;
var_Create( p_intf, "random", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
var_Create( p_intf, "loop", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
var_Create( p_intf, "repeat", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );;
/* Create the tree */
treectrl = new wxTreeCtrl( this, TreeCtrl_Event,
wxDefaultPosition, wxDefaultSize,
wxTR_HIDE_ROOT | wxTR_LINES_AT_ROOT|
wxTR_NO_LINES |
wxTR_HAS_BUTTONS | wxTR_TWIST_BUTTONS |
wxTR_MULTIPLE | wxTR_EXTENDED );
/* Add everything to the panel */
sizer = new wxBoxSizer( wxHORIZONTAL );
SetSizer( sizer );
sizer->Add( treectrl, 1, wxEXPAND );
/* Create image list */
wxImageList *p_images = new wxImageList( 16 , 16, TRUE );
/* FIXME: absolutely needs to be in the right order FIXME */
p_images->Add( wxIcon( type_unknown_xpm ) );
p_images->Add( wxIcon( type_afile_xpm ) );
p_images->Add( wxIcon( type_vfile_xpm ) );
p_images->Add( wxIcon( type_directory_xpm ) );
p_images->Add( wxIcon( type_disc_xpm ) );
p_images->Add( wxIcon( type_cdda_xpm ) );
p_images->Add( wxIcon( type_card_xpm ) );
p_images->Add( wxIcon( type_net_xpm ) );
p_images->Add( wxIcon( type_playlist_xpm ) );
p_images->Add( wxIcon( type_node_xpm ) );
treectrl->AssignImageList( p_images );
/* Reduce font size */
wxFont font = treectrl->GetFont(); font.SetPointSize(9);
treectrl->SetFont( font );
#if wxUSE_DRAG_AND_DROP
/* Associate drop targets with the playlist */
SetDropTarget( new DragAndDrop( p_intf, VLC_TRUE ) );
#endif
/* Update the playlist */
Rebuild( VLC_TRUE );
/*
* We want to be notified of playlist changes
*/
/* Some global changes happened -> Rebuild all */
var_AddCallback( p_playlist, "intf-change", PlaylistChanged, this );
/* We went to the next item */
var_AddCallback( p_playlist, "playlist-current", PlaylistNext, this );
/* One item has been updated */
var_AddCallback( p_playlist, "item-change", ItemChanged, this );
var_AddCallback( p_playlist, "item-append", ItemAppended, this );
var_AddCallback( p_playlist, "item-deleted", ItemDeleted, this );
}
PlaylistManager::~PlaylistManager()
{
if( p_playlist == NULL ) return;
var_DelCallback( p_playlist, "item-change", ItemChanged, this );
var_DelCallback( p_playlist, "playlist-current", PlaylistNext, this );
var_DelCallback( p_playlist, "intf-change", PlaylistChanged, this );
var_DelCallback( p_playlist, "item-append", ItemAppended, this );
var_DelCallback( p_playlist, "item-deleted", ItemDeleted, this );
vlc_object_release( p_playlist );
}
/*****************************************************************************
* PlaylistChanged: callback triggered by the intf-change playlist variable
* We don't rebuild the playlist directly here because we don't want the
* caller to block for a too long time.
*****************************************************************************/
static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
vlc_value_t oval, vlc_value_t nval, void *param )
{
PlaylistManager *p_playlist = (PlaylistManager *)param;
p_playlist->b_need_update = VLC_TRUE;
return VLC_SUCCESS;
}
/*****************************************************************************
* Next: callback triggered by the playlist-current playlist variable
*****************************************************************************/
static int PlaylistNext( vlc_object_t *p_this, const char *psz_variable,
vlc_value_t oval, vlc_value_t nval, void *param )
{
PlaylistManager *p_playlist = (PlaylistManager *)param;
wxCommandEvent event( wxEVT_PLAYLIST, UpdateItem_Event );
event.SetInt( oval.i_int );
p_playlist->AddPendingEvent( event );
event.SetInt( nval.i_int );
p_playlist->AddPendingEvent( event );
return VLC_SUCCESS;
}
/*****************************************************************************
* Update functions
*****************************************************************************/
void PlaylistManager::CreateNode( playlist_item_t *p_node, wxTreeItemId parent)
{
wxTreeItemId node =
treectrl->AppendItem( parent, wxL2U( p_node->input.psz_name ), -1, -1,
new PlaylistItem( p_node ) );
treectrl->SetItemImage( node, p_node->input.i_type );
UpdateNodeChildren( p_node, node );
}
void PlaylistManager::UpdateNode( playlist_item_t *p_node, wxTreeItemId node )
{
wxTreeItemIdValue cookie;
wxTreeItemId child;
for( int i = 0; i < p_node->i_children ; i++ )
{
if( !i ) child = treectrl->GetFirstChild( node, cookie);
else child = treectrl->GetNextChild( node, cookie );
if( !child.IsOk() )
{
/* Not enough children */
CreateNode( p_node->pp_children[i], node );
/* Keep the tree pointer up to date */
child = treectrl->GetNextChild( node, cookie );
}
}
treectrl->SetItemImage( node, p_node->input.i_type );
}
void PlaylistManager::UpdateNodeChildren( playlist_item_t *p_node,
wxTreeItemId node )
{
for( int i = 0; i< p_node->i_children ; i++ )
{
/* Append the item */
if( p_node->pp_children[i]->i_children == -1 )
{
wxTreeItemId item =
treectrl->AppendItem( node,
wxL2U( p_node->pp_children[i]->input.psz_name ), -1,-1,
new PlaylistItem( p_node->pp_children[i]) );
UpdateTreeItem( item );
}
else
{
CreateNode( p_node->pp_children[i], node );
}
}
}
void PlaylistManager::UpdateTreeItem( wxTreeItemId item )
{
if( ! item.IsOk() ) return;
wxTreeItemData *p_data = treectrl->GetItemData( item );
if( !p_data ) return;
LockPlaylist( p_intf->p_sys, p_playlist );
playlist_item_t *p_item =
playlist_ItemGetById( p_playlist, ((PlaylistItem *)p_data)->i_id );
if( !p_item )
{
UnlockPlaylist( p_intf->p_sys, p_playlist );
return;
}
wxString msg;
wxString duration = wxU( "" );
char *psz_author =
vlc_input_item_GetInfo( &p_item->input,
_("Meta-information"), _("Artist"));
if( !psz_author )
{
UnlockPlaylist( p_intf->p_sys, p_playlist );
return;
}
char psz_duration[MSTRTIME_MAX_SIZE];
mtime_t dur = p_item->input.i_duration;
if( dur != -1 )
{
secstotimestr( psz_duration, dur/1000000 );
duration.Append( wxU( " ( " ) + wxString( wxU( psz_duration ) ) +
wxU( " )" ) );
}
if( !strcmp( psz_author, "" ) || p_item->input.b_fixed_name == VLC_TRUE )
{
msg = wxString( wxU( p_item->input.psz_name ) ) + duration;
}
else
{
msg = wxString(wxU( psz_author )) + wxT(" - ") +
wxString(wxU(p_item->input.psz_name)) + duration;
}
free( psz_author );
treectrl->SetItemText( item , msg );
treectrl->SetItemImage( item, p_item->input.i_type );
if( p_playlist->status.p_item == p_item )
{
treectrl->SetItemBold( item, true );
while( treectrl->GetItemParent( item ).IsOk() )
{
item = treectrl->GetItemParent( item );
treectrl->Expand( item );
}
}
else
{
treectrl->SetItemBold( item, false );
}
UnlockPlaylist( p_intf->p_sys, p_playlist );
}
void PlaylistManager::AppendItem( wxCommandEvent& event )
{
playlist_add_t *p_add = (playlist_add_t *)event.GetClientData();
playlist_item_t *p_item = NULL;
wxTreeItemId item, node;
i_items_to_append--;
/* No need to do anything if the playlist is going to be rebuilt */
if( b_need_update ) return;
//if( p_add->i_view != i_current_view ) goto update;
node = FindItem( treectrl->GetRootItem(), p_add->i_node );
if( !node.IsOk() ) goto update;
p_item = playlist_ItemGetById( p_playlist, p_add->i_item );
if( !p_item ) goto update;
item = FindItem( treectrl->GetRootItem(), p_add->i_item );
if( item.IsOk() ) goto update;
item = treectrl->AppendItem( node, wxL2U( p_item->input.psz_name ), -1,-1,
new PlaylistItem( p_item ) );
treectrl->SetItemImage( item, p_item->input.i_type );
if( item.IsOk() && p_item->i_children == -1 ) UpdateTreeItem( item );
update:
return;
}
void PlaylistManager::UpdateItem( int i )
{
if( i < 0 ) return; /* Sanity check */
wxTreeItemId item = FindItem( treectrl->GetRootItem(), i );
if( item.IsOk() ) UpdateTreeItem( item );
}
void PlaylistManager::RemoveItem( int i )
{
if( i <= 0 ) return; /* Sanity check */
wxTreeItemId item = FindItem( treectrl->GetRootItem(), i );
if( item.IsOk() )
{
treectrl->Delete( item );
/* Invalidate cache */
i_cached_item_id = -1;
}
}
/* This function is called on a regular basis */
void PlaylistManager::Update()
{
i_update_counter++;
/* If the playlist isn't show there's no need to update it */
if( !IsShown() ) return;
if( this->b_need_update )
{
this->b_need_update = VLC_FALSE;
Rebuild( VLC_TRUE );
}
/* Updating the playing status every 0.5s is enough */
if( i_update_counter % 5 ) return;
}
/**********************************************************************
* Rebuild the playlist
**********************************************************************/
void PlaylistManager::Rebuild( vlc_bool_t b_root )
{
playlist_view_t *p_view;
i_items_to_append = 0;
i_cached_item_id = -1;
p_view = playlist_ViewFind( p_playlist, VIEW_CATEGORY );
treectrl->DeleteAllItems();
treectrl->AddRoot( wxU(_("root" )), -1, -1,
new PlaylistItem( p_view->p_root ) );
wxTreeItemId root = treectrl->GetRootItem();
UpdateNode( p_view->p_root, root );
}
/**********************************************************************
* Search functions (internal)
**********************************************************************/
/* Find a wxItem from a playlist id */
wxTreeItemId PlaylistManager::FindItem( wxTreeItemId root, int i_id )
{
wxTreeItemIdValue cookie;
PlaylistItem *p_wxcurrent;
wxTreeItemId dummy, search, item, child;
if( i_id < 0 ) return dummy;
if( i_cached_item_id == i_id ) return cached_item;
p_wxcurrent = (PlaylistItem *)treectrl->GetItemData( root );