summaryrefslogtreecommitdiff
path: root/source/ui_demos.c
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2007-08-14 20:18:08 +0000
committerAndrey Nazarov <skuller@skuller.net>2007-08-14 20:18:08 +0000
commitf294db4ccf45f6274e65260dd6f9a2c5faa94313 (patch)
treee8cf1ba2bfe9c8417eec17faf912442f52fc4ef2 /source/ui_demos.c
Initial import of the new Q2PRO tree.
Diffstat (limited to 'source/ui_demos.c')
-rw-r--r--source/ui_demos.c431
1 files changed, 431 insertions, 0 deletions
diff --git a/source/ui_demos.c b/source/ui_demos.c
new file mode 100644
index 0000000..c2519fa
--- /dev/null
+++ b/source/ui_demos.c
@@ -0,0 +1,431 @@
+/*
+Copyright (C) 2003-2006 Andrey Nazarov
+
+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-1307, USA.
+
+*/
+
+#include "ui_local.h"
+
+/*
+=======================================================================
+
+DEMOS MENU
+
+=======================================================================
+*/
+
+#define MAX_MENU_DEMOS 1024
+
+#define DEMO_EXTENSIONS \
+ ".dm2;.dm2.gz;" \
+ ".dm_35;.dm_35.gz;" \
+ ".dm_36;.dm_36.gz;" \
+ ".mvd2;.mvd2.gz"
+
+#define FFILE_UP 1
+#define FFILE_FOLDER 2
+#define FFILE_DEMO 3
+
+#define ID_LIST 105
+
+typedef struct m_demos_s {
+ menuFrameWork_t menu;
+ menuList_t list;
+ menuList_t playerList;
+ menuStatic_t banner;
+
+ int count;
+ char *names[MAX_MENU_DEMOS+1];
+ int types[MAX_MENU_DEMOS];
+ char *playerNames[MAX_DEMOINFO_CLIENTS+1];
+
+ // Demo file info
+ demoInfo_t demo;
+} m_demos_t;
+
+static m_demos_t m_demos;
+static char m_demos_browse[MAX_QPATH];
+static int m_demos_selection;
+
+static void Demos_FreeInfo( void ) {
+ memset( &m_demos.demo, 0, sizeof( m_demos.demo ) );
+
+ m_demos.playerList.generic.flags |= QMF_HIDDEN;
+}
+
+static void Demos_LoadInfo( int index ) {
+ char buffer[MAX_QPATH];
+ int i, numNames, localPlayerNum;
+
+ if( m_demos.types[index] != FFILE_DEMO ) {
+ m_demos.playerList.generic.flags |= QMF_HIDDEN;
+ m_demos.menu.statusbar = NULL;
+ return;
+ }
+
+ Com_sprintf( buffer, sizeof( buffer ), "%s/%s",
+ m_demos_browse + 1, m_demos.names[index] );
+
+ client.GetDemoInfo( buffer, &m_demos.demo );
+
+ if( !m_demos.demo.mapname[0] ) {
+ m_demos.menu.statusbar = "Couldn't read demo info";
+ m_demos.playerList.generic.flags |= QMF_HIDDEN;
+ return;
+ }
+
+
+ localPlayerNum = 0;
+
+ numNames = 0;
+ for( i = 0; i < MAX_DEMOINFO_CLIENTS; i++ ) {
+ if( !m_demos.demo.clients[i][0] ) {
+ continue;
+ }
+
+ if( i == m_demos.demo.clientNum ) {
+ localPlayerNum = numNames;
+ }
+
+ // ( m_demos.demo.mvd || i == m_demos.demo.clientNum ) ? colorYellow : NULL
+
+ m_demos.playerNames[numNames++] = m_demos.demo.clients[i];
+ }
+
+ if( numNames ) {
+ m_demos.playerList.generic.flags &= ~QMF_HIDDEN;
+ } else {
+ m_demos.playerList.generic.flags |= QMF_HIDDEN;
+ }
+
+ m_demos.playerNames[numNames] = NULL;
+
+ if( m_demos.demo.mvd ) {
+ m_demos.menu.statusbar = "Press Enter to play";
+ } else {
+ m_demos.menu.statusbar = "Press Enter to play, "
+ "hold Shift to play on server";
+ }
+
+ MenuList_Init( &m_demos.playerList );
+ MenuList_SetValue( &m_demos.playerList, localPlayerNum );
+}
+
+static char *Demos_BuildName( const char *path, const char *name,
+ fsFileInfo_t *info )
+{
+ char buffer[MAX_QPATH];
+ demoInfo_t demo;
+ char *s;
+
+ Com_sprintf( buffer, sizeof( buffer ), "%s/%s", path, name );
+
+ client.GetDemoInfo( buffer, &demo );
+ if( !demo.mapname[0] ) {
+ return NULL;
+ }
+
+ Com_sprintf( buffer, sizeof( buffer ), "%4d", info->fileSize >> 10 );
+
+ if( demo.clientNum >= 0 && demo.clientNum < MAX_DEMOINFO_CLIENTS ) {
+ s = UI_FormatColumns( 4, name, buffer, demo.mapname,
+ demo.clients[demo.clientNum] );
+ } else {
+ s = UI_FormatColumns( 3, name, buffer, demo.mapname );
+ }
+
+ return s;
+}
+
+static void Demos_BuildList( const char *path ) {
+ fsFileInfo_t *info;
+ int numFiles;
+ char **list, *s;
+ int pos;
+ int i;
+
+ if( *path == '/' ) {
+ path++;
+ }
+
+ if( *path ) {
+ m_demos.names[m_demos.count] = UI_FormatColumns( 1, ".." );
+ m_demos.types[m_demos.count] = FFILE_UP;
+ m_demos.count++;
+ }
+
+ // list directories first
+ list = fs.ListFiles( path, NULL, FS_PATH_GAME |
+ FS_SEARCHDIRS_ONLY, &numFiles );
+ if( list ) {
+ if( m_demos.count + numFiles > MAX_MENU_DEMOS ) {
+ numFiles = MAX_MENU_DEMOS - m_demos.count;
+ }
+ for( i = 0; i < numFiles; i++ ) {
+ m_demos.names[m_demos.count] = UI_FormatColumns( 1, list[i] );
+ m_demos.types[m_demos.count] = FFILE_FOLDER;
+ m_demos.count++;
+ }
+
+ fs.FreeFileList( list );
+ }
+
+ pos = m_demos.count;
+
+ // list demos
+ list = fs.ListFiles( path, DEMO_EXTENSIONS, FS_PATH_GAME |
+ FS_SEARCH_EXTRAINFO, &numFiles );
+ if( list ) {
+ if( m_demos.count + numFiles > MAX_MENU_DEMOS ) {
+ numFiles = MAX_MENU_DEMOS - m_demos.count;
+ }
+ for( i = 0; i < numFiles; i++ ) {
+ info = ( fsFileInfo_t * )( list[i] + strlen( list[i] ) + 1 );
+ s = Demos_BuildName( path, list[i], info );
+ if( s ) {
+ m_demos.names[m_demos.count] = s;
+ m_demos.types[m_demos.count] = FFILE_DEMO;
+ m_demos.count++;
+ }
+ }
+
+ // sort them
+ qsort( m_demos.names + pos, m_demos.count - pos,
+ sizeof( m_demos.names[0] ), SortStrcmp );
+
+ fs.FreeFileList( list );
+ }
+
+ // terminate the list
+ m_demos.names[m_demos.count] = NULL;
+}
+
+static void Demos_Free( void ) {
+ int i;
+
+ Demos_FreeInfo();
+
+ for( i = 0; i < m_demos.count; i++ ) {
+ com.Free( m_demos.names[i] );
+ m_demos.names[i] = NULL;
+ m_demos.types[i] = 0;
+ }
+
+ m_demos.count = 0;
+ m_demos.list.curvalue = 0;
+}
+
+static void Demos_LeaveDirectory( void ) {
+ char buffer[MAX_QPATH];
+ char *s;
+ int i;
+
+ s = strrchr( m_demos_browse, '/' );
+ if( s ) {
+ *s = 0;
+ strcpy( buffer, s + 1 );
+ } else {
+ buffer[0] = 0;
+ }
+
+ // rebuild list
+ Demos_Free();
+ Demos_BuildList( m_demos_browse );
+ MenuList_Init( &m_demos.list );
+
+ if( s == m_demos_browse ) {
+ m_demos_browse[0] = '/';
+ m_demos_browse[1] = 0;
+ }
+
+ // move cursor to the previous directory
+ if( buffer[0] ) {
+ for( i = 0; i < m_demos.count; i++ ) {
+ if( !strcmp( m_demos.names[i], buffer ) ) {
+ MenuList_SetValue( &m_demos.list, i );
+ return;
+ }
+ }
+ }
+
+ MenuList_SetValue( &m_demos.list, 0 );
+
+}
+
+static int Demos_Action( void ) {
+ char buffer[MAX_QPATH];
+ int length, baseLength;
+ char *c;
+
+ switch( m_demos.types[m_demos.list.curvalue] ) {
+ case FFILE_UP:
+ Demos_LeaveDirectory();
+ return QMS_OUT;
+
+ case FFILE_FOLDER:
+ baseLength = strlen( m_demos_browse );
+ length = strlen( m_demos.names[m_demos.list.curvalue] );
+ if( baseLength + length > sizeof( m_demos_browse ) - 2 ) {
+ return QMS_BEEP;
+ }
+ if( m_demos_browse[ baseLength - 1 ] != '/' ) {
+ m_demos_browse[ baseLength++ ] = '/';
+ }
+
+ strcpy( m_demos_browse + baseLength,
+ m_demos.names[m_demos.list.curvalue] );
+
+ // rebuild list
+ Demos_Free();
+ Demos_BuildList( m_demos_browse );
+ MenuList_Init( &m_demos.list );
+ return QMS_IN;
+
+ case FFILE_DEMO:
+ if( !m_demos.demo.mapname[0] ) {
+ return QMS_BEEP;
+ }
+ c = m_demos.demo.mvd || keys.IsDown( K_SHIFT ) ? "mvdplay" : "demo";
+ Com_sprintf( buffer, sizeof( buffer ), "%s \"%s/%s\"\n", c,
+ m_demos_browse, m_demos.names[m_demos.list.curvalue] );
+ cmd.ExecuteText( EXEC_APPEND, buffer );
+ //UI_ForceMenuOff();
+ return QMS_SILENT;
+ }
+
+ return QMS_NOTHANDLED;
+}
+
+static int Demos_MenuCallback( int id, int msg, int param ) {
+ switch( msg ) {
+ case QM_ACTIVATE:
+ switch( id ) {
+ case ID_LIST:
+ return Demos_Action();
+ }
+ return QMS_IN;
+
+ case QM_CHANGE:
+ switch( id ) {
+ case ID_LIST:
+ Demos_LoadInfo( m_demos.list.curvalue );
+ break;
+ default:
+ break;
+ }
+ return QMS_MOVE;
+
+ case QM_KEY:
+ switch( id ) {
+ case ID_LIST:
+ switch( param ) {
+ case K_BACKSPACE:
+ Demos_LeaveDirectory();
+ return QMS_OUT;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+
+ case QM_DESTROY:
+ m_demos_selection = m_demos.list.curvalue; // save previous position
+ Demos_Free();
+ break;
+
+ default:
+ break;
+ }
+
+ return QMS_NOTHANDLED;
+}
+
+static void Demos_MenuInit( void ) {
+ int w1, w2;
+
+ memset( &m_demos, 0, sizeof( m_demos ) );
+
+ m_demos.menu.callback = Demos_MenuCallback;
+
+ // Point to a nice location at startup
+ if( !m_demos_browse[0] ) {
+ strcpy( m_demos_browse, "/demos" );
+ }
+
+ Demos_BuildList( m_demos_browse );
+
+ w1 = ( uis.glconfig.vidWidth - 30 ) * 0.8f;
+ w2 = ( uis.glconfig.vidWidth - 30 ) * 0.2f;
+
+ m_demos.list.generic.type = MTYPE_LIST;
+ m_demos.list.generic.id = ID_LIST;
+ m_demos.list.generic.flags = QMF_HASFOCUS;
+ m_demos.list.generic.x = 10;
+ m_demos.list.generic.y = 32;
+ m_demos.list.generic.width = 0;
+ m_demos.list.generic.height = uis.glconfig.vidHeight - 64;
+ m_demos.list.generic.name = NULL;
+ m_demos.list.itemnames = ( const char ** )m_demos.names;
+ m_demos.list.drawNames = qtrue;
+ m_demos.list.numcolumns = 4;
+
+ m_demos.list.columns[0].width = w1 - 180;
+ m_demos.list.columns[0].name = m_demos_browse;
+ m_demos.list.columns[0].uiFlags = UI_LEFT;
+
+ m_demos.list.columns[1].width = 40;
+ m_demos.list.columns[1].name = "KiB";
+ m_demos.list.columns[1].uiFlags = UI_CENTER;
+
+ m_demos.list.columns[2].width = 60;
+ m_demos.list.columns[2].name = "Map";
+ m_demos.list.columns[2].uiFlags = UI_CENTER;
+
+ m_demos.list.columns[3].width = 80;
+ m_demos.list.columns[3].name = "POV";
+ m_demos.list.columns[3].uiFlags = UI_CENTER;
+
+ m_demos.playerList.generic.type = MTYPE_LIST;
+ m_demos.playerList.generic.flags = QMF_HIDDEN|QMF_DISABLED;
+ m_demos.playerList.generic.x = w1 + 20;
+ m_demos.playerList.generic.y = 32;
+ m_demos.playerList.generic.height = uis.glconfig.vidHeight - 64;
+ m_demos.playerList.itemnames = ( const char ** )m_demos.playerNames;
+ m_demos.playerList.mlFlags = MLF_HIDE_SCROLLBAR_EMPTY;
+ m_demos.playerList.numcolumns = 1;
+ m_demos.playerList.drawNames = qtrue;
+
+ m_demos.playerList.columns[0].width = w2;
+ m_demos.playerList.columns[0].name = "Players";
+ m_demos.playerList.columns[0].uiFlags = UI_CENTER;
+
+ UI_SetupDefaultBanner( &m_demos.banner, "Demos" );
+
+ Menu_AddItem( &m_demos.menu, (void *)&m_demos.list );
+ Menu_AddItem( &m_demos.menu, (void *)&m_demos.playerList );
+ Menu_AddItem( &m_demos.menu, (void *)&m_demos.banner );
+
+ // move cursor to previous position
+ MenuList_SetValue( &m_demos.list, m_demos_selection );
+}
+
+void M_Menu_Demos_f( void ) {
+ Demos_MenuInit();
+ UI_PushMenu( &m_demos.menu );
+}