Commit 12cbd4c8 authored by Clément Stenac's avatar Clément Stenac

* include/vlc_playlist.h

  src/playlist/playlist.c:
     * Implemented a boolean b_enabled to disable a playlist item
     * Implemented the idea of group (p_item->i_group), that allows
       to enable/disable and to sort some series of items
     * Implemented an unused (at the moment), psz_author field
     * Started to implement a new playlist format to store all of these

* modules/gui/wxwindows/interface.cpp:
     Added a hiddeable panel to put some important options.
     (Menu Preferences->Extra GUI)
     At the moment, we put the adjust filter and aspect ratio, and must
     decide what options we want here

* modules/gui/wxwindows/playlist.cpp
  modules/gui/wxwindows/iteminfo.cpp:
     Added "Enable/disable group button", options to enable/disable selection
     Added an item info dialog box

* modules/misc/sap.c :
     Added a sap-group-id option: the SAP playlist items are in a separate group
     (defaults to 42)

* modules/visualization/visual/effects.c:
     Minor coding style fixes

Todo:
-----

* Advanced sort (alphabetical and/or by group)
* Ability to load 0_6 playlists
* Really use the libid3tag
parent de2868c4
......@@ -2,7 +2,7 @@
* vlc_playlist.h : Playlist functions
*****************************************************************************
* Copyright (C) 1999, 2000, 2001, 2002 VideoLAN
* $Id: vlc_playlist.h,v 1.13 2003/09/08 12:02:16 zorglub Exp $
* $Id: vlc_playlist.h,v 1.14 2003/10/06 16:23:30 zorglub Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
......@@ -10,7 +10,7 @@
* 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
......@@ -48,10 +48,15 @@ struct playlist_item_t
* ppsz_options array */
int i_type; /**< unused yet */
int i_status; /**< unused yet */
vlc_bool_t b_autodeletion; /**< Indicates wether this item is to
vlc_bool_t b_autodeletion; /**< Indicates whther this item is to
* be deleted after playback. True mean
* that this item is to be deleted
* after playback, false otherwise */
vlc_bool_t b_enabled; /**< Indicates whether this item is to be
* played or skipped */
int i_group; /**< unused yet */
char * psz_author; /**< Author */
};
/**
......@@ -73,7 +78,7 @@ struct playlist_t
int i_index; /**< current index into the playlist */
playlist_status_t i_status; /**< current status of playlist */
int i_size; /**< total size of the list */
int i_enabled; /**< How many items are enabled ? */
playlist_item_t ** pp_items; /**< array of pointers to the
* playlist items */
......@@ -85,6 +90,9 @@ struct playlist_t
#define SORT_NORMAL 0
#define SORT_REVERSE 1
#define PLAYLIST_TYPE_MANUAL 0
#define PLAYLIST_TYPE_SAP 1
/*****************************************************************************
* Prototypes
*****************************************************************************/
......@@ -105,6 +113,10 @@ VLC_EXPORT( int, playlist_Add, ( playlist_t *, const char *, const char **,
VLC_EXPORT( int, playlist_AddExt, ( playlist_t *, const char *, const char *, mtime_t, const char **, int, int, int ) );
VLC_EXPORT( int, playlist_AddItem, ( playlist_t *, playlist_item_t *, int, int ) );
VLC_EXPORT( int, playlist_Delete, ( playlist_t *, int ) );
VLC_EXPORT( int, playlist_Disable, ( playlist_t *, int ) );
VLC_EXPORT( int, playlist_Enable, ( playlist_t *, int ) );
VLC_EXPORT( int, playlist_DisableGroup, ( playlist_t *, int ) );
VLC_EXPORT( int, playlist_EnableGroup, ( playlist_t *, int ) );
VLC_EXPORT( int, playlist_Sort, ( playlist_t *, int) );
VLC_EXPORT( int, playlist_Move, ( playlist_t *, int, int ) );
VLC_EXPORT( int, playlist_LoadFile, ( playlist_t *, const char * ) );
......
......@@ -7,6 +7,7 @@ SOURCES_wxwindows = \
streamout.cpp \
messages.cpp \
playlist.cpp \
iteminfo.cpp \
menus.cpp \
preferences.cpp \
timer.cpp \
......
......@@ -2,7 +2,7 @@
* interface.cpp : wxWindows plugin for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: interface.cpp,v 1.60 2003/09/07 22:53:09 fenrir Exp $
* $Id: interface.cpp,v 1.61 2003/10/06 16:23:30 zorglub Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
......@@ -125,6 +125,7 @@ enum
FileInfo_Event,
Prefs_Event,
Extra_Event,
SliderScroll_Event,
StopStream_Event,
......@@ -134,6 +135,13 @@ enum
SlowStream_Event,
FastStream_Event,
Adjust_Event,
Hue_Event,
Contrast_Event,
Brightness_Event,
Saturation_Event,
Ratio_Event,
/* it is important for the id corresponding to the "About" command to have
* this standard value as otherwise it won't be handled properly under Mac
* (where it is special and put into the "Apple" menu) */
......@@ -152,6 +160,11 @@ BEGIN_EVENT_TABLE(Interface, wxFrame)
EVT_MENU_OPEN(Interface::OnMenuOpen)
EVT_MENU( Extra_Event, Interface::OnExtra)
EVT_CHECKBOX( Adjust_Event, Interface::OnEnableAdjust)
EVT_COMBOBOX( Ratio_Event, Interface::OnRatio)
#if defined( __WXMSW__ ) || defined( __WXMAC__ )
EVT_CONTEXT_MENU(Interface::OnContextMenu2)
#endif
......@@ -173,6 +186,11 @@ BEGIN_EVENT_TABLE(Interface, wxFrame)
/* Slider events */
EVT_COMMAND_SCROLL(SliderScroll_Event, Interface::OnSliderUpdate)
EVT_COMMAND_SCROLL(Hue_Event, Interface::OnHueUpdate)
EVT_COMMAND_SCROLL(Contrast_Event, Interface::OnContrastUpdate)
EVT_COMMAND_SCROLL(Brightness_Event, Interface::OnBrightnessUpdate)
EVT_COMMAND_SCROLL(Saturation_Event, Interface::OnSaturationUpdate)
END_EVENT_TABLE()
/*****************************************************************************
......@@ -185,12 +203,14 @@ Interface::Interface( intf_thread_t *_p_intf ):
/* Initializations */
p_intf = _p_intf;
i_old_playing_status = PAUSE_S;
b_extra = VLC_FALSE;
/* Give our interface a nice little icon */
SetIcon( wxIcon( vlc_xpm ) );
/* Create a sizer for the main frame */
frame_sizer = new wxBoxSizer( wxHORIZONTAL );
//frame_sizer= new wxFlexGridSizer( 1, 0, 0);
frame_sizer = new wxBoxSizer( wxVERTICAL );
SetSizer( frame_sizer );
/* Create a dummy widget that can get the keyboard focus */
......@@ -198,7 +218,7 @@ Interface::Interface( intf_thread_t *_p_intf ):
wxSize(0,0) );
p_dummy->SetFocus();
frame_sizer->Add( p_dummy );
/* Creation of the menu bar */
CreateOurMenuBar();
......@@ -207,9 +227,14 @@ Interface::Interface( intf_thread_t *_p_intf ):
/* Creation of the slider sub-window */
CreateOurSlider();
frame_sizer->Add( slider_frame, 1, wxGROW, 0 );
frame_sizer->Add( slider_frame, 0, wxEXPAND , 0 );
frame_sizer->Hide( slider_frame );
/* Create the extra panel */
CreateOurExtraPanel();
frame_sizer->Add( extra_frame, 0, wxEXPAND , 0 );
frame_sizer->Hide( extra_frame );
/* Creation of the status bar
* Helptext for menu items and toolbar tools will automatically get
* displayed here. */
......@@ -260,6 +285,7 @@ void Interface::CreateOurMenuBar()
#define HELP_FILEINFO N_("Show information about the file being played")
#define HELP_PREFS N_("Go to the preferences menu")
#define EXTRA_PREFS N_("Open the extended GUI")
#define HELP_ABOUT N_("About this program")
......@@ -297,6 +323,9 @@ void Interface::CreateOurMenuBar()
wxMenu *settings_menu = new wxMenu;
settings_menu->Append( Prefs_Event, wxU(_("&Preferences...")),
wxU(_(HELP_PREFS)) );
settings_menu->Append( Extra_Event, wxU(_("&Extra GUI") ),
wxU(_(EXTRA_PREFS)) );
/* Create the "Audio" menu */
p_audio_menu = new wxMenu;
......@@ -388,6 +417,7 @@ void Interface::CreateOurToolBar()
* toolbar and set this as the minimum for the main frame size. */
wxBoxSizer *toolbar_sizer = new wxBoxSizer( wxHORIZONTAL );
toolbar_sizer->Add( toolbar, 0, 0, 0 );
toolbar_sizer->Layout();
#ifndef WIN32
......@@ -438,6 +468,142 @@ void Interface::CreateOurSlider()
slider_frame->Hide();
}
void Interface::CreateOurExtraPanel()
{
char *psz_filters;
extra_frame = new wxPanel( this, -1, wxDefaultPosition, wxDefaultSize );
extra_frame->SetAutoLayout( TRUE );
wxBoxSizer *extra_sizer = new wxBoxSizer( wxHORIZONTAL );
/* Create static box to surround the adjust controls */
adjust_box = new wxStaticBox( extra_frame, -1,
wxT(_("Image adjust")) );
/* Create the size for the frame */
wxStaticBoxSizer *adjust_sizer =
new wxStaticBoxSizer( adjust_box, wxVERTICAL );
adjust_sizer->SetMinSize( -1, 50 );
/* Create every controls */
/* Create the adjust button */
wxCheckBox * adjust_check = new wxCheckBox( extra_frame, Adjust_Event,
wxU(_("Enable")));
wxBoxSizer *hue_sizer = new wxBoxSizer( wxHORIZONTAL );
wxStaticText *hue_text = new wxStaticText( extra_frame, -1,
wxU(_("Hue")) );
hue_slider = new wxSlider ( extra_frame, Hue_Event, 0, 0,
360, wxDefaultPosition, wxDefaultSize );
hue_sizer->Add(hue_text,1, 0 ,0);
hue_sizer->Add(hue_slider,1, 0 ,0);
hue_sizer->Layout();
wxBoxSizer *contrast_sizer = new wxBoxSizer( wxHORIZONTAL );
wxStaticText *contrast_text = new wxStaticText( extra_frame, -1,
wxU(_("Contrast")) );
contrast_slider = new wxSlider ( extra_frame, Contrast_Event, 0, 0,
200, wxDefaultPosition, wxDefaultSize);
contrast_sizer->Add(contrast_text,1, 0 ,0);
contrast_sizer->Add(contrast_slider,1, 0 ,0);
contrast_sizer->Layout();
wxBoxSizer *brightness_sizer = new wxBoxSizer( wxHORIZONTAL );
wxStaticText *brightness_text = new wxStaticText( extra_frame, -1,
wxU(_("Brightness")) );
brightness_slider = new wxSlider ( extra_frame, Brightness_Event, 0, 0,
200, wxDefaultPosition, wxDefaultSize) ;
brightness_sizer->Add(brightness_text,1,0,0);
brightness_sizer->Add(brightness_slider,1,0,0);
brightness_sizer->Layout();
wxBoxSizer *saturation_sizer = new wxBoxSizer( wxHORIZONTAL );
wxStaticText *saturation_text = new wxStaticText( extra_frame, -1,
wxU(_("Saturation")) );
saturation_slider = new wxSlider ( extra_frame, Saturation_Event, 0, 0,
300, wxDefaultPosition, wxDefaultSize );
saturation_sizer->Add(saturation_text,1,0,0);
saturation_sizer->Add(saturation_slider,1,0,0);
saturation_sizer->Layout();
adjust_sizer->Add(adjust_check, 1, wxEXPAND, 0);
adjust_sizer->Add(hue_sizer, 1, wxEXPAND, 0);
adjust_sizer->Add(contrast_sizer, 1, wxEXPAND, 0);
adjust_sizer->Add(brightness_sizer, 1, wxEXPAND, 0);
adjust_sizer->Add(saturation_sizer, 1, wxEXPAND, 0);
extra_sizer->Add(adjust_sizer,1,wxBOTTOM,5);
/* Create static box to surround the other controls */
other_box = new wxStaticBox( extra_frame, -1,
wxT(_("Video Options")) );
/* Create the sizer for the frame */
wxStaticBoxSizer *other_sizer =
new wxStaticBoxSizer( other_box, wxVERTICAL );
other_sizer->SetMinSize( -1, 50 );
static const wxString ratio_array[] =
{
wxT("4:3"),
wxT("16:9"),
};
wxBoxSizer *ratio_sizer = new wxBoxSizer( wxHORIZONTAL );
wxStaticText *ratio_text = new wxStaticText( extra_frame, -1,
wxU(_("Ratio")) );
ratio_combo = new wxComboBox( extra_frame, Ratio_Event, wxT(""),
wxDefaultPosition, wxSize(120,-1),
WXSIZEOF(ratio_array), ratio_array,
0 );
ratio_sizer->Add( ratio_text, 0, wxALL, 2 );
ratio_sizer->Add( ratio_combo, 0, wxALL, 2 );
ratio_sizer->Layout();
other_sizer->Add(ratio_sizer,0,wxALL,0 );
extra_sizer->Add(other_sizer,0,wxBOTTOM,5);
extra_frame->SetSizer( extra_sizer );
/* Layout the whole panel */
extra_sizer->Layout();
extra_sizer->SetSizeHints(extra_frame);
/* Write down initial values */
psz_filters = config_GetPsz( p_intf, "filter" );
if(psz_filters == NULL) psz_filters=strdup("");
if( strstr(psz_filters,"adjust") )
{
adjust_check->SetValue( 1 );
saturation_slider->Enable();
contrast_slider->Enable();
brightness_slider->Enable();
hue_slider->Enable();
}
else
{
adjust_check->SetValue( 0 );
saturation_slider->Disable();
contrast_slider->Disable();
brightness_slider->Disable();
hue_slider->Disable();
}
extra_frame->Hide();
free(psz_filters);
}
void Interface::UpdateAcceleratorTable()
{
/* Set some hotkeys */
......@@ -469,12 +635,14 @@ void Interface::UpdateAcceleratorTable()
if( !accel.Ok() )
msg_Err( p_intf, "invalid accelerator table" );
SetAcceleratorTable( accel );
msg_Dbg( p_intf, "accelerator table loaded" );
}
/*****************************************************************************
* Event Handlers.
*****************************************************************************/
......@@ -659,6 +827,108 @@ void Interface::OnShowDialog( wxCommandEvent& event )
}
}
void Interface::OnExtra(wxCommandEvent& event)
{
if( b_extra == VLC_FALSE)
{
extra_frame->Show();
frame_sizer->Show( extra_frame );
b_extra = VLC_TRUE;
}
else
{
extra_frame->Hide();
frame_sizer->Hide( extra_frame );
b_extra = VLC_FALSE;
}
frame_sizer->Layout();
frame_sizer->Fit(this);
}
void Interface::OnEnableAdjust(wxCommandEvent& event)
{
char *psz_filters=config_GetPsz( p_intf, "filter");
char *psz_new = NULL;
if( event.IsChecked() )
{
if(psz_filters == NULL)
{
psz_new = strdup( "adjust" );
}
else
{
psz_new= (char *) malloc(strlen(psz_filters) + 8 );
sprintf( psz_new, "%s:adjust", psz_filters);
}
config_PutPsz( p_intf, "filter", psz_new );
brightness_slider->Enable();
saturation_slider->Enable();
contrast_slider->Enable();
hue_slider->Enable();
}
else
{
if( psz_filters != NULL )
{
char *psz_current;
unsigned int i=0;
for( i = 0; i< strlen(psz_filters ); i++)
{
if ( !strncasecmp( &psz_filters[i],"adjust",6 ))
{
if(i > 0)
if( psz_filters[i-1] == ':' ) i--;
psz_current = strchr( &psz_filters[i+1] , ':' );
if( !psz_current )
psz_filters[i] = '\0';
else
{
memmove( &psz_filters[i] , psz_current,
&psz_filters[strlen(psz_filters)]-psz_current
+1);
}
}
}
config_PutPsz( p_intf, "filter", psz_filters);
}
brightness_slider->Disable();
saturation_slider->Disable();
contrast_slider->Disable();
hue_slider->Disable();
}
if(psz_filters) free(psz_filters);
if(psz_new) free(psz_new);
}
void Interface::OnHueUpdate( wxScrollEvent& event)
{
config_PutInt( p_intf , "hue" , event.GetPosition() );
}
void Interface::OnSaturationUpdate( wxScrollEvent& event)
{
config_PutFloat( p_intf , "saturation" , (float)event.GetPosition()/300 );
}
void Interface::OnBrightnessUpdate( wxScrollEvent& event)
{
config_PutFloat( p_intf , "brightness", (float)event.GetPosition()/200 );
}
void Interface::OnContrastUpdate(wxScrollEvent& event)
{
config_PutFloat( p_intf , "contrast" , (float)event.GetPosition()/200 );
}
void Interface::OnRatio( wxCommandEvent& event )
{
config_PutPsz( p_intf, "aspect-ratio", ratio_combo->GetValue() );
}
void Interface::OnPlayStream( wxCommandEvent& WXUNUSED(event) )
{
wxCommandEvent dummy;
......@@ -667,7 +937,7 @@ void Interface::OnPlayStream( wxCommandEvent& WXUNUSED(event) )
FIND_ANYWHERE );
if( p_playlist == NULL ) return;
if( p_playlist->i_size )
if( p_playlist->i_size && p_playlist->i_enabled )
{
vlc_value_t state;
......
/*****************************************************************************
* iteminfo.cpp : wxWindows plugin for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: iteminfo.cpp,v 1.1 2003/10/06 16:23:30 zorglub Exp $
*
* Authors: Clment Stenac <zorglub@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 <stdlib.h> /* malloc(), free() */
#include <errno.h> /* ENOMEM */
#include <string.h> /* strerror() */
#include <stdio.h>
#include <vlc/vlc.h>
#ifdef WIN32 /* mingw32 hack */
#undef Yield
#undef CreateDialog
#endif
/* Let vlc take care of the i18n stuff */
#define WXINTL_NO_GETTEXT_MACRO
#include <wx/wxprec.h>
#include <wx/wx.h>
#include <wx/notebook.h>
#include <wx/textctrl.h>
#include <wx/combobox.h>
#include <wx/spinctrl.h>
#include <wx/statline.h>
#include <vlc/intf.h>
#include "wxwindows.h"
#ifndef wxRB_SINGLE
# define wxRB_SINGLE 0
#endif
/*****************************************************************************
* Event Table.
*****************************************************************************/
/* IDs for the controls and the menu commands */
enum
{
Uri_Event,
Name_Event,
Author_Event,
Enabled_Event,
};
BEGIN_EVENT_TABLE(ItemInfoDialog, wxDialog)
/* Button events */
EVT_BUTTON(wxID_OK, ItemInfoDialog::OnOk)
EVT_BUTTON(wxID_CANCEL, ItemInfoDialog::OnCancel)
/* Events generated by the panels */
END_EVENT_TABLE()
/*****************************************************************************
* Constructor.
*****************************************************************************/
ItemInfoDialog::ItemInfoDialog( intf_thread_t *_p_intf,
playlist_item_t *_p_item,
wxWindow* _p_parent ):
wxDialog( _p_parent, -1, wxU(_("Playlist Item options")),
wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE )
{
/* Initializations */
p_intf = _p_intf;
p_parent = _p_parent;
p_item = _p_item;
SetIcon( *p_intf->p_sys->p_icon );
/* Create a panel to put everything in */
wxPanel *panel = new wxPanel( this, -1 );
panel->SetAutoLayout( TRUE );
/* Create the standard info panel */
wxPanel *info_panel = InfoPanel( panel );
/* Create the group panel */
wxPanel *group_panel = GroupPanel( panel );
/* Separation */
wxStaticLine *static_line = new wxStaticLine( panel, wxID_OK );
/* Create the buttons */
wxButton *ok_button = new wxButton( panel, wxID_OK, wxU(_("OK")) );
ok_button->SetDefault();
wxButton *cancel_button = new wxButton( panel, wxID_CANCEL,
wxU(_("Cancel")) );
/* Place everything in sizers */
wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
button_sizer->Add( ok_button, 0, wxALL, 5 );
button_sizer->Add( cancel_button, 0, wxALL, 5 );
button_sizer->Layout();
wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
panel_sizer->Add( info_panel, 0, wxEXPAND | wxALL, 5 );
panel_sizer->Add( group_panel, 0, wxEXPAND | wxALL, 5 );
panel_sizer->Add( static_line, 0, wxEXPAND | wxALL, 5 );
panel_sizer->Add( button_sizer, 0, wxALIGN_LEFT | wxALIGN_BOTTOM |
wxALL, 5 );
panel_sizer->Layout();
panel->SetSizerAndFit( panel_sizer );
main_sizer->Add( panel, 1, wxGROW, 0 );
main_sizer->Layout();
SetSizerAndFit( main_sizer );
}
ItemInfoDialog::~ItemInfoDialog()
{
}
/*****************************************************************************
* Private methods.
*****************************************************************************/
wxPanel *ItemInfoDialog::InfoPanel( wxWindow* parent )
{
wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
wxDefaultSize );
wxStaticBox *panel_box = new wxStaticBox( panel, -1,
wxU(_("Item informations")) );
wxStaticBoxSizer *panel_sizer = new wxStaticBoxSizer( panel_box,
wxVERTICAL );
info_subpanel = new wxPanel( panel, -1 );
wxFlexGridSizer *subpanel_sizer =
new wxFlexGridSizer( 3, 1 , 0 , 0 );
/* URI Textbox */
wxStaticText *uri_label =
new wxStaticText(info_subpanel, -1, wxU(_("URI")) );
uri_text = new wxTextCtrl( info_subpanel, Uri_Event,
wxT(p_item->psz_uri),
wxDefaultPosition, wxSize( 300, -1 ),
wxTE_PROCESS_ENTER);
subpanel_sizer->Add( uri_label, 0, wxALIGN_LEFT |
wxALIGN_CENTER_VERTICAL );
subpanel_sizer->Add( uri_text, 0, wxALIGN_RIGHT |
wxALIGN_CENTER_VERTICAL );
/* Name Textbox */
wxStaticText *name_label =
new wxStaticText(info_subpanel, -1, wxU(_("Name")) );
name_text =
new wxTextCtrl( info_subpanel, Uri_Event,
wxT(p_item->psz_name),
wxDefaultPosition, wxSize( 300, -1 ),
wxTE_PROCESS_ENTER);
subpanel_sizer->Add( name_label, 0, wxALIGN_LEFT |
wxALIGN_CENTER_VERTICAL );
subpanel_sizer->Add( name_text, 0, wxALIGN_RIGHT |
wxALIGN_CENTER_VERTICAL );
/* Author Textbox */
wxStaticText *author_label =
new wxStaticText(info_subpanel, -1, wxU(_("Author")) );
author_text =
new wxTextCtrl( info_subpanel, Uri_Event,
wxT(p_item->psz_author),
wxDefaultPosition, wxSize( 300, -1 ),
wxTE_PROCESS_ENTER);
subpanel_sizer->Add( author_label, 0, wxALIGN_LEFT |
wxALIGN_CENTER_VERTICAL );
subpanel_sizer->Add( author_text, 0, wxALIGN_RIGHT |
wxALIGN_CENTER_VERTICAL );
info_subpanel->SetSizerAndFit( subpanel_sizer );
/* Stuff everything into the main panel */
panel_sizer->Add( info_subpanel, 1,
wxEXPAND | wxALIGN_LEFT |
wxALIGN_CENTER_VERTICAL | wxALL, 5 );
panel->SetSizerAndFit( panel_sizer );
return panel;
}
wxPanel *ItemInfoDialog::GroupPanel( wxWindow* parent )
{
wxPanel *panel = new wxPanel( parent, -1, wxDefaultPosition,
wxDefaultSize );
wxStaticBox *panel_box = new wxStaticBox( panel, -1,
wxU(_("Group Info")) );
wxStaticBoxSizer *panel_sizer = new wxStaticBoxSizer( panel_box,
wxVERTICAL);
wxBoxSizer *subpanel_sizer;
group_subpanel = new wxPanel( panel, -1 );
subpanel_sizer = new wxBoxSizer( wxVERTICAL) ;
enabled_checkbox = new wxCheckBox( group_subpanel,
-1,
wxU(_("Item enabled")) );
enabled_checkbox->SetValue( p_item->b_enabled);
wxStaticText *group_label = new wxStaticText( group_subpanel,
-1, wxU(_("Group")) );
group_spin = new wxSpinCtrl( group_subpanel,
-1 );
group_spin->SetValue( p_item->i_group > 0 ? p_item->i_group : 0);
subpanel_sizer->Add( enabled_checkbox, 0, wxALIGN_RIGHT|
wxALIGN_CENTER_VERTICAL );
subpanel_sizer->Add( group_label, 0, wxALIGN_LEFT |
wxALIGN_CENTER_VERTICAL );
subpanel_sizer->Add( group_spin, 0, wxALIGN_RIGHT );
group_subpanel->SetSizerAndFit( subpanel_sizer );
/* Stuff everything into the main panel */
panel_sizer->Add( group_subpanel, 0,
wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 5 );
panel->SetSizerAndFit( panel_sizer );
/* Update panel */
return panel;
}
/*****************************************************************************
* Events methods.
*****************************************************************************/
void ItemInfoDialog::OnOk( wxCommandEvent& WXUNUSED(event) )
{
p_item->psz_name = strdup( name_text->GetLineText(0) );
p_item->psz_uri = strdup( uri_text->GetLineText(0) );
p_item->psz_author = strdup( author_text->GetLineText(0) );
vlc_bool_t b_old_enabled = p_item->b_enabled;
playlist_t * p_playlist =
(playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist != NULL )
{
if( b_old_enabled == VLC_FALSE && enabled_checkbox->IsChecked() )
p_playlist->i_enabled ++;
else if( b_old_enabled == VLC_TRUE && !enabled_checkbox->IsChecked() )
p_playlist->i_enabled --;
vlc_object_release( p_playlist );
}
p_item->b_enabled = enabled_checkbox->IsChecked() ? VLC_TRUE : VLC_FALSE ;
p_item->i_group = group_spin->GetValue();
EndModal( wxID_OK );
}
void ItemInfoDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
{
EndModal( wxID_CANCEL );
}
/******************************************************************************
* Info panel event methods.
******************************************************************************/
......@@ -2,7 +2,7 @@
* playlist.cpp : wxWindows plugin for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: playlist.cpp,v 1.21 2003/09/22 14:40:10 zorglub Exp $
* $Id: playlist.cpp,v 1.22 2003/10/06 16:23:30 zorglub Exp $
*
* Authors: Olivier Teulire <ipkiss@via.ecp.fr>
*
......@@ -55,6 +55,9 @@ enum
Open_Event,
Save_Event,
EnableSelection_Event,
DisableSelection_Event,
InvertSelection_Event,
DeleteSelection_Event,
Random_Event,
......@@ -62,6 +65,10 @@ enum
Repeat_Event,
SelectAll_Event,
En_Dis_Event,
Infos_Event,
SearchText_Event,
Search_Event,
......@@ -78,9 +85,12 @@ BEGIN_EVENT_TABLE(Playlist, wxFrame)
EVT_MENU(Close_Event, Playlist::OnClose)
EVT_MENU(Open_Event, Playlist::OnOpen)
EVT_MENU(Save_Event, Playlist::OnSave)
EVT_MENU(EnableSelection_Event, Playlist::OnEnableSelection)
EVT_MENU(DisableSelection_Event, Playlist::OnDisableSelection)
EVT_MENU(InvertSelection_Event, Playlist::OnInvertSelection)
EVT_MENU(DeleteSelection_Event, Playlist::OnDeleteSelection)
EVT_MENU(SelectAll_Event, Playlist::OnSelectAll)
EVT_MENU(Infos_Event, Playlist::OnInfos)
EVT_CHECKBOX(Random_Event, Playlist::OnRandom)
EVT_CHECKBOX(Repeat_Event, Playlist::OnRepeat)
EVT_CHECKBOX(Loop_Event, Playlist::OnLoop)
......@@ -91,7 +101,9 @@ BEGIN_EVENT_TABLE(Playlist, wxFrame)
/* Button events */
EVT_BUTTON( Search_Event, Playlist::OnSearch)
EVT_BUTTON( En_Dis_Event, Playlist::OnEnDis)
EVT_BUTTON( Save_Event, Playlist::OnSave)
EVT_BUTTON( Infos_Event, Playlist::OnInfos)
EVT_TEXT(SearchText_Event, Playlist::OnSearchTextChange)
......@@ -108,6 +120,7 @@ Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ):
wxDefaultSize, wxDEFAULT_FRAME_STYLE )
{
/* Initializations */
iteminfo_dialog = NULL;
p_intf = _p_intf;
vlc_value_t val;
i_update_counter = 0;
......@@ -135,6 +148,9 @@ Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ):
/* Create our "Selection" menu */
wxMenu *selection_menu = new wxMenu;
selection_menu->Append( EnableSelection_Event, wxU(_("&Enable")) );
selection_menu->Append( DisableSelection_Event, wxU(_("&Disable")) );
selection_menu->AppendSeparator();
selection_menu->Append( InvertSelection_Event, wxU(_("&Invert")) );
selection_menu->Append( DeleteSelection_Event, wxU(_("&Delete")) );
selection_menu->Append( SelectAll_Event, wxU(_("&Select All")) );
......@@ -161,76 +177,87 @@ Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ):
wxLC_REPORT | wxSUNKEN_BORDER );
listview->InsertColumn( 0, wxU(_("Url")) );
#if 0
listview->InsertColumn( 1, wxU(_("Duration")) );
listview->InsertColumn( 1, wxU(_("Duration")) );
#endif
listview->SetColumnWidth( 0, 300 );
#if 0
listview->SetColumnWidth( 1, 100 );
listview->SetColumnWidth( 1, 100 );
#endif
/* Create the Random checkbox */
wxCheckBox *random_checkbox =
wxCheckBox *random_checkbox =
new wxCheckBox( playlist_panel, Random_Event, wxU(_("Random")) );
var_Get( p_intf, "random", &val);
vlc_bool_t b_random = val.b_bool;
random_checkbox->SetValue( b_random == VLC_FALSE ? 0 : 1);
/* Create the Loop Checkbox */
wxCheckBox *loop_checkbox =
wxCheckBox *loop_checkbox =
new wxCheckBox( playlist_panel, Loop_Event, wxU(_("Loop")) );
var_Get( p_intf, "loop", &val );
int b_loop = val.b_bool ;
int b_loop = val.b_bool ;
loop_checkbox->SetValue( b_loop );
/* Create the Repeat one checkbox */
wxCheckBox *repeat_checkbox =
new wxCheckBox( playlist_panel, Repeat_Event, wxU(_("Repeat one")) );
wxCheckBox *repeat_checkbox =
new wxCheckBox( playlist_panel, Repeat_Event, wxU(_("Repeat one")) );
var_Get( p_intf, "repeat", &val );
int b_repeat = val.b_bool ;
int b_repeat = val.b_bool ;
repeat_checkbox->SetValue( b_repeat );
/* Create the Search Textbox */
search_text =
new wxTextCtrl( playlist_panel, SearchText_Event, wxT(""),
wxDefaultPosition, wxSize( 140, -1),
wxTE_PROCESS_ENTER);
new wxTextCtrl( playlist_panel, SearchText_Event, wxT(""),
wxDefaultPosition, wxSize( 140, -1),
wxTE_PROCESS_ENTER);
/* Create the search button */
search_button =
new wxButton( playlist_panel, Search_Event, wxU(_("Search")) );
search_button =
new wxButton( playlist_panel, Search_Event, wxU(_("Search")) );
/* Place everything in sizers */
wxBoxSizer *button_sizer = new wxBoxSizer( wxVERTICAL );
button_sizer->Add( random_checkbox, 0,
wxEXPAND|wxALIGN_RIGHT, 5);
button_sizer->Add( loop_checkbox, 0,
wxEXPAND|wxALIGN_RIGHT, 5);
button_sizer->Add( repeat_checkbox, 0,
wxEXPAND|wxALIGN_RIGHT, 5);
wxButton *en_dis_button =
new wxButton( playlist_panel, En_Dis_Event, wxU(_("Enable/Disable Group") ) );
wxButton *iteminfo_button =
new wxButton( playlist_panel, Infos_Event, wxU(_("Item Infos") ) );
/* Place everything in sizers */
wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
button_sizer->Add( en_dis_button, 0, wxALIGN_CENTER|wxRIGHT, 5);
button_sizer->Add( iteminfo_button, 0, wxALIGN_CENTER|wxLEFT , 5);
button_sizer->Layout();
wxBoxSizer *search_sizer = new wxBoxSizer( wxVERTICAL );
wxBoxSizer *checkbox_sizer = new wxBoxSizer( wxHORIZONTAL );
checkbox_sizer->Add( random_checkbox, 0,
wxEXPAND|wxALIGN_RIGHT, 5);
checkbox_sizer->Add( loop_checkbox, 0,
wxEXPAND|wxALIGN_RIGHT, 5);
checkbox_sizer->Add( repeat_checkbox, 0,
wxEXPAND|wxALIGN_RIGHT, 5);
checkbox_sizer->Layout();
wxBoxSizer *search_sizer = new wxBoxSizer( wxHORIZONTAL );
search_sizer->Add( search_text, 0, wxALL|wxALIGN_CENTER, 5);
search_sizer->Add( search_button, 0, wxALL|wxALIGN_CENTER, 5);
search_sizer->Layout();
wxBoxSizer *bottom_sizer = new wxBoxSizer( wxHORIZONTAL );
bottom_sizer->Add( search_sizer , 0, wxALL|wxALIGN_CENTER, 5 );
wxBoxSizer *bottom_sizer = new wxBoxSizer( wxVERTICAL );
bottom_sizer->Add( checkbox_sizer, 0, wxALL|wxALIGN_CENTER, 5 );
bottom_sizer->Add( button_sizer , 0, wxALL|wxALIGN_CENTER, 5 );
bottom_sizer->Layout();
wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
panel_sizer->Add( listview, 1, wxEXPAND | wxALL, 5 );
panel_sizer->Add( search_sizer, 0, wxALIGN_CENTRE );
panel_sizer->Add( bottom_sizer, 0 , wxALIGN_CENTRE);
panel_sizer->Layout();
......@@ -270,6 +297,8 @@ Playlist::~Playlist()
return;
}
delete iteminfo_dialog;
var_DelCallback( p_playlist, "intf-change", PlaylistChanged, this );
vlc_object_release( p_playlist );
}
......@@ -293,11 +322,18 @@ void Playlist::Rebuild()
{
wxString filename = wxU(p_playlist->pp_items[i]->psz_name);
listview->InsertItem( i, filename );
if( p_playlist->pp_items[i]->b_enabled == VLC_FALSE )
{
wxListItem listitem;
listitem.m_itemId = i;
listitem.SetTextColour( *wxLIGHT_GREY);
listview->SetItem(listitem);
}
/* FIXME: we should try to find the actual duration... */
/* While we don't use it, hide it, it's ugly */
#if 0
listview->SetItem( i, 1, wxU(_("no info")) );
#endif
/* While we don't use it, hide it, it's ugly */
#if 0
listview->SetItem( i, 1, wxU(_("no info")) );
#endif
}
vlc_mutex_unlock( &p_playlist->object_lock );
......@@ -307,7 +343,6 @@ void Playlist::Rebuild()
listitem.SetTextColour( *wxRED );
listview->SetItem( listitem );
// listview->Select( p_playlist->i_index, TRUE );
listview->Focus( p_playlist->i_index );
vlc_object_release( p_playlist );
......@@ -465,7 +500,7 @@ void Playlist::OnSort( wxCommandEvent& WXUNUSED(event) )
}
playlist_Sort( p_playlist , 0 );
vlc_object_release( p_playlist );
Rebuild();
......@@ -484,7 +519,7 @@ void Playlist::OnRSort( wxCommandEvent& WXUNUSED(event) )
}
playlist_Sort( p_playlist , 1 );
vlc_object_release( p_playlist );
Rebuild();
......@@ -494,7 +529,7 @@ void Playlist::OnRSort( wxCommandEvent& WXUNUSED(event) )
void Playlist::OnSearchTextChange( wxCommandEvent& WXUNUSED(event) )
{
search_button->SetDefault();
search_button->SetDefault();
}
void Playlist::OnSearch( wxCommandEvent& WXUNUSED(event) )
......@@ -502,30 +537,30 @@ void Playlist::OnSearch( wxCommandEvent& WXUNUSED(event) )
wxString search_string= search_text->GetValue();
int i_current;
int i_first = 0 ;
int i_first = 0 ;
int i_item = -1;
for( i_current = 0 ; i_current <= listview->GetItemCount() ; i_current++ )
{
if( listview->GetItemState( i_current, wxLIST_STATE_SELECTED)
== wxLIST_STATE_SELECTED )
{
i_first = i_current;
break;
}
if( listview->GetItemState( i_current, wxLIST_STATE_SELECTED)
== wxLIST_STATE_SELECTED )
{
i_first = i_current;
break;
}
}
for ( i_current = i_first + 1; i_current <= listview->GetItemCount()
; i_current++ )
for ( i_current = i_first + 1; i_current <= listview->GetItemCount() ;
i_current++ )
{
wxListItem listitem;
listitem.SetId( i_current );
listview->GetItem( listitem );
if( listitem.m_text.Lower().Contains( search_string.Lower() ) )
{
i_item = i_current;
break;
}
wxListItem listitem;
listitem.SetId( i_current );
listview->GetItem( listitem );
if( listitem.m_text.Lower().Contains( search_string.Lower() ) )
{
i_item = i_current;
break;
}
}
for( long item = 0; item < listview->GetItemCount(); item++ )
{
......@@ -562,11 +597,52 @@ void Playlist::OnDeleteSelection( wxCommandEvent& WXUNUSED(event) )
Rebuild();
}
void Playlist::OnEnableSelection( wxCommandEvent& WXUNUSED(event) )
{
playlist_t *p_playlist =
(playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist == NULL )
{
return;
}
for( long item = listview->GetItemCount() - 1; item >= 0; item-- )
{
if( listview->IsSelected( item ) )
{
playlist_Enable( p_playlist, item );
}
}
vlc_object_release( p_playlist);
Rebuild();
}
void Playlist::OnDisableSelection( wxCommandEvent& WXUNUSED(event) )
{
playlist_t *p_playlist =
(playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist == NULL )
{
return;
}
for( long item = listview->GetItemCount() - 1; item >= 0; item-- )
{
if( listview->IsSelected( item ) )
{
playlist_Disable( p_playlist, item );
}
}
vlc_object_release( p_playlist);
Rebuild();
}
void Playlist::OnRandom( wxCommandEvent& event )
{
vlc_value_t val;
val.b_bool = event.IsChecked();
// ? VLC_TRUE : VLC_FALSE ;
playlist_t *p_playlist =
(playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
......@@ -581,7 +657,6 @@ void Playlist::OnLoop ( wxCommandEvent& event )
{
vlc_value_t val;
val.b_bool = event.IsChecked();
// ? VLC_TRUE : VLC_FALSE ;
playlist_t *p_playlist =
(playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
......@@ -597,7 +672,6 @@ void Playlist::OnRepeat ( wxCommandEvent& event )
{
vlc_value_t val;
val.b_bool = event.IsChecked();
// ? VLC_TRUE : VLC_FALSE ;
playlist_t *p_playlist =
(playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
......@@ -626,7 +700,6 @@ void Playlist::OnActivateItem( wxListEvent& event )
{
return;
}
playlist_Goto( p_playlist, event.GetIndex() );
vlc_object_release( p_playlist );
......@@ -642,6 +715,65 @@ void Playlist::OnKeyDown( wxListEvent& event )
}
}
void Playlist::OnInfos( wxCommandEvent& WXUNUSED(event) )
{
playlist_t *p_playlist =
(playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist == NULL )
{
return;
}
if( iteminfo_dialog == NULL )
{
/* We use the first selected item, so find it */
long i_item = -1;
i_item = listview->GetNextItem(i_item,
wxLIST_NEXT_ALL,
wxLIST_STATE_SELECTED);
if( i_item >= 0 && i_item < p_playlist->i_size )
{
iteminfo_dialog = new ItemInfoDialog(
p_intf, p_playlist->pp_items[i_item], this );
if( iteminfo_dialog->ShowModal() == wxID_OK )
Rebuild();
delete iteminfo_dialog;
iteminfo_dialog = NULL;
}
}
vlc_object_release( p_playlist );
}
void Playlist::OnEnDis( wxCommandEvent& WXUNUSED(event) )
{
playlist_t *p_playlist =
(playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist == NULL )
{
return;
}
long i_item = -1;
i_item = listview->GetNextItem(i_item,
wxLIST_NEXT_ALL,
wxLIST_STATE_SELECTED);
if( i_item >= 0 && i_item < p_playlist->i_size )
{
if( p_playlist->pp_items[i_item]->b_enabled == VLC_TRUE)
playlist_DisableGroup( p_playlist ,
p_playlist->pp_items[i_item]->i_group );
else
playlist_EnableGroup( p_playlist ,
p_playlist->pp_items[i_item]->i_group );
Rebuild();
}
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
......
......@@ -2,7 +2,7 @@
* wxwindows.h: private wxWindows interface description
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: wxwindows.h,v 1.62 2003/09/22 14:40:10 zorglub Exp $
* $Id: wxwindows.h,v 1.63 2003/10/06 16:23:30 zorglub Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
......@@ -141,19 +141,33 @@ public:
virtual ~Interface();
void TogglePlayButton( int i_playing_status );
// wxFlexGridSizer *frame_sizer;
wxBoxSizer *frame_sizer;
wxStatusBar *statusbar;
wxSlider *slider;
wxWindow *slider_frame;
wxWindow *extra_frame;
wxStaticBox *slider_box;
vlc_bool_t b_extra;
wxStaticBox *adjust_box;
wxSlider *brightness_slider;
wxSlider *contrast_slider;
wxSlider *saturation_slider;
wxSlider *hue_slider;
wxStaticBox *other_box;
wxComboBox *ratio_combo;
wxGauge *volctrl;
private:
void UpdateAcceleratorTable();
void CreateOurMenuBar();
void CreateOurToolBar();
void CreateOurExtraPanel();
void CreateOurSlider();
void Open( int i_access_method );
......@@ -167,6 +181,7 @@ private:
void OnOpenNet( wxCommandEvent& event );
void OnOpenSat( wxCommandEvent& event );
void OnOpenV4L( wxCommandEvent& event );
void OnExtra( wxCommandEvent& event );
void OnShowDialog( wxCommandEvent& event );
void OnPlayStream( wxCommandEvent& event );
void OnStopStream( wxCommandEvent& event );
......@@ -176,6 +191,14 @@ private:
void OnSlowStream( wxCommandEvent& event );
void OnFastStream( wxCommandEvent& event );
void OnEnableAdjust( wxCommandEvent& event );
void OnHueUpdate( wxScrollEvent& event );
void OnContrastUpdate( wxScrollEvent& event );
void OnBrightnessUpdate( wxScrollEvent& event );
void OnSaturationUpdate( wxScrollEvent& event );
void OnRatio( wxCommandEvent& event );
void OnMenuOpen( wxMenuEvent& event );
#if defined( __WXMSW__ ) || defined( __WXMAC__ )
......@@ -638,6 +661,7 @@ private:
};
/* Playlist */
class ItemInfoDialog;
class Playlist: public wxFrame
{
public:
......@@ -661,9 +685,13 @@ private:
void OnRSort( wxCommandEvent& event );
void OnClose( wxCommandEvent& event );
void OnSearch( wxCommandEvent& event );
void OnEnDis( wxCommandEvent& event );
void OnInfos( wxCommandEvent& event );
void OnSearchTextChange( wxCommandEvent& event );
void OnOpen( wxCommandEvent& event );
void OnSave( wxCommandEvent& event );
void OnEnableSelection( wxCommandEvent& event );
void OnDisableSelection( wxCommandEvent& event );
void OnInvertSelection( wxCommandEvent& event );
void OnDeleteSelection( wxCommandEvent& event );
void OnSelectAll( wxCommandEvent& event );
......@@ -675,14 +703,59 @@ private:
void Rebuild();
wxTextCtrl *search_text;
wxButton *search_button;
wxButton *search_button;
DECLARE_EVENT_TABLE();
ItemInfoDialog *iteminfo_dialog;
intf_thread_t *p_intf;
wxListView *listview;
int i_update_counter;
};
/* ItemInfo Dialog */
class ItemInfoDialog: public wxDialog
{
public:
/* Constructor */
ItemInfoDialog( intf_thread_t *p_intf, playlist_item_t *_p_item,
wxWindow *p_parent );
virtual ~ItemInfoDialog();
wxArrayString GetOptions();
private:
wxPanel *InfoPanel( wxWindow* parent );
wxPanel *GroupPanel( wxWindow* parent );
/* Event handlers (these functions should _not_ be virtual) */
void OnOk( wxCommandEvent& event );
void OnCancel( wxCommandEvent& event );
DECLARE_EVENT_TABLE();
intf_thread_t *p_intf;
playlist_item_t *p_item;
wxWindow *p_parent;
/* Controls for the iteminfo dialog box */
wxPanel *info_subpanel;
wxPanel *info_panel;
wxPanel *group_subpanel;
wxPanel *group_panel;
wxTextCtrl *uri_text;
wxTextCtrl *name_text;
wxTextCtrl *author_text;
wxCheckBox *enabled_checkbox;
wxSpinCtrl *group_spin;
};
/* File Info */
class FileInfo: public wxFrame
{
......
......@@ -2,12 +2,12 @@
* sap.c : SAP interface module
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: sap.c,v 1.23 2003/09/15 08:33:29 zorglub Exp $
* $Id: sap.c,v 1.24 2003/10/06 16:23:30 zorglub Exp $
*
* Authors: Arnaud Schauly <gitan@via.ecp.fr>
* Clment Stenac <zorglub@via.ecp.fr>
* Damien Lucas <nitrox@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
......@@ -160,12 +160,15 @@ struct attr_descr_t
#define SAP_IPV6_LONGTEXT N_("Set this if you want SAP to listen for IPv6 announces")
#define SAP_SCOPE_TEXT N_("IPv6 SAP scope")
#define SAP_SCOPE_LONGTEXT N_("Sets the scope for IPv6 announces (default is 8)")
#define SAP_GROUP_ID_TEXT N_("SAP Playlist group ID")
#define SAP_GROUP_ID_LONGTEXT N_("Sets the default group ID in which" \
"SAP items are put" )
vlc_module_begin();
add_category_hint( N_("SAP"), NULL, VLC_TRUE );
add_string( "sap-addr", NULL, NULL,
SAP_ADDR_TEXT, SAP_ADDR_LONGTEXT, VLC_TRUE );
add_bool( "no-sap-ipv4", 0 , NULL,
SAP_IPV4_TEXT,SAP_IPV4_LONGTEXT, VLC_TRUE);
......@@ -175,6 +178,9 @@ vlc_module_begin();
add_string( "sap-ipv6-scope", "8" , NULL,
SAP_SCOPE_TEXT, SAP_SCOPE_LONGTEXT, VLC_TRUE);
add_integer( "sap-group-id", 42, NULL,
SAP_GROUP_ID_TEXT, SAP_GROUP_ID_LONGTEXT, VLC_TRUE);
set_description( _("SAP interface") );
set_capability( "interface", 0 );
set_callbacks( Activate, NULL);
......@@ -412,8 +418,8 @@ static int sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
}
}
/* Filling p_item->psz_uri */
if( b_http == VLC_FALSE )
{
......@@ -421,7 +427,7 @@ static int sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
p_item->psz_uri = malloc( strlen( psz_proto ) + strlen( psz_uri ) +
strlen( psz_port ) + 5 +i_multicast );
if( p_item->psz_uri == NULL )
{
msg_Err( p_intf, "Not enough memory");
......@@ -442,27 +448,30 @@ static int sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
}
else
{
if( psz_http_path == NULL )
if( psz_http_path == NULL )
psz_http_path = strdup("/");
p_item->psz_uri = malloc( strlen( psz_proto ) + strlen( psz_uri ) +
strlen( psz_port ) + 3 + strlen(psz_http_path) );
if( p_item->psz_uri == NULL )
{
msg_Err( p_intf, "Not enough memory");
free( p_item );
return 0;
}
sprintf( p_item->psz_uri, "%s://%s:%s%s", psz_proto,
psz_uri, psz_port,psz_http_path );
}
/* Enqueueing p_item in the playlist */
if( p_item )
{
p_item->i_group = config_GetInt( p_intf, "sap-group-id" );
p_item->b_enabled = VLC_TRUE;
p_item->psz_author = NULL;
p_playlist = vlc_object_find( p_intf,
VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
......@@ -470,8 +479,8 @@ static int sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
PLAYLIST_CHECK_INSERT, PLAYLIST_END);
vlc_object_release( p_playlist );
}
if( psz_http_path )
if( psz_http_path )
free(psz_http_path);
}
......
......@@ -2,7 +2,7 @@
* effects.c : Effects for the visualization system
*****************************************************************************
* Copyright (C) 2002 VideoLAN
* $Id: effects.c,v 1.7 2003/09/20 00:37:53 fenrir Exp $
* $Id: effects.c,v 1.8 2003/10/06 16:23:30 zorglub Exp $
*
* Authors: Clment Stenac <zorglub@via.ecp.fr>
*
......@@ -61,13 +61,13 @@ int spectrum_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
int i_amp; /* Vertical amplification */
int i_peak; /* Should we draw peaks ? */
char *psz_parse = NULL; /* Args line */
/* Horizontal scale for 20-band equalizer */
const int xscale1[]={0,1,2,3,4,5,6,7,8,11,15,20,27,
36,47,62,82,107,141,184,255};
/* Horizontal scale for 80-band equalizer */
const int xscale2[] =
const int xscale2[] =
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,
19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,
35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
......@@ -75,9 +75,9 @@ int spectrum_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
110,115,121,130,141,152,163,174,185,200,255};
const int *xscale;
const double y_scale = 3.60673760222; /* (log 256) */
fft_state *p_state; /* internal FFT data */
int i , j , y , k;
int i_line;
s16 p_dest[FFT_BUFFER_SIZE]; /* Adapted FFT result */
......@@ -89,8 +89,8 @@ int spectrum_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
s16 *p_buffs; /* s16 converted buffer */
s16 *p_s16_buff = NULL; /* s16 converted buffer */
p_s16_buff = (s16*)malloc(
p_s16_buff = (s16*)malloc(
p_buffer->i_nb_samples * p_effect->i_nb_chans * sizeof(s16));
if( !p_s16_buff )
......@@ -98,7 +98,7 @@ int spectrum_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
msg_Err(p_aout,"Out of memory");
return -1;
}
p_buffs = p_s16_buff;
i_nb_bands = config_GetInt ( p_aout, "visual-nbbands" );
i_separ = config_GetInt( p_aout, "visual-separ" );
......@@ -114,7 +114,7 @@ int spectrum_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
i_nb_bands = 80;
xscale = xscale2;
}
if( !p_effect->p_data )
{
p_effect->p_data=(void *)malloc(i_nb_bands * sizeof(int) );
......@@ -128,14 +128,14 @@ int spectrum_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
{
peaks[i] = 0;
}
}
else
{
peaks =(int *)p_effect->p_data;
}
height = (int *)malloc( i_nb_bands * sizeof(int) );
if( !height)
{
......@@ -152,7 +152,7 @@ int spectrum_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
if(i_in > 0x43c07fff ) * p_buffs = 32767;
else if ( i_in < 0x43bf8000 ) *p_buffs = -32768;
else *p_buffs = i_in - 0x43c00000;
p_buffl++ ; p_buffs++ ;
}
p_state = fft_init();
......@@ -167,11 +167,11 @@ int spectrum_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
p_output[i] = 0;
p_buffer1[i] = *p_buffs;
p_buffs = p_buffs + p_effect->i_nb_chans;
}
}
fft_perform( p_buffer1, p_output, p_state);
for(i= 0; i< FFT_BUFFER_SIZE ; i++ )
p_dest[i] = ( (int) sqrt( p_output [ i + 1 ] ) ) >> 8;
for ( i = 0 ; i< i_nb_bands ;i++)
{
/* We search the maximum on one scale */
......@@ -192,7 +192,7 @@ int spectrum_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
{
height[i] = 0 ;
}
/* Draw the bar now */
i_band_width = floor( p_effect->i_width / i_nb_bands) ;
......@@ -215,39 +215,39 @@ int spectrum_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
if( peaks[i] > 0 && i_peak )
{
if( peaks[i] >= p_effect->i_height )
if( peaks[i] >= p_effect->i_height )
peaks[i] = p_effect->i_height - 2;
i_line = peaks[i];
for( j = 0 ; j< i_band_width - i_separ; j++)
{
for( k = 0 ; k< 3 ; k ++)
{
/* Draw the peak */
*(p_picture->p[0].p_pixels +
(p_picture->p[0].i_lines - i_line -1 -k ) *
p_picture->p[0].i_pitch + (i_band_width*i +j) )
*(p_picture->p[0].p_pixels +
(p_picture->p[0].i_lines - i_line -1 -k ) *
p_picture->p[0].i_pitch + (i_band_width*i +j) )
= 0xff;
*(p_picture->p[1].p_pixels +
(p_picture->p[1].i_lines - i_line /2 -1 -k/2 ) *
p_picture->p[1].i_pitch +
p_picture->p[1].i_pitch +
( ( i_band_width * i + j ) /2 ) )
= 0x00;
if( 0x04 * (i_line + k ) - 0x0f > 0 )
{
if ( 0x04 * (i_line + k ) -0x0f < 0xff)
*(p_picture->p[2].p_pixels +
(p_picture->p[2].i_lines - i_line /2 - 1 -k/2 ) *
p_picture->p[2].i_pitch +
( ( i_band_width * i + j ) /2 ) )
p_picture->p[2].i_pitch +
( ( i_band_width * i + j ) /2 ) )
= ( 0x04 * ( i_line + k ) ) -0x0f ;
else
*(p_picture->p[2].p_pixels +
(p_picture->p[2].i_lines - i_line /2 - 1 -k/2 ) *
p_picture->p[2].i_pitch +
( ( i_band_width * i + j ) /2 ) )
p_picture->p[2].i_pitch +
( ( i_band_width * i + j ) /2 ) )
= 0xff;
}
else
......@@ -269,13 +269,13 @@ int spectrum_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
{
for( j = 0 ; j< i_band_width - i_separ ; j++)
{
*(p_picture->p[0].p_pixels +
(p_picture->p[0].i_lines - i_line -1) *
*(p_picture->p[0].p_pixels +
(p_picture->p[0].i_lines - i_line -1) *
p_picture->p[0].i_pitch + (i_band_width*i +j) ) = 0xff;
*(p_picture->p[1].p_pixels +
(p_picture->p[1].i_lines - i_line /2 -1) *
p_picture->p[1].i_pitch +
p_picture->p[1].i_pitch +
( ( i_band_width * i + j ) /2 ) ) = 0x00;
......@@ -321,7 +321,7 @@ int spectrum_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
return 0;
}
/*****************************************************************************
* scope_Run: scope effect
*****************************************************************************/
......@@ -331,8 +331,8 @@ int scope_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
int i_index;
float *p_sample ;
u8 *ppp_area[2][3];
for( i_index = 0 ; i_index < 2 ; i_index++ )
{
int j;
......@@ -351,7 +351,7 @@ int scope_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
u8 i_value;
/* Left channel */
i_value = (*p_sample++ +1) * 127;
i_value = (*p_sample++ +1) * 127;
*(ppp_area[0][0]
+ p_picture->p[0].i_pitch * i_index / p_effect->i_width
+ p_picture->p[0].i_lines * i_value / 512
......@@ -361,7 +361,7 @@ int scope_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
+ p_picture->p[1].i_lines * i_value / 512
* p_picture->p[1].i_pitch) = 0xff;
/* Right channel */
i_value = ( *p_sample++ +1 ) * 127;
*(ppp_area[1][0]
......
......@@ -2,7 +2,7 @@
* playlist.c : Playlist management functions
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: playlist.c,v 1.56 2003/09/24 10:21:32 zorglub Exp $
* $Id: playlist.c,v 1.57 2003/10/06 16:23:30 zorglub Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
......@@ -34,6 +34,7 @@
#include "vlc_playlist.h"
#define PLAYLIST_FILE_HEADER_0_5 "# vlc playlist file version 0.5"
#define PLAYLIST_FILE_HEADER_0_6 "# vlc playlist file version 0.6"
/*****************************************************************************
* Local prototypes
......@@ -158,12 +159,15 @@ int playlist_AddExt( playlist_t *p_playlist, const char * psz_uri,
msg_Err( p_playlist, "out of memory" );
}
p_item->psz_name = strdup( psz_name );
p_item->psz_uri = strdup( psz_uri );
p_item->psz_name = strdup( psz_name );
p_item->psz_uri = strdup( psz_uri );
p_item->psz_author = strdup( "" );
p_item->i_duration = i_duration;
p_item->i_type = 0;
p_item->i_status = 0;
p_item->b_autodeletion = VLC_FALSE;
p_item->b_enabled = VLC_TRUE;
p_item->i_group = PLAYLIST_TYPE_MANUAL;
p_item->ppsz_options = NULL;
p_item->i_options = i_options;
......@@ -271,6 +275,7 @@ int playlist_AddItem( playlist_t *p_playlist, playlist_item_t * p_item,
p_playlist->i_size,
i_pos,
p_item );
p_playlist->i_enabled ++;
if( p_playlist->i_index >= i_pos )
{
......@@ -358,6 +363,8 @@ int playlist_Delete( playlist_t * p_playlist, int i_pos )
REMOVE_ELEM( p_playlist->pp_items,
p_playlist->i_size,
i_pos );
if( p_playlist->i_enabled > 0 )
p_playlist->i_enabled--;
}
vlc_mutex_unlock( &p_playlist->object_lock );
......@@ -368,6 +375,136 @@ int playlist_Delete( playlist_t * p_playlist, int i_pos )
return 0;
}
/**
* Disables a playlist item
*
* \param p_playlist the playlist to disable from.
* \param i_pos the position of the item to disable
* \return returns 0
*/
int playlist_Disable( playlist_t * p_playlist, int i_pos )
{
vlc_value_t val;
vlc_mutex_lock( &p_playlist->object_lock );
if( i_pos >= 0 && i_pos < p_playlist->i_size )
{
msg_Dbg( p_playlist, "disabling playlist item %s ",
p_playlist->pp_items[i_pos]->psz_name );
if( p_playlist->pp_items[i_pos]->b_enabled == VLC_TRUE )
p_playlist->i_enabled--;
p_playlist->pp_items[i_pos]->b_enabled = VLC_FALSE;
}
vlc_mutex_unlock( &p_playlist->object_lock );
val.b_bool = VLC_TRUE;
var_Set( p_playlist, "intf-change", val );
return 0;
}
/**
* Enables a playlist item
*
* \param p_playlist the playlist to enable from.
* \param i_pos the position of the item to enable
* \return returns 0
*/
int playlist_Enable( playlist_t * p_playlist, int i_pos )
{
vlc_value_t val;
vlc_mutex_lock( &p_playlist->object_lock );
if( i_pos >= 0 && i_pos < p_playlist->i_size )
{
msg_Dbg( p_playlist, "enabling playlist item %s ",
p_playlist->pp_items[i_pos]->psz_name );
if( p_playlist->pp_items[i_pos]->b_enabled == VLC_FALSE )
p_playlist->i_enabled++;
p_playlist->pp_items[i_pos]->b_enabled = VLC_TRUE;
}
vlc_mutex_unlock( &p_playlist->object_lock );
val.b_bool = VLC_TRUE;
var_Set( p_playlist, "intf-change", val );
return 0;
}
/**
* Disables a playlist group
*
* \param p_playlist the playlist to disable from.
* \param i_pos the id of the group to disable
* \return returns 0
*/
int playlist_DisableGroup( playlist_t * p_playlist, int i_group)
{
vlc_value_t val;
vlc_mutex_lock( &p_playlist->object_lock );
int i;
msg_Dbg(p_playlist,"Disabling group %i",i_group);
for( i = 0 ; i< p_playlist->i_size; i++ )
{
if( p_playlist->pp_items[i]->i_group == i_group )
{
msg_Dbg( p_playlist, "disabling playlist item %s ",
p_playlist->pp_items[i]->psz_name );
if( p_playlist->pp_items[i]->b_enabled == VLC_TRUE )
p_playlist->i_enabled--;
p_playlist->pp_items[i]->b_enabled = VLC_FALSE;
}
}
vlc_mutex_unlock( &p_playlist->object_lock );
val.b_bool = VLC_TRUE;
var_Set( p_playlist, "intf-change", val );
return 0;
}
/**
* Enables a playlist group
*
* \param p_playlist the playlist to enable from.
* \param i_pos the id of the group to enable
* \return returns 0
*/
int playlist_EnableGroup( playlist_t * p_playlist, int i_group)
{
vlc_value_t val;
vlc_mutex_lock( &p_playlist->object_lock );
int i;
for( i = 0 ; i< p_playlist->i_size; i++ )
{
if( p_playlist->pp_items[i]->i_group == i_group )
{
msg_Dbg( p_playlist, "enabling playlist item %s ",
p_playlist->pp_items[i]->psz_name );
if( p_playlist->pp_items[i]->b_enabled == VLC_FALSE )
p_playlist->i_enabled++;
p_playlist->pp_items[i]->b_enabled = VLC_TRUE;
}
}
vlc_mutex_unlock( &p_playlist->object_lock );
val.b_bool = VLC_TRUE;
var_Set( p_playlist, "intf-change", val );
return 0;
}
/**
* Sort the playlist
......@@ -396,6 +533,12 @@ int playlist_Sort( playlist_t * p_playlist , int i_type )
i_small = i;
}
}
/* Keep the correct current index */
if( i_small == p_playlist->i_index )
p_playlist->i_index = i_position;
else if( i_position == p_playlist->i_index )
p_playlist->i_index = i_small;
p_temp = p_playlist->pp_items[i_position];
p_playlist->pp_items[i_position] = p_playlist->pp_items[i_small];
p_playlist->pp_items[i_small] = p_temp;
......@@ -424,7 +567,7 @@ int playlist_Move( playlist_t * p_playlist, int i_pos, int i_newpos)
/* take into account that our own row disappears. */
if ( i_pos < i_newpos ) i_newpos--;
if( i_pos >= 0 && i_newpos >=0 && i_pos <= p_playlist->i_size
if( i_pos >= 0 && i_newpos >=0 && i_pos <= p_playlist->i_size
&& i_newpos <= p_playlist->i_size )
{
playlist_item_t * temp;
......@@ -501,7 +644,7 @@ int playlist_Move( playlist_t * p_playlist, int i_pos, int i_newpos)
case PLAYLIST_PLAY:
p_playlist->i_status = PLAYLIST_RUNNING;
if( !p_playlist->p_input )
if( !p_playlist->p_input && p_playlist->i_enabled != 0 )
{
PlayItem( p_playlist );
}
......@@ -523,6 +666,10 @@ int playlist_Move( playlist_t * p_playlist, int i_pos, int i_newpos)
case PLAYLIST_SKIP:
p_playlist->i_status = PLAYLIST_STOPPED;
if( p_playlist->i_enabled == 0)
{
break;
}
SkipItem( p_playlist, i_arg );
if( p_playlist->p_input )
{
......@@ -532,7 +679,8 @@ int playlist_Move( playlist_t * p_playlist, int i_pos, int i_newpos)
break;
case PLAYLIST_GOTO:
if( i_arg >= 0 && i_arg < p_playlist->i_size )
if( i_arg >= 0 && i_arg < p_playlist->i_size &&
p_playlist->i_enabled != 0 )
{
p_playlist->i_index = i_arg;
if( p_playlist->p_input )
......@@ -784,6 +932,7 @@ static void SkipItem( playlist_t *p_playlist, int i_arg )
vlc_bool_t b_random, b_repeat, b_loop;
vlc_value_t val;
msg_Dbg(p_playlist,"%i",p_playlist->i_enabled);
/* If the playlist is empty, there is no current item */
if( p_playlist->i_size == 0 )
{
......@@ -839,6 +988,12 @@ static void SkipItem( playlist_t *p_playlist, int i_arg )
p_playlist->i_index = p_playlist->i_size - 1;
}
/* Check that the item is enabled */
if( p_playlist->pp_items[p_playlist->i_index]->b_enabled == VLC_FALSE &&
p_playlist->i_enabled != 0)
{
SkipItem( p_playlist , 1 );
}
val.b_bool = VLC_TRUE;
var_Set( p_playlist, "intf-change", val );
}
......@@ -853,7 +1008,7 @@ static void PlayItem( playlist_t *p_playlist )
{
if( p_playlist->i_index == -1 )
{
if( p_playlist->i_size == 0 )
if( p_playlist->i_size == 0 || p_playlist->i_enabled == 0)
{
return;
}
......@@ -861,6 +1016,11 @@ static void PlayItem( playlist_t *p_playlist )
SkipItem( p_playlist, 1 );
}
if( p_playlist->i_enabled == 0)
{
return;
}
msg_Dbg( p_playlist, "creating new input thread" );
p_playlist->p_input = input_CreateThread( p_playlist,
p_playlist->pp_items[p_playlist->i_index] );
......@@ -884,6 +1044,7 @@ int playlist_LoadFile( playlist_t * p_playlist, const char *psz_filename )
FILE *file;
char line[1024];
int i_current_status;
int i_format;
int i;
msg_Dbg( p_playlist, "opening playlist file %s", psz_filename );
......@@ -911,7 +1072,15 @@ int playlist_LoadFile( playlist_t * p_playlist, const char *psz_filename )
if( line[strlen(line)-1] == '\r' ) line[strlen(line)-1] = (char)0;
}
/* check the file format is valid */
if ( strcmp ( line , PLAYLIST_FILE_HEADER_0_5 ) )
if ( !strcmp ( line , PLAYLIST_FILE_HEADER_0_5 ) )
{
i_format = 5;
}
else if( !strcmp ( line , PLAYLIST_FILE_HEADER_0_6 ) )
{
i_format = 6;
}
else
{
msg_Err( p_playlist, "playlist file %s format is unsupported"
, psz_filename );
......@@ -946,9 +1115,15 @@ int playlist_LoadFile( playlist_t * p_playlist, const char *psz_filename )
line[strlen(line)-1] = (char)0;
if( line[strlen(line)-1] == '\r' ) line[strlen(line)-1] = (char)0;
}
playlist_Add ( p_playlist , (char *)&line ,
if( i_format == 5 )
{
playlist_Add ( p_playlist , (char *)&line ,
0, 0, PLAYLIST_APPEND , PLAYLIST_END );
}
else
{
msg_Warn( p_playlist, "Not supported yet");
}
}
/* start playing */
......@@ -981,6 +1156,7 @@ int playlist_SaveFile( playlist_t * p_playlist, const char * psz_filename )
, psz_filename );
return -1;
}
/* Save is done in 0_5 mode at the moment*/
fprintf( file , PLAYLIST_FILE_HEADER_0_5 "\n" );
......@@ -989,7 +1165,24 @@ int playlist_SaveFile( playlist_t * p_playlist, const char * psz_filename )
fprintf( file , p_playlist->pp_items[i]->psz_uri );
fprintf( file , "\n" );
}
#if 0
fprintf( file, PLAYLIST_FILE_HEADER_0_6 "\n" );
for ( i=0 ; i< p_playlist->i_size ; i++ )
{
fprintf( file, p_playlist->pp_items[i]->psz_uri );
fprintf( file, "||" );
fprintf( file, p_playlist->pp_items[i]->psz_name );
fprintf( file, "||" );
fprintf( file, "%i",p_playlist->pp_items[i]->b_enabled = VLC_TRUE ?
1:0 );
fprintf( file, "||" );
fprintf( file, "%i", p_playlist->pp_items[i]->i_group );
fprintf( file, "||" );
fprintf( file, p_playlist->pp_items[i]->psz_author );
fprintf( file , "\n" );
}
#endif
fclose( file );
vlc_mutex_unlock( &p_playlist->object_lock );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment