48 import android.widget.TableRow; |
48 import android.widget.TableRow; |
49 import android.widget.Toast; |
49 import android.widget.Toast; |
50 |
50 |
51 /** |
51 /** |
52 * Display a map preview, and configuration options for the map. |
52 * Display a map preview, and configuration options for the map. |
53 * |
53 * |
54 * Mostly for layout reasons, this does not include the theme setting, which |
54 * Mostly for layout reasons, this does not include the theme setting, which |
55 * (arguably) is more a map setting than a general game setting. |
55 * (arguably) is more a map setting than a general game setting. |
56 */ |
56 */ |
57 public class MapFragment extends Fragment { |
57 public class MapFragment extends Fragment { |
58 private Spinner mapTypeSpinner, mapNameSpinner, templateSpinner, mazeSizeSpinner; |
58 private Spinner mapTypeSpinner, mapNameSpinner, templateSpinner, mazeSizeSpinner; |
59 private TableRow nameRow, templateRow, mazeSizeRow; |
59 private TableRow nameRow, templateRow, mazeSizeRow; |
60 private ImageView mapPreview; |
60 private ImageView mapPreview; |
61 |
61 |
62 private List<MapFile> mapFiles; |
62 private List<MapFile> mapFiles; |
63 private RoomStateManager stateManager; |
63 private RoomStateManager stateManager; |
64 private Random random = new Random(); |
64 private Random random = new Random(); |
65 private CalmDownHandler mapPreviewHandler; |
65 private CalmDownHandler mapPreviewHandler; |
66 |
66 |
67 /* |
67 /* |
68 * Rendering the preview can take a few seconds on Android, so we want to prevent preview |
68 * Rendering the preview can take a few seconds on Android, so we want to prevent preview |
69 * requests from queueing up if maps are changed quickly. So if there is already a preview |
69 * requests from queueing up if maps are changed quickly. So if there is already a preview |
70 * being generated, we store our latest request in the newPreviewRequest variable instead. |
70 * being generated, we store our latest request in the newPreviewRequest variable instead. |
71 * Once the current preview is finished generating it will start on that one. |
71 * Once the current preview is finished generating it will start on that one. |
72 */ |
72 */ |
73 private boolean previewGenerationInProgress; |
73 private boolean previewGenerationInProgress; |
74 private MapRecipe newPreviewRequest; |
74 private MapRecipe newPreviewRequest; |
75 private MapRecipe currentMap; // kept for reference on every change to find out what changed |
75 private MapRecipe currentMap; // kept for reference on every change to find out what changed |
76 |
76 |
77 @Override |
77 @Override |
78 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { |
78 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { |
79 View v = inflater.inflate(R.layout.fragment_map, container, false); |
79 View v = inflater.inflate(R.layout.fragment_map, container, false); |
80 final Context appContext = getActivity().getApplicationContext(); |
80 final Context appContext = getActivity().getApplicationContext(); |
81 |
81 |
82 /* |
82 /* |
83 * This handler will start the map preview after none of the map settings |
83 * This handler will start the map preview after none of the map settings |
84 * have been updated for a short time. |
84 * have been updated for a short time. |
85 */ |
85 */ |
86 mapPreviewHandler = new CalmDownHandler(getActivity().getMainLooper(), new Runnable() { |
86 mapPreviewHandler = new CalmDownHandler(getActivity().getMainLooper(), new Runnable() { |
87 public void run() { |
87 public void run() { |
88 if(!previewGenerationInProgress) { |
88 if(!previewGenerationInProgress) { |
89 mapPreview.setImageResource(R.drawable.roomlist_preparing); |
89 mapPreview.setImageResource(R.drawable.roomlist_preparing); |
90 MapPreviewGenerator.startPreviewGeneration(appContext, stateManager.getMapRecipe(), mapPreviewListener); |
90 MapPreviewGenerator.startPreviewGeneration(appContext, stateManager.getMapRecipe(), mapPreviewListener); |
91 previewGenerationInProgress = true; |
91 previewGenerationInProgress = true; |
92 } else { |
92 } else { |
93 newPreviewRequest = stateManager.getMapRecipe(); |
93 newPreviewRequest = stateManager.getMapRecipe(); |
94 } |
94 } |
95 } |
95 } |
96 }, 250); |
96 }, 250); |
97 |
97 |
98 nameRow = (TableRow) v.findViewById(R.id.rowMapName); |
98 nameRow = (TableRow) v.findViewById(R.id.rowMapName); |
99 templateRow = (TableRow) v.findViewById(R.id.rowTemplateFilter); |
99 templateRow = (TableRow) v.findViewById(R.id.rowTemplateFilter); |
100 mazeSizeRow = (TableRow) v.findViewById(R.id.rowMazeSize); |
100 mazeSizeRow = (TableRow) v.findViewById(R.id.rowMazeSize); |
101 mapPreview = (ImageView) v.findViewById(R.id.mapPreview); |
101 mapPreview = (ImageView) v.findViewById(R.id.mapPreview); |
102 mapPreview.setImageDrawable(null);; |
102 mapPreview.setImageDrawable(null);; |
103 mapPreview.setOnClickListener(mapClickListener); |
103 mapPreview.setOnClickListener(mapClickListener); |
104 |
104 |
105 try { |
105 try { |
106 mapFiles = FrontendDataUtils.getMaps(getActivity()); |
106 mapFiles = FrontendDataUtils.getMaps(getActivity()); |
107 } catch (IOException e) { |
107 } catch (IOException e) { |
108 Toast.makeText(getActivity().getApplicationContext(), R.string.error_missing_sdcard_or_files, Toast.LENGTH_LONG).show(); |
108 Toast.makeText(getActivity().getApplicationContext(), R.string.error_missing_sdcard_or_files, Toast.LENGTH_LONG).show(); |
109 getActivity().finish(); |
109 getActivity().finish(); |
110 return null; |
110 return null; |
111 } |
111 } |
112 Collections.sort(mapFiles, MapFile.MISSIONS_FIRST_NAME_ORDER); |
112 Collections.sort(mapFiles, MapFile.MISSIONS_FIRST_NAME_ORDER); |
113 |
113 |
114 List<String> mapNames = MapFile.toDisplayNameList(mapFiles, getResources()); |
114 List<String> mapNames = MapFile.toDisplayNameList(mapFiles, getResources()); |
115 mapTypeSpinner = prepareSpinner(v, R.id.spinMapType, Arrays.asList(getResources().getStringArray(R.array.map_types)), mapTypeSelectedListener); |
115 mapTypeSpinner = prepareSpinner(v, R.id.spinMapType, Arrays.asList(getResources().getStringArray(R.array.map_types)), mapTypeSelectedListener); |
116 mapNameSpinner = prepareSpinner(v, R.id.spinMapName, mapNames, mapNameSelectedListener); |
116 mapNameSpinner = prepareSpinner(v, R.id.spinMapName, mapNames, mapNameSelectedListener); |
117 templateSpinner = prepareSpinner(v, R.id.spinTemplateFilter, Arrays.asList(getResources().getStringArray(R.array.map_templates)), mapTemplateSelectedListener); |
117 templateSpinner = prepareSpinner(v, R.id.spinTemplateFilter, Arrays.asList(getResources().getStringArray(R.array.map_templates)), mapTemplateSelectedListener); |
118 mazeSizeSpinner = prepareSpinner(v, R.id.spinMazeSize, Arrays.asList(getResources().getStringArray(R.array.map_maze_sizes)), mazeSizeSelectedListener); |
118 mazeSizeSpinner = prepareSpinner(v, R.id.spinMazeSize, Arrays.asList(getResources().getStringArray(R.array.map_maze_sizes)), mazeSizeSelectedListener); |
119 |
119 |
120 stateManager.addListener(roomStateChangeListener); |
120 stateManager.addListener(roomStateChangeListener); |
121 currentMap = stateManager.getMapRecipe(); |
121 currentMap = stateManager.getMapRecipe(); |
122 if(currentMap != null) { |
122 if(currentMap != null) { |
123 updateDisplay(currentMap); |
123 updateDisplay(currentMap); |
124 } |
124 } |
125 setChiefState(stateManager.getChiefStatus()); |
125 setChiefState(stateManager.getChiefStatus()); |
126 mapPreviewHandler.activity(); |
126 mapPreviewHandler.activity(); |
127 return v; |
127 return v; |
128 } |
128 } |
129 |
129 |
130 private static Spinner prepareSpinner(View v, int id, List<String> items, OnItemSelectedListener itemSelectedListener) { |
130 private static Spinner prepareSpinner(View v, int id, List<String> items, OnItemSelectedListener itemSelectedListener) { |
131 Spinner spinner = (Spinner)v.findViewById(id); |
131 Spinner spinner = (Spinner)v.findViewById(id); |
132 ArrayAdapter<String> adapter = new ArrayAdapter<String>(v.getContext(), R.layout.listview_item, items); |
132 ArrayAdapter<String> adapter = new ArrayAdapter<String>(v.getContext(), R.layout.listview_item, items); |
133 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); |
133 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); |
134 spinner.setAdapter(adapter); |
134 spinner.setAdapter(adapter); |
135 spinner.setOnItemSelectedListener(itemSelectedListener); |
135 spinner.setOnItemSelectedListener(itemSelectedListener); |
136 return spinner; |
136 return spinner; |
137 } |
137 } |
138 |
138 |
139 @Override |
139 @Override |
140 public void onCreate(Bundle savedInstanceState) { |
140 public void onCreate(Bundle savedInstanceState) { |
141 super.onCreate(savedInstanceState); |
141 super.onCreate(savedInstanceState); |
142 try { |
142 try { |
143 stateManager = ((RoomStateManager.Provider)getActivity()).getRoomStateManager(); |
143 stateManager = ((RoomStateManager.Provider)getActivity()).getRoomStateManager(); |
144 } catch(ClassCastException e) { |
144 } catch(ClassCastException e) { |
145 throw new RuntimeException("Hosting activity must implement RoomStateManager.Provider.", e); |
145 throw new RuntimeException("Hosting activity must implement RoomStateManager.Provider.", e); |
146 } |
146 } |
147 } |
147 } |
148 |
148 |
149 @Override |
149 @Override |
150 public void onDestroy() { |
150 public void onDestroy() { |
151 super.onDestroy(); |
151 super.onDestroy(); |
152 mapPreviewHandler.stop(); |
152 mapPreviewHandler.stop(); |
153 newPreviewRequest = null; |
153 newPreviewRequest = null; |
154 |
154 |
155 stateManager.removeListener(roomStateChangeListener); |
155 stateManager.removeListener(roomStateChangeListener); |
156 } |
156 } |
157 |
157 |
158 private void setChiefState(boolean chiefState) { |
158 private void setChiefState(boolean chiefState) { |
159 mapTypeSpinner.setEnabled(chiefState); |
159 mapTypeSpinner.setEnabled(chiefState); |
160 mapNameSpinner.setEnabled(chiefState); |
160 mapNameSpinner.setEnabled(chiefState); |
161 templateSpinner.setEnabled(chiefState); |
161 templateSpinner.setEnabled(chiefState); |
162 mazeSizeSpinner.setEnabled(chiefState); |
162 mazeSizeSpinner.setEnabled(chiefState); |
163 mapPreview.setEnabled(chiefState); |
163 mapPreview.setEnabled(chiefState); |
164 |
164 |
165 if(chiefState) { |
165 if(chiefState) { |
166 sendMapnameAndGenerator(); |
166 sendMapnameAndGenerator(); |
167 stateManager.changeMapTemplate(templateSpinner.getSelectedItemPosition()); |
167 stateManager.changeMapTemplate(templateSpinner.getSelectedItemPosition()); |
168 stateManager.changeMazeSize(mazeSizeSpinner.getSelectedItemPosition()); |
168 stateManager.changeMazeSize(mazeSizeSpinner.getSelectedItemPosition()); |
169 } |
169 } |
170 } |
170 } |
171 |
171 |
172 private void updateDisplay(MapRecipe map) { |
172 private void updateDisplay(MapRecipe map) { |
173 nameRow.setVisibility(map.mapgen == Frontlib.MAPGEN_NAMED ? View.VISIBLE : View.GONE); |
173 nameRow.setVisibility(map.mapgen == Frontlib.MAPGEN_NAMED ? View.VISIBLE : View.GONE); |
174 templateRow.setVisibility(map.mapgen == Frontlib.MAPGEN_REGULAR ? View.VISIBLE : View.GONE); |
174 templateRow.setVisibility(map.mapgen == Frontlib.MAPGEN_REGULAR ? View.VISIBLE : View.GONE); |
175 mazeSizeRow.setVisibility(map.mapgen == Frontlib.MAPGEN_MAZE ? View.VISIBLE : View.GONE); |
175 mazeSizeRow.setVisibility(map.mapgen == Frontlib.MAPGEN_MAZE ? View.VISIBLE : View.GONE); |
176 |
176 |
177 mapTypeSpinner.setSelection(map.mapgen); |
177 mapTypeSpinner.setSelection(map.mapgen); |
178 int mapPosition = findMapPosition(mapFiles, map.name); |
178 int mapPosition = findMapPosition(mapFiles, map.name); |
179 if(mapPosition >= 0) { |
179 if(mapPosition >= 0) { |
180 mapNameSpinner.setSelection(mapPosition); |
180 mapNameSpinner.setSelection(mapPosition); |
181 } |
181 } |
182 templateSpinner.setSelection(map.templateFilter); |
182 templateSpinner.setSelection(map.templateFilter); |
183 mazeSizeSpinner.setSelection(map.mazeSize); |
183 mazeSizeSpinner.setSelection(map.mazeSize); |
184 } |
184 } |
185 |
185 |
186 private static int findMapPosition(List<MapFile> mapFiles, String mapName) { |
186 private static int findMapPosition(List<MapFile> mapFiles, String mapName) { |
187 for(int i=0; i<mapFiles.size(); i++) { |
187 for(int i=0; i<mapFiles.size(); i++) { |
188 if(mapName.equals(mapFiles.get(i).name)) { |
188 if(mapName.equals(mapFiles.get(i).name)) { |
189 return i; |
189 return i; |
190 } |
190 } |
191 } |
191 } |
192 return -1; |
192 return -1; |
193 } |
193 } |
194 |
194 |
195 private void sendMapnameAndGenerator() { |
195 private void sendMapnameAndGenerator() { |
196 int mapType = mapTypeSpinner.getSelectedItemPosition(); |
196 int mapType = mapTypeSpinner.getSelectedItemPosition(); |
197 String mapName = mapFiles.get(mapNameSpinner.getSelectedItemPosition()).name; |
197 String mapName = mapFiles.get(mapNameSpinner.getSelectedItemPosition()).name; |
198 stateManager.changeMapNameAndGenerator(MapRecipe.mapnameForGenerator(mapType, mapName)); |
198 stateManager.changeMapNameAndGenerator(MapRecipe.mapnameForGenerator(mapType, mapName)); |
199 } |
199 } |
200 |
200 |
201 private final OnItemSelectedListener mapTypeSelectedListener = new OnItemSelectedListener() { |
201 private final OnItemSelectedListener mapTypeSelectedListener = new OnItemSelectedListener() { |
202 public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) { |
202 public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) { |
203 sendMapnameAndGenerator(); |
203 sendMapnameAndGenerator(); |
204 } |
204 } |
205 public void onNothingSelected(AdapterView<?> arg0) {} |
205 public void onNothingSelected(AdapterView<?> arg0) {} |
206 }; |
206 }; |
207 |
207 |
208 private final OnItemSelectedListener mapNameSelectedListener = new OnItemSelectedListener() { |
208 private final OnItemSelectedListener mapNameSelectedListener = new OnItemSelectedListener() { |
209 public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) { |
209 public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) { |
210 sendMapnameAndGenerator(); |
210 sendMapnameAndGenerator(); |
211 } |
211 } |
212 public void onNothingSelected(AdapterView<?> arg0) {} |
212 public void onNothingSelected(AdapterView<?> arg0) {} |
213 }; |
213 }; |
214 |
214 |
215 private final OnItemSelectedListener mapTemplateSelectedListener = new OnItemSelectedListener() { |
215 private final OnItemSelectedListener mapTemplateSelectedListener = new OnItemSelectedListener() { |
216 public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) { |
216 public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) { |
217 stateManager.changeMapTemplate(position); |
217 stateManager.changeMapTemplate(position); |
218 } |
218 } |
219 public void onNothingSelected(AdapterView<?> arg0) {} |
219 public void onNothingSelected(AdapterView<?> arg0) {} |
220 }; |
220 }; |
221 |
221 |
222 private final OnItemSelectedListener mazeSizeSelectedListener = new OnItemSelectedListener() { |
222 private final OnItemSelectedListener mazeSizeSelectedListener = new OnItemSelectedListener() { |
223 public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) { |
223 public void onItemSelected(AdapterView<?> adapter, View v, int position, long arg3) { |
224 stateManager.changeMazeSize(position); |
224 stateManager.changeMazeSize(position); |
225 } |
225 } |
226 public void onNothingSelected(AdapterView<?> arg0) {} |
226 public void onNothingSelected(AdapterView<?> arg0) {} |
227 }; |
227 }; |
228 |
228 |
229 private final OnClickListener mapClickListener = new OnClickListener() { |
229 private final OnClickListener mapClickListener = new OnClickListener() { |
230 public void onClick(View v) { |
230 public void onClick(View v) { |
231 stateManager.changeMapSeed(MapRecipe.makeRandomSeed()); |
231 stateManager.changeMapSeed(MapRecipe.makeRandomSeed()); |
232 if(mapTypeSpinner.getSelectedItemPosition() == Frontlib.MAPGEN_NAMED) { |
232 if(mapTypeSpinner.getSelectedItemPosition() == Frontlib.MAPGEN_NAMED) { |
233 mapNameSpinner.setSelection(random.nextInt(mapNameSpinner.getCount())); |
233 mapNameSpinner.setSelection(random.nextInt(mapNameSpinner.getCount())); |
234 } |
234 } |
235 } |
235 } |
236 }; |
236 }; |
237 |
237 |
238 private final RoomStateManager.Listener roomStateChangeListener = new RoomStateManager.ListenerAdapter() { |
238 private final RoomStateManager.Listener roomStateChangeListener = new RoomStateManager.ListenerAdapter() { |
239 @Override |
239 @Override |
240 public void onChiefStatusChanged(boolean isChief) { |
240 public void onChiefStatusChanged(boolean isChief) { |
241 setChiefState(isChief); |
241 setChiefState(isChief); |
242 }; |
242 }; |
243 |
243 |
244 @Override |
244 @Override |
245 public void onMapChanged(MapRecipe recipe) { |
245 public void onMapChanged(MapRecipe recipe) { |
246 // Only trigger a preview update if a relevant field changed (not theme) |
246 // Only trigger a preview update if a relevant field changed (not theme) |
247 if(currentMap==null |
247 if(currentMap==null |
248 || currentMap.mapgen != recipe.mapgen |
248 || currentMap.mapgen != recipe.mapgen |
249 || currentMap.mazeSize != recipe.mazeSize |
249 || currentMap.mazeSize != recipe.mazeSize |
250 || !currentMap.name.equals(recipe.name) |
250 || !currentMap.name.equals(recipe.name) |
251 || !currentMap.seed.equals(recipe.seed) |
251 || !currentMap.seed.equals(recipe.seed) |
252 || currentMap.templateFilter != recipe.templateFilter |
252 || currentMap.templateFilter != recipe.templateFilter |
253 || !Arrays.equals(currentMap.getDrawData(), recipe.getDrawData())) { |
253 || !Arrays.equals(currentMap.getDrawData(), recipe.getDrawData())) { |
254 mapPreviewHandler.activity(); |
254 mapPreviewHandler.activity(); |
255 } |
255 } |
256 updateDisplay(recipe); |
256 updateDisplay(recipe); |
257 currentMap = recipe; |
257 currentMap = recipe; |
258 }; |
258 }; |
259 }; |
259 }; |
260 |
260 |
261 private MapPreviewGenerator.Listener mapPreviewListener = new MapPreviewGenerator.Listener() { |
261 private MapPreviewGenerator.Listener mapPreviewListener = new MapPreviewGenerator.Listener() { |
262 public void onMapPreviewResult(Drawable preview) { |
262 public void onMapPreviewResult(Drawable preview) { |
263 if(newPreviewRequest != null) { |
263 if(newPreviewRequest != null) { |
264 MapPreviewGenerator.startPreviewGeneration(getActivity().getApplicationContext(), newPreviewRequest, mapPreviewListener); |
264 MapPreviewGenerator.startPreviewGeneration(getActivity().getApplicationContext(), newPreviewRequest, mapPreviewListener); |
265 newPreviewRequest = null; |
265 newPreviewRequest = null; |
266 } else { |
266 } else { |
267 if(mapPreview != null) { |
267 if(mapPreview != null) { |
268 mapPreview.setImageDrawable(preview); |
268 mapPreview.setImageDrawable(preview); |
269 } |
269 } |
270 previewGenerationInProgress = false; |
270 previewGenerationInProgress = false; |
271 } |
271 } |
272 } |
272 } |
273 }; |
273 }; |
274 } |
274 } |