From f0e0ffe5186c2217cb131c49b5323514bdf1e2cd Mon Sep 17 00:00:00 2001 From: Victor Date: Wed, 17 Jun 2015 01:42:54 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B9?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=B7=D0=B0=D0=BF=D1=83=D1=81=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=B2=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3=D0=B5=20init.rpy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/init.rpy | 41 +++ .../everlastingsummer/MainActivity.java | 250 +++++++++++++++++- 2 files changed, 280 insertions(+), 11 deletions(-) create mode 100644 assets/init.rpy diff --git a/assets/init.rpy b/assets/init.rpy new file mode 100644 index 0000000..fbc0bb5 --- /dev/null +++ b/assets/init.rpy @@ -0,0 +1,41 @@ +# Сценарий для автозапуска +#rp.scenario = "meet_you_there.rpy" + +# Путь к ресурсам +# sdcard - предустановленный путь к карте памяти, напр. /mnt/sdcard/ +# archive - предустановленный путь к архиву программы (папка assets) +#rp.assets = archive + "everlastingsummer/" +rp.assets = sdcard + "everlastingsummer/" + +# Использовать стартовое меню +rp.menu = false +rp.menu_background = "bg/ext_road_night.jpg" +rp.menu_items = 4 + +rp.menu_item1.text = "Начать" +rp.menu_item1.x = 960 +rp.menu_item1.y = 560 +rp.menu_item1.font = 25 +rp.menu_item1.color = "FFFFFFFF" +rp.menu_item1.action = "meet_you_there.rpy" + +rp.menu_item2.text = "Загрузить" +rp.menu_item2.x = 960 +rp.menu_item2.y = 720 +rp.menu_item2.font = 25 +rp.menu_item2.color = white +rp.menu_item2.action = load + +rp.menu_item3.text = "Выход" +rp.menu_item3.x = 960 +rp.menu_item3.y = 880 +rp.menu_item3.font = 25 +rp.menu_item3.color = white +rp.menu_item3.action = exit + +# используется для вывода текста (action не указан) +rp.menu_item4.text = "v" + version +rp.menu_item4.x = 60 +rp.menu_item4.y = 1000 +rp.menu_item4.font = 16 +rp.menu_item4.color = "7AFFFFFF" # прозрачность 7A \ No newline at end of file diff --git a/src/com/annimon/everlastingsummer/MainActivity.java b/src/com/annimon/everlastingsummer/MainActivity.java index bc229ec..98a9dc0 100644 --- a/src/com/annimon/everlastingsummer/MainActivity.java +++ b/src/com/annimon/everlastingsummer/MainActivity.java @@ -1,26 +1,122 @@ package com.annimon.everlastingsummer; import java.io.IOException; -import android.app.ListActivity; +import java.io.InputStream; +import java.util.List; +import android.app.Activity; +import android.content.DialogInterface; import android.content.Intent; +import android.content.pm.PackageManager.NameNotFoundException; +import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; +import android.util.DisplayMetrics; +import android.util.TypedValue; import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.ListView; -import android.widget.Toast; +import android.widget.*; /** * Экран выбора сценариев из папки assets. * @author aNNiMON */ -public final class MainActivity extends ListActivity { +@SuppressWarnings("deprecation") +public final class MainActivity extends Activity { + + private static final double VIRTUAL_WIDTH = 1920d, VIRTUAL_HEIGHT = 1080d; + private static final String ARCHIVE = "archive://"; + private static final String LOAD = "%load%"; + private static final String EXIT = "%exit%"; private String[] scripts; + private boolean needAlignment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + try { + parseInitConfig(); + } catch (IOException ioe) { + if (Logger.DEBUG) Logger.log("MainActivity", ioe); + scriptListMode(); + } + } + + private void openScenario(String name) { + final Intent intent = new Intent(this, ViewActivity.class); + intent.putExtra(ViewActivity.EXTRA_NAME, name); + startActivity(intent); + } + + private void parseInitConfig() throws IOException { + final InputStream is = getAssets().open("init.rpy"); + final ConfigParser config = ConfigParser.parse(Lexer.tokenize( IOUtil.readContents(is) )); + config.addValue("sdcard", IOUtil.getSdCardPath()); + config.addValue("archive", ARCHIVE); + try { + config.addValue("version", getPackageManager().getPackageInfo(getPackageName(), 0).versionName); + } catch (NameNotFoundException ex) { + if (Logger.DEBUG) Logger.log("version", ex); + } + config.addValue("load", LOAD); + config.addValue("exit", EXIT); + config.addValue("white", "FFFFFFFF"); + config.addValue("black", "FF000000"); + config.parse(); + // Настройка пути к ресурсам + if (config.isValueExists("rp.assets")) { + final String path = config.getValue("rp.assets"); + if (path.startsWith(ARCHIVE)) { + // Возможность работы с ресурсами внутри программы + IOUtil.useArchive = true; + IOUtil.ASSETS = path.substring(ARCHIVE.length()); + } else { + IOUtil.useArchive = false; + IOUtil.ASSETS = path; + } + } + // Автозапуск скрипта + if (config.isValueExists("rp.scenario")) { + finish(); + openScenario(config.getValue("rp.scenario")); + } + // Меню + if (config.getValueAsBoolean("rp.menu")) { + menuMode(config); + } else { + scriptListMode(); + } + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + + if (!needAlignment) return; + + needAlignment = false; + + final RelativeLayout root = (RelativeLayout) findViewById(R.id.root); + if (root == null) return; + + final int childCount = root.getChildCount(); + for (int i = 0; i < childCount; i++) { + final View v = root.getChildAt(i); + if (v instanceof Button) { + final Button button = (Button) v; + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) button.getLayoutParams(); + params.leftMargin -= button.getWidth() / 2; + params.topMargin -= button.getHeight() / 2; + } + } + } + + + /* + * Выбор скриптов из списка в папке assets/scripts + */ + private void scriptListMode() { + needAlignment = false; + final ListView list = new ListView(this); try { scripts = getAssets().list(PathResolver.SCRIPT_ASSETS); } catch (IOException ioe) { @@ -31,13 +127,145 @@ public final class MainActivity extends ListActivity { Toast.LENGTH_LONG).show(); finish(); } - setListAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, scripts)); + list.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, scripts)); + list.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + openScenario(scripts[position]); + } + }); + setContentView(list); } - @Override - protected void onListItemClick(ListView l, View v, int index, long id) { - final Intent intent = new Intent(this, ViewActivity.class); - intent.putExtra(ViewActivity.EXTRA_NAME, scripts[index]); - startActivity(intent); + /* + * Парсинг и показ меню с пунктами в конфиге init.rpy + */ + private void menuMode(ConfigParser config) { + needAlignment = true; + // Полноэкранный режим + setTheme(R.style.FullscreenTheme); + // Размеры экрана для правильного позиционирования элементов + final DisplayMetrics displaymetrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(displaymetrics); + final int width = displaymetrics.widthPixels; + final int height = displaymetrics.heightPixels; + + setContentView(R.layout.launcher); + if (config.isValueExists("rp.menu_background")) { + final ImageView background = (ImageView) findViewById(R.id.background); + try { + // IOUtil обращается к ViewActivity при useArchive, что приведёт к NPE + // поэтому загружаем вручную + if (IOUtil.useArchive) { + background.setImageDrawable(new BitmapDrawable( getResources(), + getAssets().open(IOUtil.ASSETS + config.getValue("rp.menu_background")) + )); + } else { + background.setImageBitmap(IOUtil.readBitmap(config.getValue("rp.menu_background"))); + } + } catch (IOException ioe) { + Logger.log("menu background", ioe); + } + } + + final RelativeLayout root = (RelativeLayout) findViewById(R.id.root); + final int items = (int) config.getValueAsDouble("rp.menu_items"); + for (int i = 0; i < items; i++) { + parseMenuItem(config, root, width, height, i+1); + } } + + private void parseMenuItem(ConfigParser config, RelativeLayout root, int width, int height, int index) { + final String key = "rp.menu_item" + index + "."; + + final Button button = new Button(this); + button.setBackgroundDrawable(null); + + // текст + if (config.isValueExists(key + "text")) { + button.setText(config.getValue(key + "text")); + } + // шрифт + if (config.isValueExists(key + "font")) { + button.setTextSize(TypedValue.COMPLEX_UNIT_DIP, (float)config.getValueAsDouble(key + "font")); + } + // цвет текста + if (config.isValueExists(key + "color")) { + button.setTextColor(parseColor(config.getValue(key + "color"))); + } + + // позиция + final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( + RelativeLayout.LayoutParams.WRAP_CONTENT, + RelativeLayout.LayoutParams.WRAP_CONTENT); + params.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE); + params.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE); + if (config.isValueExists(key + "x")) { + final double x = config.getValueAsDouble(key + "x"); + params.leftMargin = (int)(x * width / VIRTUAL_WIDTH); + } + if (config.isValueExists(key + "y")) { + final double y = config.getValueAsDouble(key + "y"); + params.topMargin = (int)(y * height / VIRTUAL_HEIGHT); + } + + // действие + if (config.isValueExists(key + "action")) { + final String action = config.getValue(key + "action"); + if (LOAD.equalsIgnoreCase(action)) { + button.setOnClickListener(loadListener); + } else if (EXIT.equalsIgnoreCase(action)) { + button.setOnClickListener(exitListener); + } else { + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + openScenario(action); + } + }); + } + } + + root.addView(button, params); + } + + private int parseColor(String value) { + try { + return (int) Long.parseLong(value, 16); + } catch (NumberFormatException nfe) { + return 0xFF000000; + } + } + + private void showLoadStateDialog() { + final List saves = IOUtil.listSaves(getApplicationContext()); + if (saves == null || saves.isEmpty()) { + Toast.makeText(this, R.string.no_saves, Toast.LENGTH_SHORT).show(); + return; + } + Dialogs.with(this).showSaves(saves, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + final SaveInfo save = saves.get(which); + // Пересоздаём активити + final Intent intent = new Intent(MainActivity.this, ViewActivity.class); + intent.putExtra(ViewActivity.EXTRA_SAVE, save); + startActivity(intent); + } + }); + } + + private final View.OnClickListener loadListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + showLoadStateDialog(); + } + }; + + private final View.OnClickListener exitListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }; }