mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-29 08:34:37 +01:00
Change the suggested game name (a vs b) with the RematchOrder
It's bad to display a name based on a player order in the same place as where you're letting people change that order and not have the name change. So re-juggle the rematch process to allow the name to be changed -- but don't change once the user has edited the name.
This commit is contained in:
parent
144b68cbd5
commit
aa0aded8c4
19 changed files with 480 additions and 207 deletions
|
@ -446,15 +446,10 @@ public class GameUtils {
|
|||
public static Bitmap loadMakeBitmap( Context context, long rowid )
|
||||
{
|
||||
Bitmap thumb = null;
|
||||
try ( GameLock lock = GameLock.tryLockRO( rowid ) ) {
|
||||
if ( null != lock ) {
|
||||
CurGameInfo gi = new CurGameInfo( context );
|
||||
try ( GamePtr gamePtr = loadMakeGame( context, gi, lock ) ) {
|
||||
if ( null != gamePtr ) {
|
||||
thumb = takeSnapshot( context, gamePtr, gi );
|
||||
DBUtils.saveThumbnail( context, lock, thumb );
|
||||
}
|
||||
}
|
||||
try ( GameWrapper gw = makeGameWrapper( context, rowid ) ) {
|
||||
if ( null != gw ) {
|
||||
thumb = takeSnapshot( context, gw.gamePtr(), gw.gi() );
|
||||
DBUtils.saveThumbnail( context, gw.lock(), thumb );
|
||||
}
|
||||
}
|
||||
return thumb;
|
||||
|
@ -574,25 +569,71 @@ public class GameUtils {
|
|||
return rowid;
|
||||
}
|
||||
|
||||
public static class GameWrapper implements AutoCloseable {
|
||||
private Context mContext;
|
||||
private GameLock mLock;
|
||||
private GamePtr mGamePtr;
|
||||
private CurGameInfo mGi;
|
||||
|
||||
GameWrapper( Context context, long rowid )
|
||||
{
|
||||
mContext = context;
|
||||
mLock = GameLock.tryLockRO( rowid );
|
||||
if ( null != mLock ) {
|
||||
mGi = new CurGameInfo( mContext );
|
||||
mGamePtr = loadMakeGame( mContext, mGi, mLock );
|
||||
}
|
||||
}
|
||||
|
||||
public GamePtr gamePtr() { return mGamePtr; }
|
||||
public GameLock lock() { return mLock; }
|
||||
public CurGameInfo gi() { return mGi; }
|
||||
public boolean hasGame() { return null != mGamePtr; }
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
if ( null != mGamePtr ) {
|
||||
mGamePtr.close();
|
||||
mGamePtr = null;
|
||||
}
|
||||
if ( null != mLock ) {
|
||||
mLock.close();
|
||||
mLock = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalize() throws java.lang.Throwable
|
||||
{
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
public static GameWrapper makeGameWrapper( Context context, long rowid )
|
||||
{
|
||||
GameWrapper result = new GameWrapper( context, rowid );
|
||||
if ( !result.hasGame() ) {
|
||||
result.close();
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static long makeRematch( Context context, long srcRowid,
|
||||
long groupID, String gameName,
|
||||
RematchOrder ro )
|
||||
int[] newOrder )
|
||||
{
|
||||
long rowid = DBUtils.ROWID_NOTFOUND;
|
||||
try ( GameLock lock = GameLock.tryLockRO( srcRowid ) ) {
|
||||
if ( null != lock ) {
|
||||
CurGameInfo gi = new CurGameInfo( context );
|
||||
try ( GamePtr gamePtr = loadMakeGame( context, gi, lock ) ) {
|
||||
if ( null != gamePtr ) {
|
||||
UtilCtxt util = new UtilCtxtImpl( context );
|
||||
CommonPrefs cp = CommonPrefs.get( context );
|
||||
try ( GamePtr gamePtrNew = XwJNI
|
||||
.game_makeRematch( gamePtr, util, cp, gameName, ro ) ) {
|
||||
if ( null != gamePtrNew ) {
|
||||
rowid = saveNewGame1( context, gamePtrNew,
|
||||
groupID, gameName );
|
||||
}
|
||||
}
|
||||
try ( GameWrapper gw = makeGameWrapper( context, srcRowid ) ) {
|
||||
if ( null != gw ) {
|
||||
UtilCtxt util = new UtilCtxtImpl( context );
|
||||
CommonPrefs cp = CommonPrefs.get( context );
|
||||
try ( GamePtr gamePtrNew = XwJNI
|
||||
.game_makeRematch( gw.gamePtr(), util, cp, gameName, newOrder ) ) {
|
||||
if ( null != gamePtrNew ) {
|
||||
rowid = saveNewGame1( context, gamePtrNew,
|
||||
groupID, gameName );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -880,13 +880,11 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
LocUtils.inflate( m_activity, R.layout.rematch_config );
|
||||
|
||||
int iconResID = R.drawable.ic_sologame;
|
||||
Assert.assertTrueNR( null != m_rematchExtras );
|
||||
if ( null != m_rematchExtras ) {
|
||||
long rowid = m_rematchExtras.getLong( REMATCH_ROWID_EXTRA,
|
||||
ROWID_NOTFOUND );
|
||||
GameSummary summary = GameUtils.getSummary( m_activity, rowid );
|
||||
view.setName( m_rematchExtras.getString( REMATCH_NEWNAME_EXTRA ) )
|
||||
.setCanOfferRO( summary.canOfferRO );
|
||||
|
||||
view.configure( rowid, this );
|
||||
solo = m_rematchExtras.getBoolean( REMATCH_IS_SOLO, true );
|
||||
if ( !solo ) {
|
||||
iconResID = R.drawable.ic_multigame;
|
||||
|
@ -900,7 +898,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
.setPositiveButton( android.R.string.ok, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick( DialogInterface dlg, int item ) {
|
||||
startRematchWithName( view.getName(), view.getRO(), true );
|
||||
startRematchWithName( view.getName(), view.getNewOrder(), true );
|
||||
}
|
||||
} )
|
||||
.setNegativeButton( android.R.string.cancel, null )
|
||||
|
@ -2684,7 +2682,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
}
|
||||
|
||||
private void startRematchWithName( final String gameName,
|
||||
final RematchOrder ro,
|
||||
final int[] newOrder,
|
||||
boolean showRationale )
|
||||
{
|
||||
if ( null != gameName && 0 < gameName.length() ) {
|
||||
|
@ -2694,7 +2692,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
final CommsConnTypeSet addrs = new CommsConnTypeSet( bits );
|
||||
boolean hasSMS = addrs.contains( CommsConnType.COMMS_CONN_SMS );
|
||||
if ( !hasSMS || null != SMSPhoneInfo.get( m_activity ) ) {
|
||||
rematchWithNameAndPerm( gameName, ro, addrs );
|
||||
rematchWithNameAndPerm( gameName, newOrder, addrs );
|
||||
} else {
|
||||
int id = (1 == addrs.size())
|
||||
? R.string.phone_lookup_rationale_drop
|
||||
|
@ -2702,7 +2700,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
String msg = getString( R.string.phone_lookup_rationale )
|
||||
+ "\n\n" + getString( id );
|
||||
Perms23.tryGetPerms( this, Perms23.NBS_PERMS, msg,
|
||||
Action.ASKED_PHONE_STATE, gameName, ro, addrs );
|
||||
Action.ASKED_PHONE_STATE, gameName, newOrder, addrs );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2714,11 +2712,11 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
addrs.remove( CommsConnType.COMMS_CONN_SMS );
|
||||
}
|
||||
if ( 0 < addrs.size() ) {
|
||||
rematchWithNameAndPerm( (String)params[0], (RematchOrder)params[1], addrs );
|
||||
rematchWithNameAndPerm( (String)params[0], (int[])params[1], addrs );
|
||||
}
|
||||
}
|
||||
|
||||
private void rematchWithNameAndPerm( String gameName, RematchOrder ro,
|
||||
private void rematchWithNameAndPerm( String gameName, int[] newOrder,
|
||||
CommsConnTypeSet addrs )
|
||||
{
|
||||
if ( null != gameName && 0 < gameName.length() ) {
|
||||
|
@ -2729,7 +2727,7 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
DBUtils.GROUPID_UNSPEC );
|
||||
|
||||
long newid = GameUtils.makeRematch( m_activity, srcRowID,
|
||||
groupID, gameName, ro );
|
||||
groupID, gameName, newOrder );
|
||||
|
||||
if ( DBUtils.ROWID_NOTFOUND != newid ) {
|
||||
if ( extras.getBoolean( REMATCH_DELAFTER_EXTRA, false ) ) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
package org.eehouse.android.xw4;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
|
@ -33,17 +34,29 @@ import android.widget.RadioGroup;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eehouse.android.xw4.jni.XwJNI;
|
||||
import org.eehouse.android.xw4.jni.XwJNI.RematchOrder;
|
||||
import org.eehouse.android.xw4.loc.LocUtils;
|
||||
|
||||
public class RematchConfigView extends LinearLayout
|
||||
implements RadioGroup.OnCheckedChangeListener
|
||||
{
|
||||
private static final String TAG = RematchConfigView.class.getSimpleName();
|
||||
private static final String KEY_LAST_RO = TAG + "/key_last_ro";
|
||||
|
||||
private Context mContext;
|
||||
private DlgDelegate.HasDlgDelegate mDlgDlgt;
|
||||
private RadioGroup mGroup;
|
||||
Map<Integer, RematchOrder> mRos = new HashMap<>();
|
||||
private GameUtils.GameWrapper mWrapper;
|
||||
private Map<Integer, RematchOrder> mRos = new HashMap<>();
|
||||
private boolean mInflated;
|
||||
private String mNameStr;
|
||||
private int[] mNewOrder;
|
||||
private String mSep;
|
||||
private boolean mUserEditing = false;
|
||||
private boolean mNAShown;
|
||||
private EditWClear mEWC;
|
||||
private RematchOrder mCurRO;
|
||||
|
||||
public RematchConfigView( Context cx, AttributeSet as )
|
||||
{
|
||||
|
@ -51,53 +64,90 @@ public class RematchConfigView extends LinearLayout
|
|||
mContext = cx;
|
||||
}
|
||||
|
||||
public RematchConfigView setName( String name )
|
||||
public void configure( long rowid, DlgDelegate.HasDlgDelegate dlgDlgt )
|
||||
{
|
||||
EditWClear ewc = (EditWClear)findViewById( R.id.name );
|
||||
ewc.setText( name );
|
||||
return this;
|
||||
mDlgDlgt = dlgDlgt;
|
||||
mWrapper = GameUtils.makeGameWrapper( mContext, rowid );
|
||||
trySetup();
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
EditWClear ewc = (EditWClear)findViewById( R.id.name );
|
||||
return ewc.getText().toString();
|
||||
}
|
||||
|
||||
public RematchConfigView setCanOfferRO( boolean canOfferRO )
|
||||
{
|
||||
if ( !canOfferRO ) {
|
||||
findViewById( R.id.ro_stuff ).setVisibility( View.GONE );
|
||||
}
|
||||
return this;
|
||||
return mEWC.getText().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate()
|
||||
{
|
||||
mGroup = (RadioGroup)findViewById( R.id.group );
|
||||
mInflated = true;
|
||||
trySetup();
|
||||
}
|
||||
|
||||
int ordinal = DBUtils.getIntFor( mContext, KEY_LAST_RO, 0 );
|
||||
RematchOrder lastSel = RematchOrder.values()[ordinal];
|
||||
@Override
|
||||
protected void onDetachedFromWindow()
|
||||
{
|
||||
if ( null != mWrapper ) {
|
||||
mWrapper.close();
|
||||
mWrapper = null;
|
||||
}
|
||||
super.onDetachedFromWindow();
|
||||
}
|
||||
|
||||
for ( RematchOrder ro : RematchOrder.values() ) {
|
||||
RadioButton button = new RadioButton( mContext );
|
||||
button.setText( LocUtils.getString( mContext, ro.getStrID() ) );
|
||||
mGroup.addView( button );
|
||||
mRos.put( button.getId(), ro );
|
||||
if ( lastSel == ro ) {
|
||||
button.setChecked( true );
|
||||
// RadioGroup.OnCheckedChangeListener
|
||||
@Override
|
||||
public void onCheckedChanged( RadioGroup group, int checkedId )
|
||||
{
|
||||
if ( !mUserEditing && null != mNameStr ) {
|
||||
mUserEditing = ! mNameStr.equals( getName() );
|
||||
}
|
||||
|
||||
mCurRO = mRos.get( checkedId );
|
||||
mNewOrder = XwJNI.server_figureOrder( mWrapper.gamePtr(), mCurRO );
|
||||
|
||||
if ( mUserEditing ) {
|
||||
if ( !mNAShown ) {
|
||||
mNAShown = true;
|
||||
mDlgDlgt.makeNotAgainBuilder( R.string.key_na_rematch_edit,
|
||||
R.string.na_rematch_edit )
|
||||
.show();
|
||||
}
|
||||
} else {
|
||||
mNameStr = TextUtils.join( mSep, mWrapper.gi().playerNames(mNewOrder) );
|
||||
Log.d( TAG, "mNameStr: %s", mNameStr );
|
||||
mEWC.setText( mNameStr );
|
||||
}
|
||||
}
|
||||
|
||||
public int[] getNewOrder()
|
||||
{
|
||||
DBUtils.setIntFor( mContext, KEY_LAST_RO, mCurRO.ordinal() );
|
||||
return mNewOrder;
|
||||
}
|
||||
|
||||
private void trySetup()
|
||||
{
|
||||
if ( mInflated && null != mWrapper ) {
|
||||
mSep = LocUtils.getString( mContext, R.string.vs_join );
|
||||
mGroup = (RadioGroup)findViewById( R.id.group );
|
||||
mGroup.setOnCheckedChangeListener( this );
|
||||
mEWC = (EditWClear)findViewById( R.id.name );
|
||||
|
||||
boolean[] results = XwJNI.server_canOfferRematch( mWrapper.gamePtr() );
|
||||
if ( results[0] && results[1] ) {
|
||||
int ordinal = DBUtils.getIntFor( mContext, KEY_LAST_RO, 0 );
|
||||
RematchOrder lastSel = RematchOrder.values()[ordinal];
|
||||
|
||||
for ( RematchOrder ro : RematchOrder.values() ) {
|
||||
RadioButton button = new RadioButton( mContext );
|
||||
button.setText( LocUtils.getString( mContext, ro.getStrID() ) );
|
||||
mGroup.addView( button );
|
||||
mRos.put( button.getId(), ro );
|
||||
if ( lastSel == ro ) {
|
||||
button.setChecked( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RematchOrder getRO()
|
||||
{
|
||||
int id = mGroup.getCheckedRadioButtonId();
|
||||
RematchOrder ro = mRos.get(id);
|
||||
|
||||
DBUtils.setIntFor( mContext, KEY_LAST_RO, ro.ordinal() );
|
||||
|
||||
return ro;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -413,10 +413,16 @@ public class CurGameInfo implements Serializable {
|
|||
}
|
||||
|
||||
public String[] playerNames()
|
||||
{
|
||||
return playerNames( null );
|
||||
}
|
||||
|
||||
public String[] playerNames( int[] newOrder )
|
||||
{
|
||||
String[] names = new String[nPlayers];
|
||||
for ( int ii = 0; ii < nPlayers; ++ii ) {
|
||||
names[ii] = players[ii].name;
|
||||
int indx = null == newOrder ? ii : newOrder[ii];
|
||||
names[ii] = players[indx].name;
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
|
|
@ -351,10 +351,10 @@ public class XwJNI {
|
|||
|
||||
public static GamePtr game_makeRematch( GamePtr gamePtr, UtilCtxt util,
|
||||
CommonPrefs cp, String gameName,
|
||||
RematchOrder ro )
|
||||
int[] newOrder )
|
||||
{
|
||||
GamePtr gamePtrNew = initGameJNI( 0 );
|
||||
if ( !game_makeRematch( gamePtr, gamePtrNew, util, cp, gameName, ro ) ) {
|
||||
if ( !game_makeRematch( gamePtr, gamePtrNew, util, cp, gameName, newOrder ) ) {
|
||||
gamePtrNew.release();
|
||||
gamePtrNew = null;
|
||||
}
|
||||
|
@ -398,7 +398,7 @@ public class XwJNI {
|
|||
private static native boolean game_makeRematch( GamePtr gamePtr,
|
||||
GamePtr gamePtrNew,
|
||||
UtilCtxt util, CommonPrefs cp,
|
||||
String gameName, RematchOrder ro );
|
||||
String gameName, int[] newOrder );
|
||||
|
||||
private static native boolean game_makeFromInvite( GamePtr gamePtr, NetLaunchInfo nli,
|
||||
UtilCtxt util,
|
||||
|
@ -536,7 +536,14 @@ public class XwJNI {
|
|||
public static native boolean server_getGameIsConnected( GamePtr gamePtr );
|
||||
public static native String server_writeFinalScores( GamePtr gamePtr );
|
||||
public static native boolean server_initClientConnection( GamePtr gamePtr );
|
||||
public static native boolean server_canOfferRematch( GamePtr gamePtr );
|
||||
public static boolean[] server_canOfferRematch( GamePtr gamePtr )
|
||||
{
|
||||
boolean[] results = {false, false};
|
||||
server_canOfferRematch( gamePtr, results );
|
||||
return results;
|
||||
}
|
||||
private static native void server_canOfferRematch( GamePtr gamePtr, boolean[] results );
|
||||
public static native int[] server_figureOrder( GamePtr gamePtr, RematchOrder ro );
|
||||
public static native void server_endGame( GamePtr gamePtr );
|
||||
|
||||
// hybrid to save work
|
||||
|
|
|
@ -176,6 +176,7 @@
|
|||
<string name="key_na_deletecheck">key_na_deletecheck</string>
|
||||
|
||||
<string name="key_theme_which">key_theme_which</string>
|
||||
<string name="key_na_rematch_edit">key_na_rematch_edit</string>
|
||||
|
||||
<!-- Nor is my email address -->
|
||||
<string name="email_author_email">xwords@eehouse.org</string>
|
||||
|
|
|
@ -5,4 +5,8 @@
|
|||
|
||||
<string name="dup_allscores_fmt">All scores: %1$s</string>
|
||||
|
||||
<string name="na_rematch_edit">The game name will not change once
|
||||
you have started editing it. If you decide you want a generated
|
||||
name, please cancel and restart the rematching process.</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -397,10 +397,15 @@ makeBooleanArray( JNIEnv* env, int siz, const jboolean* vals )
|
|||
return array;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
getIntsFromArray( JNIEnv* env, int dest[], jintArray arr, int count, bool del )
|
||||
{
|
||||
jint* ints = (*env)->GetIntArrayElements(env, arr, 0);
|
||||
jsize len = (*env)->GetArrayLength( env, arr );
|
||||
if ( len < count ) {
|
||||
count = len;
|
||||
}
|
||||
|
||||
for ( int ii = 0; ii < count; ++ii ) {
|
||||
dest[ii] = ints[ii];
|
||||
}
|
||||
|
@ -408,6 +413,7 @@ getIntsFromArray( JNIEnv* env, int dest[], jintArray arr, int count, bool del )
|
|||
if ( del ) {
|
||||
deleteLocalRef( env, arr );
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -71,7 +71,8 @@ jobject getObjectField( JNIEnv* env, jobject obj, const char* fieldName,
|
|||
jintArray makeIntArray( JNIEnv* env, int size, const void* vals, size_t elemSize );
|
||||
void setIntArray( JNIEnv* env, jobject jowner, const char* ownerField,
|
||||
int count, const void* vals, size_t elemSize );
|
||||
void getIntsFromArray( JNIEnv* env, int dest[], jintArray arr, int count, bool del );
|
||||
/* returns number of items copied, i.e. min of count and len(array) */
|
||||
int getIntsFromArray( JNIEnv* env, int dest[], jintArray arr, int count, bool del );
|
||||
void setIntInArray( JNIEnv* env, jintArray arr, int index, int val );
|
||||
|
||||
jbyteArray makeByteArray( JNIEnv* env, int size, const jbyte* vals );
|
||||
|
|
|
@ -1423,7 +1423,7 @@ initGameGlobals( JNIEnv* env, JNIState* state, jobject jutil, jobject jprocs )
|
|||
JNIEXPORT jboolean JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeRematch
|
||||
( JNIEnv* env, jclass C, GamePtrType gamePtr, GamePtrType gamePtrNew,
|
||||
jobject jutil, jobject jcp, jstring jGameName, jobject jRo )
|
||||
jobject jutil, jobject jcp, jstring jGameName, jintArray jNO )
|
||||
{
|
||||
jboolean success = false;
|
||||
XWJNI_START_GLOBALS(gamePtr);
|
||||
|
@ -1437,10 +1437,17 @@ Java_org_eehouse_android_xw4_jni_XwJNI_game_1makeRematch
|
|||
loadCommonPrefs( env, &cp, jcp );
|
||||
|
||||
const char* gameName = (*env)->GetStringUTFChars( env, jGameName, NULL );
|
||||
RematchOrder ro = jEnumToInt( env, jRo );
|
||||
|
||||
NewOrder no;
|
||||
int tmp[VSIZE(no.order)];
|
||||
int count = getIntsFromArray( env, tmp, jNO, VSIZE(tmp), XP_FALSE );
|
||||
for ( int ii = 0; ii < count; ++ii ) {
|
||||
no.order[ii] = tmp[ii];
|
||||
}
|
||||
|
||||
success = game_makeRematch( &oldState->game, env, globals->util, &cp,
|
||||
(TransportProcs*)NULL, &state->game,
|
||||
gameName, ro );
|
||||
gameName, &no );
|
||||
(*env)->ReleaseStringUTFChars( env, jGameName, gameName );
|
||||
|
||||
if ( success ) {
|
||||
|
@ -2191,15 +2198,32 @@ Java_org_eehouse_android_xw4_jni_XwJNI_server_1initClientConnection
|
|||
return result;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_server_1canOfferRematch
|
||||
( JNIEnv* env, jclass C, GamePtrType gamePtr )
|
||||
( JNIEnv* env, jclass C, GamePtrType gamePtr, jbooleanArray results )
|
||||
{
|
||||
jboolean result;
|
||||
XWJNI_START_GLOBALS(gamePtr);
|
||||
XP_Bool canOffer;
|
||||
XP_Bool canRematch = server_canRematch( state->game.server, &canOffer );
|
||||
result = canRematch && canOffer;
|
||||
XP_Bool bools[2];
|
||||
bools[0] = server_canRematch( state->game.server, &bools[1] );
|
||||
setBoolArray( env, results, VSIZE(bools), (jboolean*)bools );
|
||||
|
||||
XWJNI_END();
|
||||
}
|
||||
|
||||
JNIEXPORT jintArray JNICALL
|
||||
Java_org_eehouse_android_xw4_jni_XwJNI_server_1figureOrder
|
||||
( JNIEnv* env, jclass C, GamePtrType gamePtr, jobject jRo )
|
||||
{
|
||||
jintArray result = NULL;
|
||||
XWJNI_START_GLOBALS(gamePtr);
|
||||
RematchOrder ro = jEnumToInt( env, jRo );
|
||||
XP_LOGFF( "(ro=%s)", RO2Str(ro) );
|
||||
|
||||
NewOrder no;
|
||||
server_figureOrder( state->game.server, ro, &no );
|
||||
|
||||
result = makeIntArray( env, globals->gi->nPlayers, no.order, sizeof(no.order[0]) );
|
||||
|
||||
XWJNI_END();
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -231,14 +231,13 @@ game_makeNewGame( MPFORMAL XWEnv xwe, XWGame* game, CurGameInfo* gi,
|
|||
XP_Bool
|
||||
game_makeRematch( const XWGame* oldGame, XWEnv xwe, XW_UtilCtxt* newUtil,
|
||||
const CommonPrefs* newCp, const TransportProcs* procs,
|
||||
XWGame* newGame, const XP_UCHAR* newName, RematchOrder ro )
|
||||
XWGame* newGame, const XP_UCHAR* newName, NewOrder* nop )
|
||||
{
|
||||
XP_Bool success = XP_FALSE;
|
||||
XP_LOGFF( "(newName=%s, ro=%s)", newName, RO2Str(ro) );
|
||||
|
||||
RematchInfo* rip;
|
||||
if ( server_getRematchInfo( oldGame->server, newUtil,
|
||||
makeGameID( newUtil ), ro, &rip ) ) {
|
||||
makeGameID( newUtil ), nop, &rip ) ) {
|
||||
CommsAddrRec* selfAddrP = NULL;
|
||||
CommsAddrRec selfAddr;
|
||||
if ( !!oldGame->comms ) {
|
||||
|
@ -275,9 +274,10 @@ game_makeRematch( const XWGame* oldGame, XWEnv xwe, XW_UtilCtxt* newUtil,
|
|||
}
|
||||
server_disposeRematchInfo( oldGame->server, &rip );
|
||||
}
|
||||
XP_LOGFF( "=> %s; game with gid %08X rematched to create game with gid %08X using ro %s",
|
||||
XP_LOGFF( "=> %s; game with gid %08X rematched to create game "
|
||||
"with gid %08X",
|
||||
boolToStr(success), oldGame->util->gameInfo->gameID,
|
||||
newUtil->gameInfo->gameID, RO2Str(ro) );
|
||||
newUtil->gameInfo->gameID );
|
||||
return success;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ XP_Bool game_makeNewGame( MPFORMAL XWEnv xwe, XWGame* game, CurGameInfo* gi,
|
|||
XP_Bool game_makeRematch( const XWGame* game, XWEnv xwe, XW_UtilCtxt* util,
|
||||
const CommonPrefs* cp, const TransportProcs* procs,
|
||||
XWGame* newGame, const XP_UCHAR* newName,
|
||||
RematchOrder ro );
|
||||
NewOrder* no );
|
||||
|
||||
void game_changeDict( MPFORMAL XWGame* game, XWEnv xwe, CurGameInfo* gi,
|
||||
DictionaryCtxt* dict );
|
||||
|
|
|
@ -4184,16 +4184,16 @@ server_canRematch( const ServerCtxt* server, XP_Bool* canOrderP )
|
|||
as invitees join the new game.
|
||||
*/
|
||||
static void
|
||||
sortBySame( const ServerCtxt* server, int newOrder[] )
|
||||
sortBySame( const ServerCtxt* server, NewOrder* nop )
|
||||
{
|
||||
const CurGameInfo* gi = server->vol.gi;
|
||||
for ( int ii = 0; ii < gi->nPlayers; ++ii ) {
|
||||
newOrder[ii] = ii;
|
||||
nop->order[ii] = ii;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sortByScoreLow( const ServerCtxt* server, int newOrder[] )
|
||||
sortByScoreLow( const ServerCtxt* server, NewOrder* nop )
|
||||
{
|
||||
const CurGameInfo* gi = server->vol.gi;
|
||||
|
||||
|
@ -4216,7 +4216,7 @@ sortByScoreLow( const ServerCtxt* server, int newOrder[] )
|
|||
break;
|
||||
} else {
|
||||
mask |= 1 << newPosn;
|
||||
newOrder[resultIndx] = newPosn;
|
||||
nop->order[resultIndx] = newPosn;
|
||||
/* SRVR_LOGFF( "result[%d] = %d (for score %d)", resultIndx, newPosn, */
|
||||
/* lowest ); */
|
||||
}
|
||||
|
@ -4224,20 +4224,20 @@ sortByScoreLow( const ServerCtxt* server, int newOrder[] )
|
|||
}
|
||||
|
||||
static void
|
||||
sortByScoreHigh( const ServerCtxt* server, int newOrder[] )
|
||||
sortByScoreHigh( const ServerCtxt* server, NewOrder* nop )
|
||||
{
|
||||
sortByScoreLow( server, newOrder );
|
||||
sortByScoreLow( server, nop );
|
||||
|
||||
const CurGameInfo* gi = server->vol.gi;
|
||||
for ( int ii = 0, jj = gi->nPlayers - 1; ii < jj; ++ii, --jj ) {
|
||||
int tmp = newOrder[ii];
|
||||
newOrder[ii] = newOrder[jj];
|
||||
newOrder[jj] = tmp;
|
||||
int tmp = nop->order[ii];
|
||||
nop->order[ii] = nop->order[jj];
|
||||
nop->order[jj] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sortByRandom( const ServerCtxt* server, int newOrder[] )
|
||||
sortByRandom( const ServerCtxt* server, NewOrder* nop )
|
||||
{
|
||||
const CurGameInfo* gi = server->vol.gi;
|
||||
int src[gi->nPlayers];
|
||||
|
@ -4247,8 +4247,8 @@ sortByRandom( const ServerCtxt* server, int newOrder[] )
|
|||
for ( int ii = 0; ii < gi->nPlayers; ++ii ) {
|
||||
int nLeft = gi->nPlayers - ii;
|
||||
int indx = XP_RANDOM() % nLeft;
|
||||
newOrder[ii] = src[indx];
|
||||
SRVR_LOGFF( "set result[%d] to %d", ii, newOrder[ii] );
|
||||
nop->order[ii] = src[indx];
|
||||
SRVR_LOGFF( "set result[%d] to %d", ii, nop->order[ii] );
|
||||
/* now swap the last down */
|
||||
src[indx] = src[nLeft-1];
|
||||
}
|
||||
|
@ -4256,7 +4256,7 @@ sortByRandom( const ServerCtxt* server, int newOrder[] )
|
|||
|
||||
#ifdef XWFEATURE_RO_BYNAME
|
||||
static void
|
||||
sortByName( const ServerCtxt* server, int newOrder[] )
|
||||
sortByName( const ServerCtxt* server, NewOrder* nop )
|
||||
{
|
||||
const CurGameInfo* gi = server->vol.gi;
|
||||
int mask = 0; /* mark values already consumed */
|
||||
|
@ -4275,81 +4275,40 @@ sortByName( const ServerCtxt* server, int newOrder[] )
|
|||
}
|
||||
XP_ASSERT( lowest != -1 );
|
||||
mask |= 1 << lowest;
|
||||
newOrder[ii] = lowest;
|
||||
nop->order[ii] = lowest;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef void (*OrderProc)(const ServerCtxt* server, int newOrder[]);
|
||||
|
||||
static XP_Bool
|
||||
setPlayerOrder( const ServerCtxt* server, RematchOrder ro,
|
||||
setPlayerOrder( const ServerCtxt* server, const NewOrder* nop,
|
||||
CurGameInfo* gi, RematchInfo* rip )
|
||||
{
|
||||
// SRVR_LOGFF( "(ro=%s)", RO2Str(ri->ro) );
|
||||
LOGGI( gi, "start" );
|
||||
OrderProc proc = NULL;
|
||||
switch ( ro ) {
|
||||
case RO_SAME:
|
||||
proc = sortBySame;
|
||||
// sortBySame( server, newOrder );
|
||||
break;
|
||||
case RO_LOW_SCORE_FIRST:
|
||||
proc = sortByScoreLow;
|
||||
break;
|
||||
case RO_HIGH_SCORE_FIRST:
|
||||
proc = sortByScoreHigh;
|
||||
break;
|
||||
case RO_JUGGLE:
|
||||
proc = sortByRandom;
|
||||
break;
|
||||
#ifdef XWFEATURE_RO_BYNAME
|
||||
case RO_BY_NAME:
|
||||
proc = sortByName;
|
||||
break;
|
||||
#endif
|
||||
case RO_NUM_ROS:
|
||||
default:
|
||||
XP_ASSERT(0); break;
|
||||
CurGameInfo srcGi = *gi;
|
||||
RematchInfo srcRi;
|
||||
if ( !!rip ) {
|
||||
srcRi = *rip;
|
||||
}
|
||||
|
||||
XP_ASSERT( !!proc );
|
||||
int newOrder[gi->nPlayers];
|
||||
XP_MEMSET( newOrder, 0, sizeof(newOrder) );
|
||||
XP_Bool success = !!proc;
|
||||
if ( success ) {
|
||||
(*proc)( server, newOrder );
|
||||
/* We have gi and rip that express an ordering of players. And we have
|
||||
a new order into which to move them. Just walk and swap the current
|
||||
with the right one above it. */
|
||||
|
||||
CurGameInfo srcGi = *gi;
|
||||
RematchInfo srcRi;
|
||||
for ( int ii = 0; ii < gi->nPlayers; ++ii ) {
|
||||
gi->players[ii] = srcGi.players[nop->order[ii]];
|
||||
if ( !!rip ) {
|
||||
srcRi = *rip;
|
||||
}
|
||||
|
||||
for ( int ii = 0; ii < gi->nPlayers; ++ii ) {
|
||||
gi->players[ii] = srcGi.players[newOrder[ii]];
|
||||
if ( !!rip ) {
|
||||
rip->addrIndices[ii] = srcRi.addrIndices[newOrder[ii]];
|
||||
}
|
||||
}
|
||||
|
||||
LOGGI( gi, "end" );
|
||||
if ( !!rip ) {
|
||||
LOG_RI( rip );
|
||||
rip->addrIndices[ii] = srcRi.addrIndices[nop->order[ii]];
|
||||
}
|
||||
}
|
||||
XP_ASSERT(success);
|
||||
return success;
|
||||
|
||||
LOGGI( gi, "end" );
|
||||
if ( !!rip ) {
|
||||
LOG_RI( rip );
|
||||
}
|
||||
|
||||
return XP_TRUE;
|
||||
} /* setPlayerOrder */
|
||||
|
||||
XP_Bool
|
||||
server_getRematchInfo( const ServerCtxt* server, XW_UtilCtxt* newUtil,
|
||||
XP_U32 gameID, RematchOrder ro, RematchInfo** ripp )
|
||||
XP_U32 gameID, const NewOrder* nop, RematchInfo** ripp )
|
||||
{
|
||||
SRVR_LOGFF( "(ro=%s)", RO2Str(ro) );
|
||||
XP_Bool success = server_canRematch( server, NULL );
|
||||
const CommsCtxt* comms = server->vol.comms;
|
||||
if ( success ) {
|
||||
|
@ -4443,7 +4402,7 @@ server_getRematchInfo( const ServerCtxt* server, XW_UtilCtxt* newUtil,
|
|||
if ( !!comms ) {
|
||||
assertRI( &ri, newGI );
|
||||
}
|
||||
success = setPlayerOrder( server, ro, newGI, !!comms ? &ri : NULL );
|
||||
success = setPlayerOrder( server, nop, newGI, !!comms ? &ri : NULL );
|
||||
}
|
||||
|
||||
if ( success && !!comms ) {
|
||||
|
@ -4500,6 +4459,38 @@ server_ri_getAddr( const RematchInfo* rip, XP_U16 nth,
|
|||
return success;
|
||||
}
|
||||
|
||||
void
|
||||
server_figureOrder( const ServerCtxt* server, RematchOrder ro, NewOrder* nop )
|
||||
{
|
||||
XP_MEMSET( nop, 0, sizeof(*nop) );
|
||||
|
||||
void (*proc)(const ServerCtxt*, NewOrder*) = NULL;
|
||||
switch ( ro ) {
|
||||
case RO_SAME:
|
||||
proc = sortBySame;
|
||||
break;
|
||||
case RO_LOW_SCORE_FIRST:
|
||||
proc = sortByScoreLow;
|
||||
break;
|
||||
case RO_HIGH_SCORE_FIRST:
|
||||
proc = sortByScoreHigh;
|
||||
break;
|
||||
case RO_JUGGLE:
|
||||
proc = sortByRandom;
|
||||
break;
|
||||
#ifdef XWFEATURE_RO_BYNAME
|
||||
case RO_BY_NAME:
|
||||
proc = sortByName;
|
||||
break;
|
||||
#endif
|
||||
case RO_NUM_ROS:
|
||||
default:
|
||||
XP_ASSERT(0); break;
|
||||
}
|
||||
|
||||
(*proc)( server, nop );
|
||||
}
|
||||
|
||||
/* Record the desired order, which is already set in the RematchInfo passed
|
||||
in, so we can enforce it as clients register. */
|
||||
void
|
||||
|
|
|
@ -167,13 +167,22 @@ const XP_UCHAR* RO2Str(RematchOrder ro);
|
|||
No need for a count: once we find a playersMask == 0 we're done
|
||||
*/
|
||||
|
||||
typedef struct RematchInfo RematchInfo;
|
||||
typedef struct _NewOrder {
|
||||
XP_U8 order[MAX_NUM_PLAYERS];
|
||||
} NewOrder;
|
||||
|
||||
/* Figure the order of players from the current game per the RematchOrder
|
||||
provided. */
|
||||
void server_figureOrder( const ServerCtxt* server, RematchOrder ro,
|
||||
NewOrder* nop );
|
||||
|
||||
/* Sets up newUtil->gameInfo correctly, and returns with a set of
|
||||
addresses to which invitation should be sent. But: meant to be called
|
||||
only from game.c anyway.
|
||||
*/
|
||||
typedef struct RematchInfo RematchInfo;
|
||||
XP_Bool server_getRematchInfo( const ServerCtxt* server, XW_UtilCtxt* newUtil,
|
||||
XP_U32 gameID, RematchOrder ro, RematchInfo** ripp );
|
||||
XP_U32 gameID, const NewOrder* nop, RematchInfo** ripp );
|
||||
void server_disposeRematchInfo( ServerCtxt* server, RematchInfo** rip );
|
||||
XP_Bool server_ri_getAddr( const RematchInfo* ri, XP_U16 nth,
|
||||
CommsAddrRec* addr, XP_U16* nPlayersH );
|
||||
|
|
|
@ -130,6 +130,7 @@ DEFINES += -DINITIAL_CLIENT_VERS=3
|
|||
DEFINES += -DCOMMON_LAYOUT
|
||||
DEFINES += -DNATIVE_NLI
|
||||
DEFINES += -DXWFEATURE_COMMS_INVITE
|
||||
DEFINES += -DXWFEATURE_RO_BYNAME
|
||||
# DEFINES += -DRELAY_VIA_HTTP
|
||||
|
||||
# MAX_ROWS controls STREAM_VERS_BIGBOARD and with it move hashing
|
||||
|
@ -211,6 +212,7 @@ GTK_OBJS = \
|
|||
$(BUILD_PLAT_DIR)/gtkaskdict.o \
|
||||
$(BUILD_PLAT_DIR)/gtkchat.o \
|
||||
$(BUILD_PLAT_DIR)/gtkkpdlg.o \
|
||||
$(BUILD_PLAT_DIR)/gtkrmtch.o \
|
||||
|
||||
endif
|
||||
ifdef DO_CURSES
|
||||
|
|
|
@ -1032,10 +1032,13 @@ rematch_and_save( CursesBoardGlobals* bGlobals, RematchOrder ro,
|
|||
|
||||
CursesBoardGlobals* bGlobalsNew = commonInit( cbState, -1, NULL );
|
||||
|
||||
XP_Bool success = game_makeRematch( &bGlobals->cGlobals.game, NULL_XWE,
|
||||
NewOrder no;
|
||||
server_figureOrder( cGlobals->game.server, ro, &no );
|
||||
|
||||
XP_Bool success = game_makeRematch( &cGlobals->game, NULL_XWE,
|
||||
bGlobalsNew->cGlobals.util,
|
||||
&cGlobals->cp, &bGlobalsNew->cGlobals.procs,
|
||||
&bGlobalsNew->cGlobals.game, "newName", ro );
|
||||
&bGlobalsNew->cGlobals.game, "newName", &no );
|
||||
if ( success ) {
|
||||
if ( !!newGameIDP ) {
|
||||
*newGameIDP = bGlobalsNew->cGlobals.gi->gameID;
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "device.h"
|
||||
#include "gtkkpdlg.h"
|
||||
#include "gtknewgame.h"
|
||||
#include "gtkrmtch.h"
|
||||
|
||||
static void onNewData( GtkAppGlobals* apg, sqlite3_int64 rowid,
|
||||
XP_Bool isNew );
|
||||
|
@ -366,51 +367,33 @@ handle_open_button( GtkWidget* XP_UNUSED(widget), void* closure )
|
|||
void
|
||||
make_rematch( GtkAppGlobals* apg, const CommonGlobals* cGlobals )
|
||||
{
|
||||
XP_Bool canOffer;
|
||||
XP_Bool canRematch = server_canRematch( cGlobals->game.server, &canOffer );
|
||||
XP_Bool canRematch = server_canRematch( cGlobals->game.server, NULL );
|
||||
XP_ASSERT( canRematch );
|
||||
|
||||
RematchOrder ro = RO_SAME;
|
||||
if ( canOffer ) {
|
||||
const AskPair buttons[] = {
|
||||
{"Juggle", RO_JUGGLE},
|
||||
{"Low score first", RO_LOW_SCORE_FIRST},
|
||||
{"High score first", RO_HIGH_SCORE_FIRST},
|
||||
#ifdef XWFEATURE_RO_BYNAME
|
||||
{ "Alphabetical", RO_BY_NAME },
|
||||
#endif
|
||||
{ "Keep existing", RO_SAME },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
if ( canRematch ) {
|
||||
gchar gameName[128];
|
||||
int nameLen = VSIZE(gameName);
|
||||
NewOrder no;
|
||||
if ( gtkask_rematch( cGlobals, &no, gameName, &nameLen ) ) {
|
||||
LaunchParams* params = apg->cag.params;
|
||||
GtkGameGlobals* newGlobals = calloc( 1, sizeof(*newGlobals) );
|
||||
initBoardGlobalsGtk( newGlobals, params, NULL );
|
||||
|
||||
gint response;
|
||||
if ( gtkask_radios( apg->window, "rematch? choose new order",
|
||||
buttons, &response ) ) {
|
||||
ro = buttons[response].result;
|
||||
} else {
|
||||
goto exit;
|
||||
XW_UtilCtxt* util = newGlobals->cGlobals.util;
|
||||
const CommonPrefs* cp = &newGlobals->cGlobals.cp;
|
||||
XP_UCHAR buf[64];
|
||||
snprintf( buf, VSIZE(buf), "Game %lX", XP_RANDOM() % 256 );
|
||||
game_makeRematch( &cGlobals->game, NULL_XWE, util, cp,
|
||||
&newGlobals->cGlobals.procs,
|
||||
&newGlobals->cGlobals.game, buf, &no );
|
||||
|
||||
linuxSaveGame( &newGlobals->cGlobals );
|
||||
sqlite3_int64 rowid = newGlobals->cGlobals.rowid;
|
||||
freeGlobals( newGlobals );
|
||||
|
||||
open_row( apg, rowid, XP_TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
LaunchParams* params = apg->cag.params;
|
||||
GtkGameGlobals* newGlobals = calloc( 1, sizeof(*newGlobals) );
|
||||
initBoardGlobalsGtk( newGlobals, params, NULL );
|
||||
|
||||
XW_UtilCtxt* util = newGlobals->cGlobals.util;
|
||||
const CommonPrefs* cp = &newGlobals->cGlobals.cp;
|
||||
XP_UCHAR buf[64];
|
||||
snprintf( buf, VSIZE(buf), "Game %lX", XP_RANDOM() % 256 );
|
||||
game_makeRematch( &cGlobals->game, NULL_XWE, util, cp,
|
||||
&newGlobals->cGlobals.procs,
|
||||
&newGlobals->cGlobals.game, buf, ro );
|
||||
|
||||
linuxSaveGame( &newGlobals->cGlobals );
|
||||
sqlite3_int64 rowid = newGlobals->cGlobals.rowid;
|
||||
freeGlobals( newGlobals );
|
||||
|
||||
open_row( apg, rowid, XP_TRUE );
|
||||
exit:
|
||||
return;
|
||||
} /* make_rematch */
|
||||
|
||||
static void
|
||||
|
|
118
xwords4/linux/gtkrmtch.c
Normal file
118
xwords4/linux/gtkrmtch.c
Normal file
|
@ -0,0 +1,118 @@
|
|||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
||||
/*
|
||||
* Copyright 2024 by Eric House (xwords@eehouse.org). All rights reserved.
|
||||
*
|
||||
* 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 "gtkrmtch.h"
|
||||
#include "dbgutil.h"
|
||||
#include "gtkutils.h"
|
||||
|
||||
struct {
|
||||
const gchar* txt;
|
||||
RematchOrder ro;
|
||||
} sROData[] = {
|
||||
{ "Keep existing", RO_SAME },
|
||||
{ "Low score first", RO_LOW_SCORE_FIRST },
|
||||
{ "High score first", RO_HIGH_SCORE_FIRST },
|
||||
{ "Juggle", RO_JUGGLE },
|
||||
#ifdef XWFEATURE_RO_BYNAME
|
||||
{ "Alphabetical", RO_BY_NAME },
|
||||
#endif
|
||||
};
|
||||
|
||||
#define OK_RESULT 1000
|
||||
|
||||
typedef struct _State {
|
||||
const CommonGlobals* cGlobals;
|
||||
NewOrder* nop;
|
||||
GtkWidget* dialog;
|
||||
GtkWidget* radios[RO_NUM_ROS];
|
||||
int curSel;
|
||||
GtkWidget* nameField;
|
||||
} State;
|
||||
|
||||
static void
|
||||
toggled( GtkToggleButton* togglebutton, gpointer user_data )
|
||||
{
|
||||
State* state = (State*)user_data;
|
||||
gboolean active = gtk_toggle_button_get_active( togglebutton );
|
||||
if ( active ) {
|
||||
for ( int ii = 0; ii < VSIZE(sROData); ++ii ) {
|
||||
if ( state->radios[ii] == GTK_WIDGET(togglebutton) ) {
|
||||
state->curSel = ii;
|
||||
|
||||
server_figureOrder( state->cGlobals->game.server, sROData[ii].ro,
|
||||
state->nop );
|
||||
|
||||
const CurGameInfo* gi = state->cGlobals->gi;
|
||||
const gchar* arr[gi->nPlayers + 1];
|
||||
for ( int ii = 0; ii < gi->nPlayers; ++ii ) {
|
||||
arr[ii] = gi->players[state->nop->order[ii]].name;
|
||||
}
|
||||
arr[gi->nPlayers] = NULL;
|
||||
gchar* namesstr = g_strjoinv( " vs. ", (gchar**)arr );
|
||||
gtk_entry_set_text( GTK_ENTRY(state->nameField), namesstr );
|
||||
g_free( namesstr );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XP_Bool
|
||||
gtkask_rematch( const CommonGlobals* cGlobals, NewOrder* nop,
|
||||
gchar* gameName, int* nameLen )
|
||||
{
|
||||
XP_USE( gameName );
|
||||
XP_USE( nameLen );
|
||||
|
||||
State state = { .cGlobals = cGlobals, .nop = nop, };
|
||||
|
||||
state.dialog = gtk_dialog_new();
|
||||
gtk_window_set_modal( GTK_WINDOW( state.dialog ), TRUE );
|
||||
|
||||
GtkWidget* vbox = gtk_box_new( GTK_ORIENTATION_VERTICAL, 0 );
|
||||
|
||||
GtkWidget* tmp = makeLabeledField( "Game Name", &state.nameField, "nothing" );
|
||||
gtk_box_pack_start( GTK_BOX(vbox), GTK_WIDGET(tmp), FALSE, TRUE, 0 );
|
||||
|
||||
GtkWidget* prev = NULL;
|
||||
for ( int ii = 0; ii < VSIZE(sROData); ++ii ) {
|
||||
const gchar* txt = sROData[ii].txt;
|
||||
GtkWidget* radio = state.radios[ii]
|
||||
= gtk_radio_button_new_with_label_from_widget( GTK_RADIO_BUTTON(prev), txt );
|
||||
g_signal_connect( radio, "toggled", G_CALLBACK(toggled), &state );
|
||||
gtk_box_pack_start( GTK_BOX(vbox), GTK_WIDGET(radio), FALSE, TRUE, 0 );
|
||||
prev = radio;
|
||||
}
|
||||
g_signal_emit_by_name(state.radios[0], "toggled");
|
||||
|
||||
gtk_dialog_add_action_widget( GTK_DIALOG(state.dialog), vbox, 0 );
|
||||
|
||||
gtk_dialog_add_button( GTK_DIALOG(state.dialog), "OK", OK_RESULT );
|
||||
|
||||
gtk_widget_show_all( state.dialog );
|
||||
|
||||
gint dlgResult = gtk_dialog_run( GTK_DIALOG(state.dialog) );
|
||||
|
||||
gtk_widget_destroy( state.dialog );
|
||||
|
||||
XP_Bool success = dlgResult == OK_RESULT;
|
||||
LOG_RETURNF( "%s", boolToStr(success) );
|
||||
return success;
|
||||
}
|
29
xwords4/linux/gtkrmtch.h
Normal file
29
xwords4/linux/gtkrmtch.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
||||
/*
|
||||
* Copyright 2024 by Eric House (xwords@eehouse.org). All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _GTKRMTCH_H_
|
||||
#define _GTKRMTCH_H_
|
||||
|
||||
#include "server.h"
|
||||
#include "main.h"
|
||||
|
||||
XP_Bool gtkask_rematch( const CommonGlobals* cGlobals, NewOrder* nop,
|
||||
gchar* gameName, int* nameLen );
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue