/* * ZoomButtons.java * Copyright (C) 2015 Nicholas Killewald * * This file is distributed under the terms of the BSD license. * The source package should have a LICENSE file at the toplevel. */ package net.exclaimindustries.geohashdroid.widgets; import android.app.Activity; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.ViewTreeObserver; import android.widget.ImageButton; import android.widget.RelativeLayout; import net.exclaimindustries.geohashdroid.R; /** * The <code>ZoomButtons</code> container handles the button in the lower-left * of CentralMap. It pops out when tapped, revealing more buttons to center and * re-zoom the view as need be. No, this isn't related to the zoom buttons on * the old API v1 maps. */ public class ZoomButtons extends RelativeLayout { private static final String DEBUG_TAG = "ZoomButtons"; private ImageButton mZoomMenu; private ImageButton mCancelMenu; private ImageButton mZoomFitBoth; private ImageButton mZoomUser; private ImageButton mZoomDestination; private boolean mAlreadyLaidOut = false; // So we don't have to keep recalculating it for five buttons and their // margins, that's why. private float mButtonWidth = 0.0f; /** Zoom to fit both the user and the hashpoint on screen at once. */ public static final int ZOOM_FIT_BOTH = 0; /** Zoom to the user's location. */ public static final int ZOOM_USER = 1; /** Zoom to the hashpoint. */ public static final int ZOOM_DESTINATION = 2; /** * This should be implemented by anything that's waiting to respond to the * zoom buttons. So, ExpeditionMode, really. */ public interface ZoomButtonListener { /** * Called when a zoom button is pressed. Not, mind you, when either the * menu button itself or the cancel button are pressed. * * @param container this, for convenience * @param which an int specifying which button just got pressed * @see #ZOOM_FIT_BOTH * @see #ZOOM_USER * @see #ZOOM_DESTINATION */ void zoomButtonPressed(View container, int which); } private ZoomButtonListener mListener; public ZoomButtons(Context c) { this(c, null); } public ZoomButtons(Context c, AttributeSet attrs) { super(c, attrs); inflate(c, R.layout.zoom_buttons, this); // Gather up all our sub-buttons... mZoomMenu = (ImageButton) findViewById(R.id.zoom_button_menu); mCancelMenu = (ImageButton) findViewById(R.id.zoom_button_cancel); mZoomFitBoth = (ImageButton) findViewById(R.id.zoom_button_fit_both); mZoomUser = (ImageButton) findViewById(R.id.zoom_button_you); mZoomDestination = (ImageButton) findViewById(R.id.zoom_button_destination); // ...and make them do something. mZoomFitBoth.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(mListener != null) mListener.zoomButtonPressed(ZoomButtons.this, ZOOM_FIT_BOTH); showMenu(false); } }); mZoomUser.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(mListener != null) mListener.zoomButtonPressed(ZoomButtons.this, ZOOM_USER); showMenu(false); } }); mZoomDestination.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(mListener != null) mListener.zoomButtonPressed(ZoomButtons.this, ZOOM_DESTINATION); showMenu(false); } }); mZoomMenu.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { showMenu(true); } }); mCancelMenu.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { showMenu(false); } }); // Wait for layout, as usual... getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if(!mAlreadyLaidOut) { mAlreadyLaidOut = true; // Get hold of the basic widths of everything. We'll just // re-use that a lot. mButtonWidth = mCancelMenu.getWidth() + (2 * getResources().getDimension(R.dimen.margin_zoom_button)); // First layout, make all the buttons be off-screen. The // right mode will be set back on as need be. mZoomMenu.setTranslationX(-mButtonWidth); mCancelMenu.setTranslationX(-mButtonWidth); mZoomFitBoth.setTranslationX(-mButtonWidth); mZoomUser.setTranslationX(-mButtonWidth); mZoomDestination.setTranslationX(-mButtonWidth); showMenu(false); } } }); } /** * Sets whether the menu is showing (the three options and cancel are up) or * not (the button that triggers the menu is up). * * @param show true to show, false to hide */ public void showMenu(boolean show) { if(mAlreadyLaidOut) { // Only do this if we're laid out. Otherwise, this'll go haywire // with the widget sizes if mButtonWidth isn't defined. if(show) { // Menu in! Button out! mZoomMenu.animate().translationX(-mButtonWidth); mCancelMenu.animate().translationX(0.0f); mZoomFitBoth.animate().translationX(0.0f); mZoomUser.animate().translationX(0.0f); mZoomDestination.animate().translationX(0.0f); } else { // Menu out! Button in! mZoomMenu.animate().translationX(0.0f); mCancelMenu.animate().translationX(-mButtonWidth); mZoomFitBoth.animate().translationX(-mButtonWidth); mZoomUser.animate().translationX(-mButtonWidth); mZoomDestination.animate().translationX(-mButtonWidth); } } } /** * Sets whatever's going to listen to the buttons. * * @param listener said listener */ public void setListener(ZoomButtonListener listener) { mListener = listener; } /** * Enables or disables a button. Note that this won't do the logic to make * sure "fit both" is disabled when either "your location" or "final * destination" are, so do that yourself. * * @param button button to disable, by ZOOM_* statics * @param enabled true to enable, false to disable * @see #ZOOM_FIT_BOTH * @see #ZOOM_USER * @see #ZOOM_DESTINATION */ public void setButtonEnabled(int button, final boolean enabled) { View toDisable = null; switch(button) { case ZOOM_FIT_BOTH: toDisable = mZoomFitBoth; break; case ZOOM_USER: toDisable = mZoomUser; break; case ZOOM_DESTINATION: toDisable = mZoomDestination; break; } // Of course, if this wasn't a valid button, toDisable will remain null, // meaning the caller screwed it up. if(toDisable == null) { Log.w(DEBUG_TAG, "There's no such zoom button with an ID of " + button + "!"); return; } // But with a button in hand... final View reallyToDisable = toDisable; ((Activity)getContext()).runOnUiThread(new Runnable() { @Override public void run() { reallyToDisable.setEnabled(enabled); } }); } }