toward snapshots in gtk version

Add new "snap" blob to db and pixbuf column to games display table, and
add code to store and retrieve from db. What's stored now is a
hard-coded file, so next up is generating an actual snapshot from the
game.
This commit is contained in:
Eric House 2016-08-05 08:29:25 -07:00
parent b4393d5965
commit aeee2d801a
4 changed files with 84 additions and 14 deletions

View file

@ -42,6 +42,7 @@ openGamesDB( const char* dbName )
"CREATE TABLE games ( "
"rowid INTEGER PRIMARY KEY AUTOINCREMENT"
",game BLOB"
",snap BLOB"
",inviteInfo BLOB"
",room VARCHAR(32)"
",connvia VARCHAR(32)"
@ -73,12 +74,11 @@ closeGamesDB( sqlite3* pDb )
}
static sqlite3_int64
writeBlobColumn( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 curRow,
const char* column )
writeBlobColumnData( const XP_U8* data, gsize len, XP_U16 strVersion, sqlite3* pDb,
sqlite3_int64 curRow, const char* column )
{
XP_LOGF( "%s(col=%s)", __func__, column );
int result;
/* size includes stream version as header */
XP_U16 len = stream_getSize( stream );
char buf[256];
char* query;
@ -114,12 +114,10 @@ writeBlobColumn( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 curRow,
result = sqlite3_blob_open( pDb, "main", "games", column,
curRow, 1 /*flags: writeable*/, &blob );
assertPrintResult( pDb, result, SQLITE_OK );
XP_U16 strVersion = stream_getVersion( stream );
XP_ASSERT( strVersion <= CUR_STREAM_VERS );
result = sqlite3_blob_write( blob, &strVersion, sizeof(strVersion), 0 );
result = sqlite3_blob_write( blob, &strVersion, sizeof(strVersion), 0/*offset*/ );
assertPrintResult( pDb, result, SQLITE_OK );
const XP_U8* ptr = stream_getPtr( stream );
result = sqlite3_blob_write( blob, ptr, len, sizeof(strVersion) );
result = sqlite3_blob_write( blob, data, len, sizeof(strVersion) /* offset */ );
assertPrintResult( pDb, result, SQLITE_OK );
result = sqlite3_blob_close( blob );
assertPrintResult( pDb, result, SQLITE_OK );
@ -127,13 +125,24 @@ writeBlobColumn( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 curRow,
sqlite3_finalize( stmt );
}
LOG_RETURNF( "%lld", curRow );
return curRow;
}
static sqlite3_int64
writeBlobColumnStream( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 curRow,
const char* column )
{
XP_U16 strVersion = stream_getVersion( stream );
const XP_U8* data = stream_getPtr( stream );
gsize len = stream_getSize( stream );
return writeBlobColumnData( data, len, strVersion, pDb, curRow, column );
}
sqlite3_int64
writeNewGameToDB( XWStreamCtxt* stream, sqlite3* pDb )
{
sqlite3_int64 newRow = writeBlobColumn( stream, pDb, -1, "game" );
sqlite3_int64 newRow = writeBlobColumnStream( stream, pDb, -1, "game" );
return newRow;
}
@ -145,7 +154,7 @@ writeToDB( XWStreamCtxt* stream, void* closure )
sqlite3* pDb = cGlobals->pDb;
XP_Bool newGame = -1 == selRow;
selRow = writeBlobColumn( stream, pDb, selRow, "game" );
selRow = writeBlobColumnStream( stream, pDb, selRow, "game" );
if ( newGame ) { /* new row; need to insert blob first */
cGlobals->selRow = selRow;
@ -154,6 +163,29 @@ writeToDB( XWStreamCtxt* stream, void* closure )
(*cGlobals->onSave)( cGlobals->onSaveClosure, selRow, newGame );
}
static void
addSnap( sqlite3* pDb, sqlite3_int64 curRow )
{
LOG_FUNC();
char* filename = "./red.png";
GError *error = NULL;
GdkPixbuf* snap = gdk_pixbuf_new_from_file_at_size( filename, 80, 80, &error );
XP_ASSERT( !!snap );
gchar* buffer;
gsize buffer_size;
gboolean worked = gdk_pixbuf_save_to_buffer( snap, &buffer, &buffer_size,
"png", &error, NULL );
XP_ASSERT( worked );
sqlite3_int64 newRow = writeBlobColumnData( (const XP_U8*)buffer, buffer_size,
CUR_STREAM_VERS, pDb, curRow, "snap" );
XP_ASSERT( curRow == newRow );
g_free( buffer );
g_object_unref( snap );
}
void
summarize( CommonGlobals* cGlobals )
{
@ -222,6 +254,8 @@ summarize( CommonGlobals* cGlobals )
}
sqlite3_finalize( stmt );
XP_USE( result );
addSnap( cGlobals->pDb, cGlobals->selRow );
}
GSList*
@ -262,7 +296,7 @@ getGameInfo( sqlite3* pDb, sqlite3_int64 rowid, GameInfo* gib )
{
XP_Bool success = XP_FALSE;
const char* fmt = "SELECT room, ended, turn, nmoves, ntotal, nmissing, "
"seed, connvia, gameid, lastMoveTime "
"seed, connvia, gameid, lastMoveTime, snap "
"FROM games WHERE rowid = %lld";
XP_UCHAR query[256];
snprintf( query, sizeof(query), fmt, rowid );
@ -284,8 +318,27 @@ getGameInfo( sqlite3* pDb, sqlite3_int64 rowid, GameInfo* gib )
gib->gameID = sqlite3_column_int( ppStmt, 8 );
gib->lastMoveTime = sqlite3_column_int( ppStmt, 9 );
snprintf( gib->name, sizeof(gib->name), "Game %lld", rowid );
/* Load the snapshot */
const XP_U8* ptr = sqlite3_column_blob( ppStmt, 10 );
int size = sqlite3_column_bytes( ppStmt, 10 );
/* Skip the version that's written in */
ptr += sizeof(XP_U16); size -= sizeof(XP_U16);
GInputStream* istr = g_memory_input_stream_new_from_data( ptr, size, NULL );
GError *error = NULL;
GdkPixbuf* snap = gdk_pixbuf_new_from_stream( istr, NULL, &error );
g_object_unref( istr );
if ( !snap ) {
XP_LOGF( "%s(): error from gdk_pixbuf_new_from_stream(): %s",
__func__, error->message );
g_error_free( error );
}
XP_ASSERT( !!snap );
gib->snap = snap;
}
sqlite3_finalize( ppStmt );
return success;
}
@ -354,7 +407,7 @@ loadGame( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid )
void
saveInviteAddrs( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid )
{
sqlite3_int64 row = writeBlobColumn( stream, pDb, rowid, "inviteInfo" );
sqlite3_int64 row = writeBlobColumnStream( stream, pDb, rowid, "inviteInfo" );
assert( row == rowid );
}

View file

@ -31,6 +31,7 @@ typedef struct _GameInfo {
XP_UCHAR name[128];
XP_UCHAR room[128];
XP_UCHAR conn[128];
GdkPixbuf* snap;
XP_U32 gameID;
XP_S16 nMoves;
XP_Bool gameOver;

View file

@ -75,8 +75,9 @@ findOpenGame( const GtkAppGlobals* apg, sqlite3_int64 rowid )
return result;
}
enum { ROW_ITEM, NAME_ITEM, ROOM_ITEM, GAMEID_ITEM, SEED_ITEM, CONN_ITEM, OVER_ITEM, TURN_ITEM,
NMOVES_ITEM, NTOTAL_ITEM, MISSING_ITEM, LASTTURN_ITEM, N_ITEMS };
enum { ROW_ITEM, ROW_THUMB, NAME_ITEM, ROOM_ITEM, GAMEID_ITEM, SEED_ITEM,
CONN_ITEM, OVER_ITEM, TURN_ITEM, NMOVES_ITEM, NTOTAL_ITEM, MISSING_ITEM,
LASTTURN_ITEM, N_ITEMS };
static void
foreachProc( GtkTreeModel* model, GtkTreePath* XP_UNUSED(path),
@ -143,12 +144,23 @@ addTextColumn( GtkWidget* list, const gchar* title, int item )
gtk_tree_view_append_column( GTK_TREE_VIEW(list), column );
}
static void
addImageColumn( GtkWidget* list, const gchar* title, int item )
{
GtkCellRenderer* renderer = gtk_cell_renderer_pixbuf_new();
GtkTreeViewColumn* column =
gtk_tree_view_column_new_with_attributes( title, renderer,
"pixbuf", item, NULL );
gtk_tree_view_append_column( GTK_TREE_VIEW(list), column );
}
static GtkWidget*
init_games_list( GtkAppGlobals* apg )
{
GtkWidget* list = gtk_tree_view_new();
addTextColumn( list, "Row", ROW_ITEM );
addImageColumn( list, "Snap", ROW_THUMB );
addTextColumn( list, "Name", NAME_ITEM );
addTextColumn( list, "Room", ROOM_ITEM );
addTextColumn( list, "GameID", GAMEID_ITEM );
@ -163,6 +175,7 @@ init_games_list( GtkAppGlobals* apg )
GtkListStore* store = gtk_list_store_new( N_ITEMS,
G_TYPE_INT64, /* ROW_ITEM */
GDK_TYPE_PIXBUF,/* ROW_THUMB */
G_TYPE_STRING, /* NAME_ITEM */
G_TYPE_STRING, /* ROOM_ITEM */
G_TYPE_INT, /* GAMEID_ITEM */
@ -212,6 +225,7 @@ add_to_list( GtkWidget* list, sqlite3_int64 rowid, XP_Bool isNew,
}
gtk_list_store_set( store, &iter,
ROW_ITEM, rowid,
ROW_THUMB, gib->snap,
NAME_ITEM, gib->name,
ROOM_ITEM, gib->room,
GAMEID_ITEM, gib->gameID,
@ -385,6 +399,7 @@ handle_delete_button( GtkWidget* XP_UNUSED(widget), void* closure )
} else {
XP_LOGF( "%s: not calling relaycon_deleted: no relayID", __func__ );
}
g_object_unref( gib.snap );
}
apg->selRows = g_array_set_size( apg->selRows, 0 );
updateButtons( apg );
@ -531,6 +546,7 @@ onNewData( GtkAppGlobals* apg, sqlite3_int64 rowid, XP_Bool isNew )
GameInfo gib;
if ( getGameInfo( apg->params->pDb, rowid, &gib ) ) {
add_to_list( apg->listWidget, rowid, isNew, &gib );
g_object_unref( gib.snap );
}
}

BIN
xwords4/linux/red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B