diff --git a/ReadMe.txt b/ReadMe.txt index 3d50ed4..a31c0b9 100644 --- a/ReadMe.txt +++ b/ReadMe.txt @@ -13,15 +13,12 @@ NOT WORKING - Serial Ports (Wire or Ir) TODO -- Add help and about -- Change KML - Support 8bits images - Put the KML title in the header of the menu in the drawer - Bug: No refresh with the clock - Option to allow rotation - Option to auto hide the menu - Bitmap corruption when touching the buttons -- Android UI Settings - Sound DONE @@ -30,6 +27,9 @@ DONE - Choose KML/Change KML/NewDocument - Load/Save object - Permission issues when reopening document after an OS restart +- Android UI Settings - Change settings per settings - Add icons - Autosave +- Add help and about +- Change KML diff --git a/app/build.gradle b/app/build.gradle index 58938d3..26df7bb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -33,6 +33,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.1.0-alpha01' implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2' implementation 'com.google.android.material:material:1.1.0-alpha01' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' // testImplementation 'junit:junit:4.12' // androidTestImplementation 'com.android.support.test:runner:1.0.2' // androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2fef573..27524ed 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,7 +20,6 @@ android:theme="@style/AppTheme.NoActionBar"> - @@ -33,6 +32,20 @@ android:name="android.support.PARENT_ACTIVITY" android:value="com.regis.cosnier.emu48.MainActivity"/> + + + + + + + + + +Emu48 Manual + + + + + + + +
+

Emu48 - A freeware HP38G/39G/40G/48SX/48GX/49G Emulator
+ for Windows 9x, ME, NT, 2000, XP, Vista, 7, 8 and 10

+
+ +
+

1. General

+

Emu48 is an emulator for the Hewlett Packard HP38G, HP39G, + HP40G, HP48SX, HP48GX and HP49G calculator hardware. These calculators + are based on the 1LT8 Clarke (HP48SX) and on the Yorke chip.

+

2. Acknowledgements

+

First of all a big thank to Sébastien Carlier for publishing + Emu48 v1.0 under the GPL. Without this decision newer versions of the + emulator wouldn't have been possible or ports to other similar + calculators wouldn't have been made. Also a big thank to Jean-Yves + Avenard for his technical assistance in the beginning. Lode Vandevenne + spend the PNG image decoder and finally I want to thank all the + unnamed authors for publishing material about these calculators.

+

3. ROM Images

+

Emu48 needs an image of a calculator ROM to be able to run. ROM + images are valid in a packed (even address lower nibble, odd address + higher nibble) or unpacked (one nibble per byte with even address first) + form.

+

Since fall 2000 the emulator ROM's for the HP38, 39, 40, 48 and 49 + are freely available on different Internet sites. Because there's no + license for the distribution of the ROM images, they aren't included + in the Emu48 package. You can still use the classic way extracting + them from your own calculator. But in mostly all cases you have to + convert the ROM files into the Emu48 ROM format.

+ +

4. Installation

+

To install Emu48 you may use the installer package which contain, + among the binaries, some HP48 KML scripts or just unzip the emulator + and the required emulator skins from archives into an empty directory. + Finally you have to copy your ROM images into this directory and + adjust the ROM image name to the name used in the corresponding KML + script. When you first run Emu48, it will detect the directory in + which you installed it, and will write the configuration to the + registry at HKCU\Software\Emu48.

+

5. How to Start

+

When Emu48 is installed and you have put valid KML scripts and the + corresponding ROM image(s) into your Emu48 installation directory, you + can start Emu48. You'll see a "Choose Your KML Script" + box.

+

KML scripts in fact define the visual aspect of Emu48, the behavior of + the buttons, of the keyboard, ... It's a GREAT way to customize your copy + of Emu48.

+

Check that the path in the "Emu48 Directory" text area is + correct. Modify it if the directory in which you installed Emu48 is not + the directory displayed. Click the refresh button ("V") after + modifying it to update the list box or use the ("...") button to + start the directory browser.

+

Choose a KML script in the list box for your calculator ROM you put + into Emu48's directory.

+

Several HP48 scripts are included in the Emu48 archive:

+ +

If you want other great scripts, visit Rechlin's great HP archive +

+

And if you are interested in writing new scripts, get the KML 2.0 + documentation from the + authors Emu48 page.

+

Once you have selected a script, press OK to start the emulator. In + most cases, when Emu48 crash after pressing the OK button, you are using + an invalid ROM image. While it's running, you can use the View/Change KML + Script... command to change the visual aspect of Emu48.

+

6. Command Line

+

The command line syntax is "Emu48 [E48file [Port2file]]". + The first parameter sets the filename for the emulation data + independent from the "LastDocument" setting, the second + parameter the Port2 file. You're not able to set a Port 2 file without + setting the emulation data file. The arguments are optional.

+

7. Virtual Keyboard

+

There are two ways to use the virtual keyboard on the emulated + calculator:

+
    +
  1. by Mouse
  2. +
  3. by PC keyboard
  4. +
+

+ The easiest way to use the emulated calculator is using the mouse. The KML + script define buttons with an area where mouse input is active. The mouse + cursor change from an arrow to a hand cursor in these areas. The state of + the virtual key follow the state of your left mouse button. When the mouse + cursor leaves the virtual key area the virtual button automatically + release. In some cases you need to press more than one key on the + emulator. For these cases press the virtual key with the right mouse + button. When you release the mouse button or leave the area of the virtual + key, the key is still hold. To release all hold virtual buttons, just use + the left mouse button again. A single release of a hold virtual key isn't + possible.

+

+ Another convenient way is using the PC keyboard. The KML script language + support a large variety of commands to implement this feature. So keyboard + usage depends on your used KML script and not on the emulator. Because of + this it's impossible to say what's happen when you press a key on the PC + keyboard. For further details read the KML 2.0 documentation mentioned + before please.

+

8. File Menu

+

8.1 New...

+

Creates a new emulation session. You're asked for a new KML script + where you can select the calculator type and skin to emulate.

+

8.2 Open...

+

Opens an existing emulation session. The emulation continues at the + same position where the loaded session was aborted. Loading emulation + sessions made with a different ROM revision may destroy the memory + content or may cause other unpredictable results.

+

8.3 Save

+

Saves the current running session with the actual name.

+

8.4 Save As...

+

Saves the current running session with a new name. You're also get in + this dialog when you Exit a new session without a state file name.

+

8.5 Close

+

Closes the current session without closing the emulator.

+

8.6 Settings

+

This calls the Settings dialog. This dialog has three tabs: + General, Memory and Peripheral.

+

8.6.1 Settings General

+

8.6.1.1 Section General

+ +

8.6.1.2 Section Style

+ +

8.6.1.3 Section Disassembler

+

Choosing the assembler syntax:

+ +

8.6.2 Settings Memory

+

8.6.2.1 Section Memory Cards

+ +

8.6.3 Settings Peripheral

+

8.6.3.1 Section Sound

+

A new implementation of the sound engine made ROM patches for sound + output obsolete. The new sound engine emulates the behavior of the beeper + output ports and only work in connection with a sound card. Using the + internal PC speaker isn't possible any more. The old beeper method with a + ROM patch is still working but deprecated, it's strongly recommended to + remove all beep patches from your current KML scripts to enable the new + sound engine. The support of the old sound implementation by a ROM patch + maybe removed in later versions of the emulator and remaining beep + patches will corrupt the ROM with an illegal opcode then. +

+

+ For the sound generation the calculator must know his own CPU strobe + frequency. On the real calculator the speed depends on various settings + like component tolerances, actual temperature, humidity and other + variables. The resulting speed is measured by the calculator firmware + at a cold- or at a warmstart and stored in the =CSPEED variable. The + content of this calculator variable has direct influence on the + resulting frequency and duration. On the emulator the HP48SX CPU + strobe frequency is set by the registry key + HKCU\Software\Emu48\Emulator\SXCycles, for all other + calculators at HKCU\Software\Emu48\Emulator\GXCycles. + For some reasons the CPU cycles are only estimated and so the + strobe frequency value in the registry is not the exact CPU strobe + frequency of the calculator in Hz divided by 16384 like in the + other emulators. Because older versions of the emulator were not + able to measure the CPU strobe frequency properly or the strobe + frequency registry content has been changed since the last + measurement, the =CSPEED variable of this session file may contain + a wrong frequency value. You easily may discover this by measuring + the real duration of a 10s beep. Is the difference to 10s less + than 1s everything is ok, if not, you should perform a + warmstart of the calculator in this + session file. Alternatively you may execute a + Reset Calculator. This recalls the measuring + routine and save the result in the speed variable. Both restart + variants purge the stack content! +

+ +

8.6.3.2 Section Infrared Printer

+

The emulator has the ability to print data to a HP82240A/B printer + simulation. The data transfer to the printer simulator is done over UDP. + In this section you can the define the IPv4 address and the port the + printer simulator is listening. A suitable HP82240B printer simulation can + be found here.

+

8.6.3.3 Section Serial Ports

+ +

8.7 Exit

+

Quit emulation. The default actions at finishing are defined in the + Settings dialog. If the current session is + "Untitled" you are asked for a session file name using the + Save As... dialog. If you quit the emulator + without a given filename, you're asked for choosing a KML script at + next startup.

+

9. Edit Menu

+

9.1 Load Object...

+

This is only valid for the HP48SX, HP48GX and the HP49G emulation. + You can load HP48 and HP49G binary objects to stack level 1. Therefore + the object must begin with "HPHP48-x" for a HP48 or with + "HPHP49-x" for a HP49G binary object where x can be any + alphanumeric character. If the binary header isn't present, the object + is loaded as string. Dropping HP objects over the emulator window will + also load objects. Be sure that the emulator isn't busy before doing + this.

+

9.2 Save Object...

+

This is only valid for the HP48SX, HP48GX and the HP49G emulation. + Save the current object in stack level 1 as binary object to disk.

+

9.3 Copy Screen

+

Copy the screen content as bitmap to the clipboard.

+

9.4 Copy Stack

+

This is only valid for the HP48SX, HP48GX and the HP49G emulation.

+

Copy a "Real Number", "Complex Number" or + "String" object in stack level 1 to the clipboard. On all + other objects, the command will be ignored. This prevents sending + binary objects to the clipboard.

+

The decimal point (radix mark) of "Real Numbers" in the + clipboard is equal to the calculator setting. This point maybe + important when you try to paste the numbers into a program using the + locale settings of the host operating system.

+

9.5 Paste Stack

+

This is only valid for the HP48SX, HP48GX and the HP49G emulation.

+

Paste the text field content of the clipboard to stack level 1 of + the emulated calculator. If the clipboard content is representing a + real number, the number will be saved as "Real Number" + object. Is the content a complex number object, the number will be + saved as "Complex Number" object, in all other cases as + "String" object.

+

To import "Real or Complex Numbers" from the clipboard, + the decimal point (radix mark) of the clipboard and calculator + must be equal. A real or complex number is only detected in the + case of valid real number characters in the clipboard. Especially + heading and tailing white spaces aren't valid number characters + also.

+

Complex numbers must be in the form (a,b) when using the + point radix mark or in the form (a;b) when using the comma + radix mark. The Cartesian or algebraic form a+bi is not + supported.

+

9.6 Reset Calculator

+

This emulates the Reset pin of the internal CPU.

+

9.7 Backup

+

9.7.1 Backup Save

+

This saves the current emulator status into a backup slot. If the + backup slot already contain data, it will be overwritten.

+

9.7.2 Backup Restore

+

This restores a previous saved emulator status without request. If you + changed the calculator model meanwhile, the emulator will switch back to + the old model.

+

9.7.3 Backup Delete

+

This deletes the data in the backup slot.

+

10. View Menu

+

10.1 Change KML Script...

+

This allows you to change the skin of the current emulated calculator. + In opposite to the New... command you see only scripts emulating the same + calculator model.

+

11. Tools Menu

+

11.1 Disassembler...

+

This is a simple disassembler.

+

Enter the address to disassemble in hexadecimal into the "Address + (HEX)" field and press <Return>. With the "Next Address" + button the next opcode is disassembled. With the "Copy Data" button + you can copy all selected lines inside the list box to the clipboard.

+

11.2 Debugger...

+

The assembler code debugger of the emulator. For more details refer to the + extra documentation of the debugger please.

+

11.3 Macro

+

The keyboard macro recorder unit.

+

11.3.1 Macro Record...

+

Prompts a dialog to enter the macro file for the data to record. After + accepting the confirm message, every key event is recorded into the macro + file with it's time information.

+

11.3.2 Macro Play...

+

Prompts a dialog box to ask for the keyboard macro file to play. The + replay starts immediately after selecting the file.

+

11.3.3 Macro Stop

+

Stops recording or replaying a keyboard macro file.

+

11.3.4 Macro Settings...

+

Settings for the Macro Replay mode

+ +

12. Help Menu

+

12.1 Help Topics

+

Call this document.

+

12.2 About Emu48...

+

The version, copyright and license message...

+

13. DDE Server

+

Emu48 has an integrated DDE server to transmit data from and to the HP + stack. Because only the HP48 and HP49 have a stack, all DDE transfers + are ignored on the other calculators. You have the same restrictions like + with the commands "Load object..." and "Save + Object...", that a running program may corrupt memory. In difference + you can choose the stack level for the transfer in the DDE item field. + Take care to transmit data only after the acknowledge of the last DDE + transaction.

+

Technical data:

+ + + + + + + + + + + + + + + + + +
Servicename:Emu48
Topicname:Stack
Item:1 (stack level)
Clipboardformat:"CF_HPOBJ" (user defined)
+

The DDE commands CONNECT, POKE and REQUEST are supported.

+

The structure of the clipboard format "CF_HPOBJ":

+ + + + + +
4 Byte (length of object, LSB first)HP object (normal HP object)
+

14. License

+

Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator
+ Copyright (C) 2018 Christoph Gießelink

+

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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

+
+ + diff --git a/app/src/main/assets/ReadMe.txt b/app/src/main/assets/ReadMe.txt new file mode 100644 index 0000000..ce7dd26 --- /dev/null +++ b/app/src/main/assets/ReadMe.txt @@ -0,0 +1,97 @@ +This application transforms an image into a painting by numbers. + +DESCRIPTION + +This application allows you to turn any photograph to a ready to paint printable canvas. Once printed on a real canvas, you just have to paint the numbered areas with the matching colors in your palette. + +The advanced version allows: +- To edit the palette. +- To access to the advanced parameters. +- To manage several projects. +- To export the result in a SVG, PNG or JPG file. + + +QUICK START + +1. Touch the top left button and select "Open a new image". +2. The image is analyzed and should appear with the numbered areas. +3. To check the result, you can zoom with two fingers or pan with one. +4. The top right button opens the parameters panel which allows changing the number of color, the size of the numbers, etc... +5. To print the result, touch the top left button and select "Export to PDF". + + +NOTES + +- It is recommended to choose images with less detail as possible. Increasing the blur power helps to reduce the details. +- You can also use the application with a mouse. + + +PERMISSIONS + +- WRITE_EXTERNAL_STORAGE is required to read images, to write the PDF/SVG/PNG/JPG files (/sdcard/Documents/PaintByNumbers) and save the last state of the application (/sdcard/.paintByNumbers/). + + +REQUIREMENTS + +Android device version 4.0 or later. + + +CHANGES + +Version 2.0 (2018-06-21) + +- Allow to use up to 75 colors in the palette. +- Add a undo change color in the color and image palette editor. +- Replace the bottom Cancel/Help/Save button with a standard actionbar in the palette editor. +- Add a PDF page format selection (A4/A3/Letter...) +- Change the folder where are the images of the project. +- Update with the latest APIs. +- Fix the image openning from another app. +- Fix the duplicate project entries. + +Version 1.9 (2016-07-11) + +- Request the permission to read and write on the sdcard to save the projects. +- Drastically improve the performances by updating third-party libraries. +- Migrate some operations to native code which reduce the size of the application. +- Displays the color in HTML format in the RGB palette editor. +- Fix a concurrency issue when viewing or exporting. + +Version 1.8 (2015-10-24) + +- Fix the bad location of the numbers in the SVG palette. +- Fix bad label "10" width seen as only one character length. +- Improve the number placement algorithm. +- Add a progress bar for the build of the vectors. + +Version 1.6 (2015-06-21) + +- Add the possibility to open an image from another applications. +- Improve the performances. +- Fix gallery access bug with Google Photos on Android version 5.1. +- Fix gallery access bug on Android version < 4.4. +- Fix badly saved palette after the editon of the colors. + +Version 1.5 (2015-03-15) + +- Add the export to JPG and PNG image. + +Version 1.1 (2014-11-02) + +- Fix the badly loaded project. +- Improve the trace algorithm. + +Version 1.0 (2014-09-14) + +- First public version available on the store. + + +LICENSES + +Copyright (c) Regis COSNIER, All Rights Reserved. + +A screenshots are a derivative of: +- "Rose laser" by T.Kiya, used under CC BY-SA 2.0 +- "Puppy" by DM.Sumon, used under CC BY 2.0 +- "Burano island" by A.Onufrienko, used under CC BY 2.0 +- "Brandy Alexander" by A.Valli, used under CC BY 2.0 diff --git a/app/src/main/cpp/core/pch.h b/app/src/main/cpp/core/pch.h index 19e3c7d..3081251 100644 --- a/app/src/main/cpp/core/pch.h +++ b/app/src/main/cpp/core/pch.h @@ -31,9 +31,9 @@ #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) extern void mainViewUpdateCallback(); extern void mainViewResizeCallback(int x, int y); -extern int mainViewGetOpenFileNameCallback(OPENFILENAME * ofn); -extern int mainViewGetSaveFileNameCallback(OPENFILENAME * ofn); extern int openFileFromContentResolver(const TCHAR * url, int writeAccess); +extern int showAlert(const TCHAR * messageText, int flags); + #if !defined VERIFY diff --git a/app/src/main/cpp/emu48-jni.c b/app/src/main/cpp/emu48-jni.c index b6c75d9..32cc2c8 100644 --- a/app/src/main/cpp/emu48-jni.c +++ b/app/src/main/cpp/emu48-jni.c @@ -10,6 +10,7 @@ #include "core/pch.h" #include "core/Emu48.h" #include "core/io.h" +#include "core/kml.h" extern void emu48Start(); extern AAssetManager * assetManager; @@ -106,6 +107,16 @@ int openFileFromContentResolver(const TCHAR * url, int writeAccess) { return result; } +// Must be called in the main thread +int showAlert(const TCHAR * messageText, int flags) { + JNIEnv *jniEnv = getJNIEnvironment(); + jclass mainActivityClass = (*jniEnv)->GetObjectClass(jniEnv, mainActivity); + jmethodID midStr = (*jniEnv)->GetMethodID(jniEnv, mainActivityClass, "showAlert", "(Ljava/lang/String;)V"); + jstring messageUTF = (*jniEnv)->NewStringUTF(jniEnv, messageText); + (*jniEnv)->CallIntMethod(jniEnv, mainActivity, midStr, messageUTF); + return IDOK; +} + JNIEXPORT void JNICALL Java_com_regis_cosnier_emu48_NativeLib_start(JNIEnv *env, jobject thisz, jobject assetMgr, jobject bitmapMainScreen0, jobject activity, jobject view) { @@ -228,6 +239,10 @@ JNIEXPORT jint JNICALL Java_com_regis_cosnier_emu48_NativeLib_getCurrentModel(JN return cCurrentRomType; } +JNIEXPORT jboolean JNICALL Java_com_regis_cosnier_emu48_NativeLib_isBackup(JNIEnv *env, jobject thisz) { + return bBackup ? JNI_TRUE : JNI_FALSE; +} + JNIEXPORT jstring JNICALL Java_com_regis_cosnier_emu48_NativeLib_getKMLLog(JNIEnv *env, jobject thisz) { jstring result = (*env)->NewStringUTF(env, szKmlLog); return result; @@ -452,6 +467,72 @@ JNIEXPORT void JNICALL Java_com_regis_cosnier_emu48_NativeLib_onViewReset(JNIEnv OnViewReset(); } +JNIEXPORT void JNICALL Java_com_regis_cosnier_emu48_NativeLib_onViewScript(JNIEnv *env, jobject thisz, jstring kmlFilename) { + + TCHAR szKmlFile[MAX_PATH]; + BOOL bKMLChanged,bSucc; + BYTE cType = cCurrentRomType; + SwitchToState(SM_INVALID); + + const char *filenameUTF8 = (*env)->GetStringUTFChars(env, kmlFilename , NULL) ; + _tcscpy(szCurrentKml, filenameUTF8); + (*env)->ReleaseStringUTFChars(env, kmlFilename, filenameUTF8); + + // make a copy of the current KML script file name + _ASSERT(sizeof(szKmlFile) == sizeof(szCurrentKml)); + lstrcpyn(szKmlFile,szCurrentKml,ARRAYSIZEOF(szKmlFile)); + + bKMLChanged = FALSE; // KML script not changed + bSucc = TRUE; // KML script successful loaded + +// do +// { +// if (!DisplayChooseKml(cType)) // quit with Cancel +// { +// if (!bKMLChanged) // KML script not changed +// break; // exit loop with current loaded KML script +// +// // restore KML script file name +// lstrcpyn(szCurrentKml,szKmlFile,ARRAYSIZEOF(szCurrentKml)); +// +// // try to restore old KML script +// if ((bSucc = InitKML(szCurrentKml,FALSE))) +// break; // exit loop with success +// +// // restoring failed, save document +// if (IDCANCEL != SaveChanges(bAutoSave)) +// break; // exit loop with no success +// +// _ASSERT(bSucc == FALSE); // for continuing loop +// } +// else // quit with Ok +// { + bKMLChanged = TRUE; // KML script changed + bSucc = InitKML(szCurrentKml,FALSE); +// } +// } +// while (!bSucc); // retry if KML script is invalid + + if (bSucc) + { + if (Chipset.wRomCrc != wRomCrc) // ROM changed + { + CpuReset(); + Chipset.Shutdn = FALSE; // automatic restart + + Chipset.wRomCrc = wRomCrc; // update current ROM fingerprint + } + if (pbyRom) SwitchToState(SM_RUN); // continue emulation + } + else + { + ResetDocument(); // close document + SetWindowTitle(NULL); + } + mainViewResizeCallback(nBackgroundW, nBackgroundH); + draw(); +} + JNIEXPORT void JNICALL Java_com_regis_cosnier_emu48_NativeLib_onBackupSave(JNIEnv *env, jobject thisz) { OnBackupSave(); } @@ -464,135 +545,6 @@ JNIEXPORT void JNICALL Java_com_regis_cosnier_emu48_NativeLib_onBackupDelete(JNI OnBackupDelete(); } -//JNIEXPORT void JNICALL Java_com_regis_cosnier_emu48_NativeLib_setConfiguration(JNIEnv *env, jobject thisz, -// jint settingsRealspeed, jint settingsGrayscale, jint settingsAutosave, -// jint settingsAutosaveonexit, jint settingsObjectloadwarning, jint settingsAlwaysdisplog, -// jint settingsPort1en, jint settingsPort1wr, -// jint settingsPort2len, jint settingsPort2wr, jstring settingsPort2load) { -// -// bRealSpeed = settingsRealspeed; -// bAutoSave = settingsAutosave; -// bAutoSaveOnExit = settingsAutosaveonexit; -// bLoadObjectWarning = settingsObjectloadwarning; -// bAlwaysDisplayLog = settingsAlwaysdisplog; -// -// SetSpeed(bRealSpeed); // set speed -// -// // LCD grayscale checkbox has been changed -// if (bGrayscale != (BOOL)settingsGrayscale) { -// UINT nOldState = SwitchToState(SM_INVALID); -// SetLcdMode(!bGrayscale); // set new display mode -// SwitchToState(nOldState); -// } -// -// //SettingsMemoryProc -// LPCTSTR szActPort2Filename = _T(""); -// -// BOOL bPort2CfgChange = FALSE; -// BOOL bPort2AttChange = FALSE; -// -// // port1 -// if (Chipset.Port1Size && (cCurrentRomType!='X' || cCurrentRomType!='2' || cCurrentRomType!='Q')) // CdB for HP: add apples -// { -// UINT nOldState = SwitchToState(SM_SLEEP); -// // save old card status -// BYTE byCardsStatus = Chipset.cards_status; -// -// // port1 disabled? -// Chipset.cards_status &= ~(PORT1_PRESENT | PORT1_WRITE); -// if (settingsPort1en) -// { -// Chipset.cards_status |= PORT1_PRESENT; -// if (settingsPort1wr) -// Chipset.cards_status |= PORT1_WRITE; -// } -// -// // changed card status in slot1? -// if ( ((byCardsStatus ^ Chipset.cards_status) & (PORT1_PRESENT | PORT1_WRITE)) != 0 -// && (Chipset.IORam[CARDCTL] & ECDT) != 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0 -// ) -// { -// Chipset.HST |= MP; // set Module Pulled -// IOBit(SRQ2,NINT,FALSE); // set NINT to low -// Chipset.SoftInt = TRUE; // set interrupt -// bInterrupt = TRUE; -// } -// SwitchToState(nOldState); -// } -// // HP48SX/GX port2 change settings detection -// if (cCurrentRomType=='S' || cCurrentRomType=='G' || cCurrentRomType==0) -// { -// //bPort2IsShared = settingsPort2isshared; -// const char * szNewPort2Filename = NULL; -// const char *settingsPort2loadUTF8 = NULL; -// if(settingsPort2load) { -// settingsPort2loadUTF8 = (*env)->GetStringUTFChars(env, settingsPort2load , NULL); -// szNewPort2Filename = settingsPort2loadUTF8; -// } else -// szNewPort2Filename = _T("SHARED.BIN"); -// -// if(_tcscmp(szPort2Filename, szNewPort2Filename) != 0) { -// _tcscpy(szPort2Filename, szNewPort2Filename); -// szActPort2Filename = szPort2Filename; -// bPort2CfgChange = TRUE; // slot2 configuration changed -// -// // R/W port -// if ( *szActPort2Filename != 0 -// && (BOOL) settingsAlwaysdisplog != bPort2Writeable) -// { -// bPort2AttChange = TRUE; // slot2 file R/W attribute changed -// bPort2CfgChange = TRUE; // slot2 configuration changed -// } -// } -// if(settingsPort2loadUTF8) -// (*env)->ReleaseStringUTFChars(env, settingsPort2load, settingsPort2loadUTF8); -// } -// -// if (bPort2CfgChange) // slot2 configuration changed -// { -// UINT nOldState = SwitchToState(SM_INVALID); -// -// UnmapPort2(); // unmap port2 -// -//// if (bPort2AttChange) // slot2 R/W mode changed -//// { -//// DWORD dwFileAtt; -//// -//// SetCurrentDirectory(szEmuDirectory); -//// dwFileAtt = GetFileAttributes(szActPort2Filename); -//// if (dwFileAtt != 0xFFFFFFFF) -//// { -//// if (IsDlgButtonChecked(hDlg,IDC_PORT2WR)) -//// dwFileAtt &= ~FILE_ATTRIBUTE_READONLY; -//// else -//// dwFileAtt |= FILE_ATTRIBUTE_READONLY; -//// -//// SetFileAttributes(szActPort2Filename,dwFileAtt); -//// } -//// SetCurrentDirectory(szCurrentDirectory); -//// } -// -// if (cCurrentRomType) // ROM defined -// { -// MapPort2(szActPort2Filename); -// -// // port2 changed and card detection enabled -// if ( (bPort2AttChange || Chipset.wPort2Crc != wPort2Crc) -// && (Chipset.IORam[CARDCTL] & ECDT) != 0 && (Chipset.IORam[TIMER2_CTRL] & RUN) != 0 -// ) -// { -// Chipset.HST |= MP; // set Module Pulled -// IOBit(SRQ2,NINT,FALSE); // set NINT to low -// Chipset.SoftInt = TRUE; // set interrupt -// bInterrupt = TRUE; -// } -// // save fingerprint of port2 -// Chipset.wPort2Crc = wPort2Crc; -// } -// SwitchToState(nOldState); -// } -//} - JNIEXPORT void JNICALL Java_com_regis_cosnier_emu48_NativeLib_setConfiguration(JNIEnv *env, jobject thisz, jstring key, jint isDynamic, jint intValue1, jint intValue2, jstring stringValue) { const char *configKey = (*env)->GetStringUTFChars(env, key, NULL) ; const char *configStringValue = stringValue ? (*env)->GetStringUTFChars(env, stringValue, NULL) : NULL; @@ -734,6 +686,11 @@ JNIEXPORT jboolean JNICALL Java_com_regis_cosnier_emu48_NativeLib_isPortExtensio return (cCurrentRomType=='S' || cCurrentRomType=='G' || cCurrentRomType==0 ? JNI_TRUE : JNI_FALSE); } +JNIEXPORT jint JNICALL Java_com_regis_cosnier_emu48_NativeLib_getState(JNIEnv *env, jobject thisz) { + return nState; +} + + //p Read5(0x7050E) // -> $1 = 461076 //p Read5(0x70914) diff --git a/app/src/main/cpp/win32-layer.c b/app/src/main/cpp/win32-layer.c index 36bee2c..fefcb58 100644 --- a/app/src/main/cpp/win32-layer.c +++ b/app/src/main/cpp/win32-layer.c @@ -593,11 +593,9 @@ HGLOBAL WINAPI GlobalFree(HGLOBAL hMem) { } BOOL GetOpenFileName(LPOPENFILENAME openFilename) { - //return mainViewGetOpenFileNameCallback(openFilename); return FALSE; } BOOL GetSaveFileName(LPOPENFILENAME openFilename) { - //return mainViewGetSaveFileNameCallback(openFilename); return FALSE; } @@ -618,7 +616,7 @@ BOOL PostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { int MessageBox(HANDLE h, LPCTSTR szMessage, LPCTSTR title, int flags) { - int result = IDOK; +// int result = IDOK; //#if !TARGET_OS_IPHONE // NSAlert *alert = [[NSAlert alloc] init]; // [alert setMessageText: NSLocalizedString([NSString stringWithUTF8String: szMessage],@"")]; @@ -654,7 +652,8 @@ int MessageBox(HANDLE h, LPCTSTR szMessage, LPCTSTR title, int flags) // result = NSAlertFirstButtonReturn ? IDYES : // NSAlertSecondButtonReturn ? IDCANCEL : IDNO; //#endif - return result; + + return showAlert(szMessage, flags); } DWORD timeGetTime(void) diff --git a/app/src/main/java/com/regis/cosnier/emu48/InfoActivity.java b/app/src/main/java/com/regis/cosnier/emu48/InfoActivity.java new file mode 100644 index 0000000..d543b90 --- /dev/null +++ b/app/src/main/java/com/regis/cosnier/emu48/InfoActivity.java @@ -0,0 +1,88 @@ +package com.regis.cosnier.emu48; + +import android.app.ActionBar; +import android.app.Activity; +import android.os.Bundle; +import android.text.method.ScrollingMovementMethod; +import android.text.util.Linkify; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.TextView; + +import java.io.IOException; +import java.io.InputStream; + +public class InfoActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_info); + + // Show the Up button in the action bar. + ActionBar actionBar = getActionBar(); + if(actionBar != null) { + actionBar.setDisplayShowHomeEnabled(true); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setDisplayHomeAsUpEnabled(true); + } + + String filepath = getString(R.string.info_readme); + + // Programmatically load text from an asset and place it into the + // text view. Note that the text we are loading is ASCII, so we + // need to convert it to UTF-16. + try { + InputStream is = getAssets().open(filepath); + + // We guarantee that the available method returns the total + // size of the asset... of course, this does mean that a single + // asset can't be more than 2 gigs. + int size = is.available(); + + // Read the entire asset into a local byte buffer. + byte[] buffer = new byte[size]; + //noinspection ResultOfMethodCallIgnored + is.read(buffer); + is.close(); + + // Convert the buffer into a string. + String text = new String(buffer); + + // Finally stick the string into the text view. + TextView textViewInfo = (TextView)findViewById(R.id.textViewInfo); + textViewInfo.setMovementMethod(new ScrollingMovementMethod()); + textViewInfo.setText(text); + Linkify.addLinks(textViewInfo, Linkify.ALL); + } catch (IOException e) { + // Should never happen! + //throw new RuntimeException(e); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + //getMenuInflater().inflate(R.menu.activity_info, menu); + return false; //true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + // This ID represents the Home or Up button. In the case of this + // activity, the Up button is shown. Use NavUtils to allow users + // to navigate up one level in the application structure. For + // more details, see the Navigation pattern on Android Design: + // + // http://developer.android.com/design/patterns/navigation.html#up-vs-back + // + //NavUtils.navigateUpFromSameTask(this); + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + +} diff --git a/app/src/main/java/com/regis/cosnier/emu48/InfoWebActivity.java b/app/src/main/java/com/regis/cosnier/emu48/InfoWebActivity.java new file mode 100644 index 0000000..3cbfe2b --- /dev/null +++ b/app/src/main/java/com/regis/cosnier/emu48/InfoWebActivity.java @@ -0,0 +1,53 @@ +package com.regis.cosnier.emu48; + +import android.app.Activity; +import android.graphics.Color; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.webkit.WebView; + +public class InfoWebActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_web_info); + // Show the Up button in the action bar. + //getActionBar().setDisplayHomeAsUpEnabled(true); + + WebView webView = (WebView)findViewById(R.id.webViewInfo); +// webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY); +// webView.setBackgroundColor(Color.LTGRAY); + String url = getString(R.string.help_url); + webView.loadUrl(url); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + //getMenuInflater().inflate(R.menu.activity_info, menu); + //return true; + return false; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + // This ID represents the Home or Up button. In the case of this + // activity, the Up button is shown. Use NavUtils to allow users + // to navigate up one level in the application structure. For + // more details, see the Navigation pattern on Android Design: + // + // http://developer.android.com/design/patterns/navigation.html#up-vs-back + // + //NavUtils.navigateUpFromSameTask(this); + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + +} diff --git a/app/src/main/java/com/regis/cosnier/emu48/MainActivity.java b/app/src/main/java/com/regis/cosnier/emu48/MainActivity.java index 382a10b..41c29ee 100644 --- a/app/src/main/java/com/regis/cosnier/emu48/MainActivity.java +++ b/app/src/main/java/com/regis/cosnier/emu48/MainActivity.java @@ -289,6 +289,7 @@ public class MainActivity extends AppCompatActivity private void updateNavigationDrawerItems() { Menu menu = navigationView.getMenu(); boolean isDocumentAvailable = NativeLib.isDocumentAvailable(); + boolean isBackup = NativeLib.isBackup(); menu.findItem(R.id.nav_save).setEnabled(isDocumentAvailable); menu.findItem(R.id.nav_save_as).setEnabled(isDocumentAvailable); menu.findItem(R.id.nav_close).setEnabled(isDocumentAvailable); @@ -299,10 +300,9 @@ public class MainActivity extends AppCompatActivity menu.findItem(R.id.nav_paste_stack).setEnabled(isDocumentAvailable); menu.findItem(R.id.nav_reset_calculator).setEnabled(isDocumentAvailable); menu.findItem(R.id.nav_backup_save).setEnabled(isDocumentAvailable); - menu.findItem(R.id.nav_backup_restore).setEnabled(isDocumentAvailable); - menu.findItem(R.id.nav_backup_delete).setEnabled(isDocumentAvailable); + menu.findItem(R.id.nav_backup_restore).setEnabled(isDocumentAvailable && isBackup); + menu.findItem(R.id.nav_backup_delete).setEnabled(isDocumentAvailable && isBackup); menu.findItem(R.id.nav_change_kml_script).setEnabled(isDocumentAvailable); - } class KMLScriptItem { @@ -577,11 +577,42 @@ public class MainActivity extends AppCompatActivity } private void OnViewScript() { - //NativeLib.onViewScript(); + extractKMLScripts(); + + if (NativeLib.getState() != 0 /*SM_RUN*/) + { + showAlert("You cannot change the KML script when Emu48 is not running.\n" + + "Use the File,New menu item to create a new calculator."); + return; + } + final ArrayList kmlScriptsForCurrentModel = new ArrayList<>(); + char m = (char)NativeLib.getCurrentModel(); + for (int i = 0; i < kmlScripts.size(); i++) { + KMLScriptItem kmlScriptItem = kmlScripts.get(i); + if (kmlScriptItem.model.charAt(0) == m) + kmlScriptsForCurrentModel.add(kmlScriptItem); + } + + final String[] kmlScriptTitles = new String[kmlScriptsForCurrentModel.size()]; + for (int i = 0; i < kmlScriptsForCurrentModel.size(); i++) + kmlScriptTitles[i] = kmlScriptsForCurrentModel.get(i).title; + new AlertDialog.Builder(MainActivity.this) + .setTitle("Pick a calculator") + .setItems(kmlScriptTitles, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String kmlScriptFilename = kmlScriptsForCurrentModel.get(which).filename; + NativeLib.onViewScript(kmlScriptFilename); + showKMLLog(); + updateNavigationDrawerItems(); + } + }).show(); } private void OnTopics() { + startActivity(new Intent(this, InfoWebActivity.class)); } private void OnAbout() { + startActivity(new Intent(this, InfoActivity.class)); } @Override @@ -687,6 +718,10 @@ public class MainActivity extends AppCompatActivity return fd; } + void showAlert(String text) { + Snackbar.make(getWindow().getDecorView().getRootView(), "text", Snackbar.LENGTH_LONG).setAction("Action", null).show(); + } + private void updateFromPreferences(String key, boolean isDynamic) { int isDynamicValue = isDynamic ? 1 : 0; if(key == null) { diff --git a/app/src/main/java/com/regis/cosnier/emu48/NativeLib.java b/app/src/main/java/com/regis/cosnier/emu48/NativeLib.java index ed87e08..c81b981 100644 --- a/app/src/main/java/com/regis/cosnier/emu48/NativeLib.java +++ b/app/src/main/java/com/regis/cosnier/emu48/NativeLib.java @@ -14,7 +14,6 @@ public class NativeLib { public static native void start(AssetManager mgr, Bitmap bitmapMainScreen, MainActivity activity, MainScreenView view); public static native void stop(); - //public static native void resize(int width, int height); public static native void draw(); public static native void buttonDown(int x, int y); public static native void buttonUp(int x, int y); @@ -25,6 +24,7 @@ public class NativeLib { public static native boolean isDocumentAvailable(); public static native String getCurrentFilename(); public static native int getCurrentModel(); + public static native boolean isBackup(); public static native String getKMLLog(); public static native int onFileNew(String kmlFilename); @@ -38,10 +38,12 @@ public class NativeLib { public static native void onStackCopy(); public static native void onStackPaste(); public static native void onViewReset(); + public static native void onViewScript(String kmlFilename); public static native void onBackupSave(); public static native void onBackupRestore(); public static native void onBackupDelete(); public static native void setConfiguration(String key, int isDynamic, int intValue1, int intValue2, String stringValue); public static native boolean isPortExtensionPossible(); + public static native int getState(); } diff --git a/app/src/main/res/layout/activity_info.xml b/app/src/main/res/layout/activity_info.xml new file mode 100644 index 0000000..ca991b1 --- /dev/null +++ b/app/src/main/res/layout/activity_info.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_web_info.xml b/app/src/main/res/layout/activity_web_info.xml new file mode 100644 index 0000000..6346389 --- /dev/null +++ b/app/src/main/res/layout/activity_web_info.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 672e0e4..05ffae4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,4 +1,20 @@ + + + + About + ReadMe.txt + + + Help + file:///android_asset/Emu48.htm + + + + Settings + + + Emu48 Open navigation drawer Close navigation drawer @@ -6,7 +22,6 @@ android.studio@android.com Navigation header Settings - Settings New... Open... Save @@ -16,4 +31,6 @@ Save Object... Copy Screen Copy Stack + +