mirror of
https://github.com/dgis/emu48android
synced 2024-12-27 09:58:46 +01:00
- Add the KML Icon if present in the navigation menu header (only support PNG or 32bits BMP in the ICO file).
- Allow an optional overlapping LCD part stuck to the screen when swiping the 2 calc parts (not yet working).
This commit is contained in:
parent
b8b8f92964
commit
62da22c1d0
13 changed files with 849 additions and 162 deletions
|
@ -25,9 +25,8 @@
|
||||||
#include "win32-layer.h"
|
#include "win32-layer.h"
|
||||||
|
|
||||||
extern AAssetManager * assetManager;
|
extern AAssetManager * assetManager;
|
||||||
static jobject viewToUpdate = NULL;
|
|
||||||
static jobject mainActivity = NULL;
|
static jobject mainActivity = NULL;
|
||||||
jobject bitmapMainScreen;
|
jobject bitmapMainScreen = NULL;
|
||||||
AndroidBitmapInfo androidBitmapInfo;
|
AndroidBitmapInfo androidBitmapInfo;
|
||||||
enum DialogBoxMode currentDialogBoxMode;
|
enum DialogBoxMode currentDialogBoxMode;
|
||||||
enum ChooseKmlMode chooseCurrentKmlMode;
|
enum ChooseKmlMode chooseCurrentKmlMode;
|
||||||
|
@ -86,16 +85,16 @@ enum CALLBACK_TYPE {
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/9630134/jni-how-to-callback-from-c-or-c-to-java
|
// https://stackoverflow.com/questions/9630134/jni-how-to-callback-from-c-or-c-to-java
|
||||||
int mainViewCallback(int type, int param1, int param2, const TCHAR * param3, const TCHAR * param4) {
|
int mainViewCallback(int type, int param1, int param2, const TCHAR * param3, const TCHAR * param4) {
|
||||||
if (viewToUpdate) {
|
if (mainActivity) {
|
||||||
JNIEnv *jniEnv = getJNIEnvironment();
|
JNIEnv *jniEnv = getJNIEnvironment();
|
||||||
if(jniEnv) {
|
if(jniEnv) {
|
||||||
jclass viewToUpdateClass = (*jniEnv)->GetObjectClass(jniEnv, viewToUpdate);
|
jclass mainActivityClass = (*jniEnv)->GetObjectClass(jniEnv, mainActivity);
|
||||||
if(viewToUpdateClass) {
|
if(mainActivityClass) {
|
||||||
jmethodID midStr = (*jniEnv)->GetMethodID(jniEnv, viewToUpdateClass, "updateCallback", "(IIILjava/lang/String;Ljava/lang/String;)I");
|
jmethodID midStr = (*jniEnv)->GetMethodID(jniEnv, mainActivityClass, "updateCallback", "(IIILjava/lang/String;Ljava/lang/String;)I");
|
||||||
jstring utfParam3 = (*jniEnv)->NewStringUTF(jniEnv, param3);
|
jstring utfParam3 = (*jniEnv)->NewStringUTF(jniEnv, param3);
|
||||||
jstring utfParam4 = (*jniEnv)->NewStringUTF(jniEnv, param4);
|
jstring utfParam4 = (*jniEnv)->NewStringUTF(jniEnv, param4);
|
||||||
int result = (*jniEnv)->CallIntMethod(jniEnv, viewToUpdate, midStr, type, param1, param2, utfParam3, utfParam4);
|
int result = (*jniEnv)->CallIntMethod(jniEnv, mainActivity, midStr, type, param1, param2, utfParam3, utfParam4);
|
||||||
(*jniEnv)->DeleteLocalRef(jniEnv, viewToUpdateClass);
|
(*jniEnv)->DeleteLocalRef(jniEnv, mainActivityClass);
|
||||||
//if(needDetach) ret = (*java_machine)->DetachCurrentThread(java_machine);
|
//if(needDetach) ret = (*java_machine)->DetachCurrentThread(java_machine);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -283,20 +282,30 @@ void sendByteUdp(unsigned char byteSent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_start(JNIEnv *env, jobject thisz, jobject assetMgr, jobject bitmapMainScreen0, jobject activity, jobject view) {
|
void setKMLIcon(int imageWidth, int imageHeight, LPBYTE buffer, int bufferSize) {
|
||||||
|
JNIEnv *jniEnv = getJNIEnvironment();
|
||||||
|
if(jniEnv) {
|
||||||
|
jclass mainActivityClass = (*jniEnv)->GetObjectClass(jniEnv, mainActivity);
|
||||||
|
if(mainActivityClass) {
|
||||||
|
jmethodID midStr = (*jniEnv)->GetMethodID(jniEnv, mainActivityClass, "setKMLIcon", "(II[B)V");
|
||||||
|
|
||||||
|
jbyteArray pixels = NULL;
|
||||||
|
if(buffer) {
|
||||||
|
pixels = (*jniEnv)->NewByteArray(jniEnv, bufferSize);
|
||||||
|
(*jniEnv)->SetByteArrayRegion(jniEnv, pixels, 0, bufferSize, (jbyte *) buffer);
|
||||||
|
}
|
||||||
|
(*jniEnv)->CallVoidMethod(jniEnv, mainActivity, midStr, imageWidth, imageHeight, pixels);
|
||||||
|
(*jniEnv)->DeleteLocalRef(jniEnv, mainActivityClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_start(JNIEnv *env, jobject thisz, jobject assetMgr, jobject activity) {
|
||||||
|
|
||||||
chooseCurrentKmlMode = ChooseKmlMode_UNKNOWN;
|
chooseCurrentKmlMode = ChooseKmlMode_UNKNOWN;
|
||||||
szChosenCurrentKml[0] = '\0';
|
szChosenCurrentKml[0] = '\0';
|
||||||
|
|
||||||
bitmapMainScreen = (*env)->NewGlobalRef(env, bitmapMainScreen0);
|
|
||||||
mainActivity = (*env)->NewGlobalRef(env, activity);
|
mainActivity = (*env)->NewGlobalRef(env, activity);
|
||||||
viewToUpdate = (*env)->NewGlobalRef(env, view);
|
|
||||||
|
|
||||||
|
|
||||||
int ret = AndroidBitmap_getInfo(env, bitmapMainScreen, &androidBitmapInfo);
|
|
||||||
if (ret < 0) {
|
|
||||||
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
assetManager = AAssetManager_fromJava(env, assetMgr);
|
assetManager = AAssetManager_fromJava(env, assetMgr);
|
||||||
|
|
||||||
|
@ -394,10 +403,6 @@ JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_stop(JNIEnv *env,
|
||||||
SoundClose(); // close waveform-audio output device
|
SoundClose(); // close waveform-audio output device
|
||||||
soundEnabled = FALSE;
|
soundEnabled = FALSE;
|
||||||
|
|
||||||
if (viewToUpdate) {
|
|
||||||
(*env)->DeleteGlobalRef(env, viewToUpdate);
|
|
||||||
viewToUpdate = NULL;
|
|
||||||
}
|
|
||||||
if(bitmapMainScreen) {
|
if(bitmapMainScreen) {
|
||||||
(*env)->DeleteGlobalRef(env, bitmapMainScreen);
|
(*env)->DeleteGlobalRef(env, bitmapMainScreen);
|
||||||
bitmapMainScreen = NULL;
|
bitmapMainScreen = NULL;
|
||||||
|
@ -419,6 +424,74 @@ JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_changeBitmap(JNIEn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL Java_org_emulator_calculator_NativeLib_copyLCD(JNIEnv *env, jobject thisz, jobject bitmapLCD) {
|
||||||
|
|
||||||
|
if(!bitmapLCD)
|
||||||
|
return JNI_FALSE;
|
||||||
|
|
||||||
|
AndroidBitmapInfo bitmapLCDInfo;
|
||||||
|
int ret = AndroidBitmap_getInfo(env, bitmapLCD, &bitmapLCDInfo);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// INT nxSize, nySize;
|
||||||
|
// GetSizeLcdBitmap(&nxSize,&nySize); // get LCD size
|
||||||
|
|
||||||
|
HDC hSrcDC = hLcdDC; // use display HDC as source
|
||||||
|
if(!hSrcDC)
|
||||||
|
return JNI_FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
HBITMAP hBmp = hSrcDC->selectedBitmap;
|
||||||
|
if (hBmp && hBmp->bitmapInfoHeader && hBmp->bitmapInfoHeader->biWidth == bitmapLCDInfo.width &&
|
||||||
|
abs(hBmp->bitmapInfoHeader->biHeight) == bitmapLCDInfo.height) {
|
||||||
|
INT nxO = 0, nyO = 0; // origin in HDC
|
||||||
|
void *pixelsDestination;
|
||||||
|
if ((ret = AndroidBitmap_lockPixels(env, bitmapLCD, &pixelsDestination)) < 0) {
|
||||||
|
LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (nCurrentHardware == HDW_SACA)
|
||||||
|
// {
|
||||||
|
// TCHAR cBuffer[32]; // temp. buffer for text
|
||||||
|
// MSG msg;
|
||||||
|
//
|
||||||
|
// // calculate bitmap origins from hWindowDC
|
||||||
|
// nxO = nLcdX; if (nxO > 1) { nxO -= 2; nxSize += 4; };
|
||||||
|
// nyO = nLcdY; if (nyO > 1) { nyO -= 2; nySize += 4; };
|
||||||
|
//
|
||||||
|
// hSrcDC = hWindowDC; // use output HDC as source
|
||||||
|
// }
|
||||||
|
|
||||||
|
EnterCriticalSection(&csGDILock); // solving NT GDI problems
|
||||||
|
|
||||||
|
// copy display area
|
||||||
|
//BitBlt(hBmpDC,0,0,nxSize,nySize,hSrcDC,nxO,nyO,SRCCOPY);
|
||||||
|
|
||||||
|
size_t strideSource = ((unsigned int) (4 * ((hBmp->bitmapInfoHeader->biWidth *
|
||||||
|
hBmp->bitmapInfoHeader->biBitCount + 31) /
|
||||||
|
32)));
|
||||||
|
size_t strideDestination = bitmapLCDInfo.stride;
|
||||||
|
VOID *bitmapBitsSource = (VOID *) hBmp->bitmapBits;
|
||||||
|
VOID *bitmapBitsDestination = pixelsDestination;
|
||||||
|
int biHeight = abs(hBmp->bitmapInfoHeader->biHeight);
|
||||||
|
for (int y = 0; y < biHeight; y++) {
|
||||||
|
memcpy(bitmapBitsDestination, bitmapBitsSource, strideSource);
|
||||||
|
bitmapBitsSource += strideSource;
|
||||||
|
bitmapBitsDestination += strideDestination;
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&csGDILock);
|
||||||
|
AndroidBitmap_unlockPixels(env, bitmapLCD);
|
||||||
|
return JNI_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_draw(JNIEnv *env, jobject thisz) {
|
JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_draw(JNIEnv *env, jobject thisz) {
|
||||||
draw();
|
draw();
|
||||||
|
@ -1117,6 +1190,12 @@ JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_getState(JNIEnv *e
|
||||||
return nState;
|
return nState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_getScreenPositionX(JNIEnv *env, jobject thisz) {
|
||||||
|
return nLcdX;
|
||||||
|
}
|
||||||
|
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_getScreenPositionY(JNIEnv *env, jobject thisz) {
|
||||||
|
return nLcdY;
|
||||||
|
}
|
||||||
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_getScreenWidth(JNIEnv *env, jobject thisz) {
|
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_getScreenWidth(JNIEnv *env, jobject thisz) {
|
||||||
return 131*nLcdZoom*nGdiXZoom;
|
return 131*nLcdZoom*nGdiXZoom;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
#include "core/resource.h"
|
#include "core/resource.h"
|
||||||
#include "win32-layer.h"
|
#include "win32-layer.h"
|
||||||
#include "emu.h"
|
#include "emu.h"
|
||||||
|
#include "core/lodepng.h"
|
||||||
|
|
||||||
|
|
||||||
extern JavaVM *java_machine;
|
extern JavaVM *java_machine;
|
||||||
extern jobject bitmapMainScreen;
|
extern jobject bitmapMainScreen;
|
||||||
|
@ -837,9 +839,189 @@ BOOL GetSaveFileName(LPOPENFILENAME openFilename) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE LoadImage(HINSTANCE hInst, LPCSTR name, UINT type, int cx, int cy, UINT fuLoad) {
|
// Almost the same function as the private core function DibNumColors()
|
||||||
//TODO
|
static __inline WORD DibNumColors(BITMAPINFOHEADER CONST *lpbi)
|
||||||
|
{
|
||||||
|
if (lpbi->biClrUsed != 0) return (WORD) lpbi->biClrUsed;
|
||||||
|
|
||||||
|
/* a 24 bitcount DIB has no color table */
|
||||||
|
return (lpbi->biBitCount <= 8) ? (1 << lpbi->biBitCount) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HBITMAP DecodeBMPIcon(LPBYTE imageBuffer, size_t imageSize) {
|
||||||
|
// size of bitmap header information
|
||||||
|
DWORD dwFileSize = sizeof(BITMAPINFOHEADER);
|
||||||
|
if (imageSize < dwFileSize)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
LPBITMAPINFO pBmi = (LPBITMAPINFO)imageBuffer;
|
||||||
|
|
||||||
|
// size with color table
|
||||||
|
if (pBmi->bmiHeader.biCompression == BI_BITFIELDS)
|
||||||
|
dwFileSize += 3 * sizeof(DWORD);
|
||||||
|
else
|
||||||
|
dwFileSize += DibNumColors(&pBmi->bmiHeader) * sizeof(RGBQUAD);
|
||||||
|
|
||||||
|
pBmi->bmiHeader.biHeight /= 2;
|
||||||
|
|
||||||
|
DWORD stride = (((pBmi->bmiHeader.biWidth * (DWORD)pBmi->bmiHeader.biBitCount) + 31) / 32 * 4);
|
||||||
|
DWORD height = (DWORD) abs(pBmi->bmiHeader.biHeight);
|
||||||
|
|
||||||
|
// size with bitmap data
|
||||||
|
if (pBmi->bmiHeader.biCompression != BI_RGB)
|
||||||
|
dwFileSize += pBmi->bmiHeader.biSizeImage;
|
||||||
|
else {
|
||||||
|
pBmi->bmiHeader.biSizeImage = stride * height;
|
||||||
|
dwFileSize += pBmi->bmiHeader.biSizeImage;
|
||||||
|
}
|
||||||
|
if (imageSize < dwFileSize)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
HBITMAP hBitmap = CreateDIBitmap(hWindowDC, &pBmi->bmiHeader, CBM_INIT, imageBuffer, pBmi, DIB_RGB_COLORS);
|
||||||
|
if(hBitmap) {
|
||||||
|
// Inverse the height
|
||||||
|
BYTE *source = imageBuffer + dwFileSize - stride;
|
||||||
|
BYTE *destination = hBitmap->bitmapBits;
|
||||||
|
for (int i = 0; i < height; ++i) {
|
||||||
|
memcpy(destination, source, stride);
|
||||||
|
source -= stride;
|
||||||
|
destination += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Only support 32bits RGBA BMP for now.
|
||||||
|
return hBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HBITMAP DecodePNGIcon(LPBYTE imageBuffer, size_t imageSize) {
|
||||||
|
HBITMAP hBitmap = NULL;
|
||||||
|
UINT uWidth,uHeight;
|
||||||
|
LPBYTE pbyImage = NULL;
|
||||||
|
UINT uError = lodepng_decode_memory(&pbyImage, &uWidth, &uHeight, imageBuffer, imageSize, LCT_RGBA, 8);
|
||||||
|
if (uError == 0) {
|
||||||
|
BITMAPINFO bmi;
|
||||||
|
ZeroMemory(&bmi, sizeof(bmi)); // init bitmap info
|
||||||
|
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||||
|
bmi.bmiHeader.biWidth = (LONG) uWidth;
|
||||||
|
bmi.bmiHeader.biHeight = (LONG) uHeight;
|
||||||
|
bmi.bmiHeader.biPlanes = 1;
|
||||||
|
bmi.bmiHeader.biBitCount = 32; // create a true color DIB
|
||||||
|
bmi.bmiHeader.biCompression = BI_RGB;
|
||||||
|
|
||||||
|
// bitmap dimensions
|
||||||
|
LONG lBytesPerLine = (((bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount) + 31) / 32 * 4);
|
||||||
|
bmi.bmiHeader.biSizeImage = (DWORD) (lBytesPerLine * bmi.bmiHeader.biHeight);
|
||||||
|
|
||||||
|
// allocate buffer for pixels
|
||||||
|
LPBYTE pbyPixels; // BMP buffer
|
||||||
|
hBitmap = CreateDIBSection(hWindowDC, &bmi, DIB_RGB_COLORS, (VOID **)&pbyPixels, NULL, 0);
|
||||||
|
if (hBitmap)
|
||||||
|
memcpy(pbyPixels, pbyImage, bmi.bmiHeader.biSizeImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pbyImage != NULL)
|
||||||
|
free(pbyImage);
|
||||||
|
return hBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICO (file format) https://en.wikipedia.org/wiki/ICO_(file_format)
|
||||||
|
// https://docs.microsoft.com/en-us/previous-versions/ms997538(v=msdn.10)
|
||||||
|
typedef struct {
|
||||||
|
WORD idReserved;
|
||||||
|
WORD idType;
|
||||||
|
WORD idCount;
|
||||||
|
} ICONDIR, *LPICONDIR;
|
||||||
|
typedef struct ICONDIRENTRY {
|
||||||
|
BYTE bWidth; // Specifies image width in pixels. Can be any number between 0 and 255. Value 0 means image width is 256 pixels.
|
||||||
|
BYTE bHeight; // Specifies image height in pixels. Can be any number between 0 and 255. Value 0 means image height is 256 pixels.
|
||||||
|
BYTE bColorCount; // Specifies number of colors in the color palette. Should be 0 if the image does not use a color palette.
|
||||||
|
BYTE bReserved; // Reserved. Should be 0.
|
||||||
|
WORD wPlanes; // In ICO format: Specifies color planes. Should be 0 or 1.
|
||||||
|
WORD wBitCount; // In ICO format: Specifies bits per pixel.
|
||||||
|
DWORD dwBytesInRes; // Specifies the size of the image's data in bytes
|
||||||
|
DWORD dwImageOffset; // Specifies the offset of BMP or PNG data from the beginning of the ICO/CUR file
|
||||||
|
} ICONDIRENTRY, *LPICONDIRENTRY;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BITMAPINFOHEADER icHeader; // DIB header
|
||||||
|
RGBQUAD icColors[1]; // Color table
|
||||||
|
BYTE icXOR[1]; // DIB bits for XOR mask
|
||||||
|
BYTE icAND[1]; // DIB bits for AND mask
|
||||||
|
} ICONIMAGE, *LPICONIMAGE;
|
||||||
|
|
||||||
|
HANDLE LoadImage(HINSTANCE hInst, LPCSTR name, UINT type, int cx, int cy, UINT fuLoad) {
|
||||||
|
|
||||||
|
HANDLE hIconFile = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||||
|
if (hIconFile == INVALID_HANDLE_VALUE)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ICONDIR fileHeader;
|
||||||
|
DWORD nNumberOfBytesToRead = 0;
|
||||||
|
if(ReadFile(hIconFile, &fileHeader, sizeof(ICONDIR), &nNumberOfBytesToRead, NULL) == FALSE || sizeof(ICONDIR) != nNumberOfBytesToRead) {
|
||||||
|
CloseHandle(hIconFile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t iconsBufferSize = fileHeader.idCount * sizeof(ICONDIRENTRY);
|
||||||
|
ICONDIRENTRY * iconHeaderArray = malloc(iconsBufferSize);
|
||||||
|
nNumberOfBytesToRead = 0;
|
||||||
|
if(ReadFile(hIconFile, iconHeaderArray, iconsBufferSize, &nNumberOfBytesToRead, NULL) == FALSE || iconsBufferSize != nNumberOfBytesToRead) {
|
||||||
|
CloseHandle(hIconFile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxWidth = -1;
|
||||||
|
int maxHeight = -1;
|
||||||
|
int maxBitPerPixel = -1;
|
||||||
|
int maxIconIndex = -1;
|
||||||
|
for (int i = 0; i < fileHeader.idCount; ++i) {
|
||||||
|
ICONDIRENTRY * iconHeader = &(iconHeaderArray[i]);
|
||||||
|
int width = iconHeader->bWidth == 0 ? 256 : iconHeader->bWidth;
|
||||||
|
int height = iconHeader->bHeight == 0 ? 256 : iconHeader->bHeight;
|
||||||
|
if(width >= maxWidth && height >= maxHeight && iconHeader->wBitCount > maxBitPerPixel) {
|
||||||
|
maxWidth = width;
|
||||||
|
maxHeight = height;
|
||||||
|
maxBitPerPixel = iconHeader->wBitCount;
|
||||||
|
maxIconIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maxIconIndex = 1; // To test BMP
|
||||||
|
if(maxIconIndex == -1) {
|
||||||
|
CloseHandle(hIconFile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD dwBytesInRes = iconHeaderArray[maxIconIndex].dwBytesInRes;
|
||||||
|
LPBYTE iconBuffer = malloc(dwBytesInRes);
|
||||||
|
|
||||||
|
SetFilePointer(hIconFile, iconHeaderArray[maxIconIndex].dwImageOffset, 0, FILE_BEGIN);
|
||||||
|
if(ReadFile(hIconFile, iconBuffer, dwBytesInRes, &nNumberOfBytesToRead, NULL) == FALSE || dwBytesInRes != nNumberOfBytesToRead) {
|
||||||
|
CloseHandle(hIconFile);
|
||||||
|
free(iconHeaderArray);
|
||||||
|
free(iconBuffer);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
CloseHandle(hIconFile);
|
||||||
|
|
||||||
|
HBITMAP icon = NULL;
|
||||||
|
if (dwBytesInRes >= 8 && memcmp(iconBuffer, "\x89PNG\r\n\x1a\n", 8) == 0)
|
||||||
|
// It is a PNG image
|
||||||
|
icon = DecodePNGIcon(iconBuffer, dwBytesInRes);
|
||||||
|
else
|
||||||
|
// It is a BMP image
|
||||||
|
icon = DecodeBMPIcon(iconBuffer, dwBytesInRes);
|
||||||
|
|
||||||
|
|
||||||
|
free(iconHeaderArray);
|
||||||
|
free(iconBuffer);
|
||||||
|
|
||||||
|
if(!icon)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
HANDLE handle = malloc(sizeof(struct _HANDLE));
|
||||||
|
memset(handle, 0, sizeof(struct _HANDLE));
|
||||||
|
handle->handleType = HANDLE_TYPE_ICON;
|
||||||
|
handle->icon = icon;
|
||||||
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -871,8 +1053,17 @@ LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
|
||||||
return selItemDataIndex[wParam];
|
return selItemDataIndex[wParam];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(Msg == WM_SETICON) {
|
if(Msg == WM_SETICON && wParam == ICON_BIG) {
|
||||||
|
if(lParam != NULL) {
|
||||||
|
HANDLE hIcon = (HANDLE)lParam;
|
||||||
|
if(hIcon->handleType == HANDLE_TYPE_ICON && hIcon->icon != NULL) {
|
||||||
|
HBITMAP icon = hIcon->icon;
|
||||||
|
if(icon && icon->bitmapInfoHeader && icon->bitmapBits)
|
||||||
|
setKMLIcon(icon->bitmapInfoHeader->biWidth, icon->bitmapInfoHeader->biHeight, icon->bitmapBits, icon->bitmapInfoHeader->biSizeImage);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setKMLIcon(0, 0, NULL, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1964,7 +2155,7 @@ BOOL StretchBlt(HDC hdcDest, int xDest, int yDest, int wDest, int hDest, HDC hdc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(jniEnv && (ret = AndroidBitmap_unlockPixels(jniEnv, bitmapMainScreen)) < 0) {
|
if(jniEnv && hdcDest->hdcCompatible == NULL && (ret = AndroidBitmap_unlockPixels(jniEnv, bitmapMainScreen)) < 0) {
|
||||||
LOGD("AndroidBitmap_unlockPixels() failed ! error=%d", ret);
|
LOGD("AndroidBitmap_unlockPixels() failed ! error=%d", ret);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1996,8 +2187,7 @@ HBITMAP CreateBitmap( int nWidth, int nHeight, UINT nPlanes, UINT nBitCount, CON
|
||||||
|
|
||||||
BITMAPINFO * newBitmapInfo = malloc(sizeof(BITMAPINFO));
|
BITMAPINFO * newBitmapInfo = malloc(sizeof(BITMAPINFO));
|
||||||
memset(newBitmapInfo, 0, sizeof(BITMAPINFO));
|
memset(newBitmapInfo, 0, sizeof(BITMAPINFO));
|
||||||
//newBitmapInfo->bmiHeader.biBitCount = 32; //TODO should be nBitCount
|
newBitmapInfo->bmiHeader.biBitCount = (WORD) nBitCount;
|
||||||
newBitmapInfo->bmiHeader.biBitCount = nBitCount; //TODO should be nBitCount
|
|
||||||
newBitmapInfo->bmiHeader.biClrUsed = 0;
|
newBitmapInfo->bmiHeader.biClrUsed = 0;
|
||||||
newBitmapInfo->bmiHeader.biWidth = nWidth;
|
newBitmapInfo->bmiHeader.biWidth = nWidth;
|
||||||
newBitmapInfo->bmiHeader.biHeight = -nHeight;
|
newBitmapInfo->bmiHeader.biHeight = -nHeight;
|
||||||
|
|
|
@ -507,20 +507,24 @@ enum HANDLE_TYPE {
|
||||||
HANDLE_TYPE_EVENT,
|
HANDLE_TYPE_EVENT,
|
||||||
HANDLE_TYPE_THREAD,
|
HANDLE_TYPE_THREAD,
|
||||||
HANDLE_TYPE_WINDOW,
|
HANDLE_TYPE_WINDOW,
|
||||||
|
HANDLE_TYPE_ICON,
|
||||||
};
|
};
|
||||||
struct _HANDLE {
|
struct _HANDLE {
|
||||||
enum HANDLE_TYPE handleType;
|
enum HANDLE_TYPE handleType;
|
||||||
|
|
||||||
|
// HANDLE_TYPE_FILE*
|
||||||
int fileDescriptor;
|
int fileDescriptor;
|
||||||
BOOL fileOpenFileFromContentResolver;
|
BOOL fileOpenFileFromContentResolver;
|
||||||
|
|
||||||
AAsset* fileAsset;
|
AAsset* fileAsset;
|
||||||
|
|
||||||
|
// HANDLE_TYPE_FILE_MAPPING*
|
||||||
off_t fileMappingOffset;
|
off_t fileMappingOffset;
|
||||||
size_t fileMappingSize;
|
size_t fileMappingSize;
|
||||||
void* fileMappingAddress;
|
void* fileMappingAddress;
|
||||||
DWORD fileMappingProtect;
|
DWORD fileMappingProtect;
|
||||||
|
|
||||||
|
// HANDLE_TYPE_THREAD
|
||||||
pthread_t threadId;
|
pthread_t threadId;
|
||||||
DWORD (*threadStartAddress)(LPVOID);
|
DWORD (*threadStartAddress)(LPVOID);
|
||||||
LPVOID threadParameter;
|
LPVOID threadParameter;
|
||||||
|
@ -528,12 +532,17 @@ struct _HANDLE {
|
||||||
struct tagMSG threadMessage;
|
struct tagMSG threadMessage;
|
||||||
int threadIndex;
|
int threadIndex;
|
||||||
|
|
||||||
|
// HANDLE_TYPE_EVENT
|
||||||
pthread_cond_t eventCVariable;
|
pthread_cond_t eventCVariable;
|
||||||
pthread_mutex_t eventMutex;
|
pthread_mutex_t eventMutex;
|
||||||
BOOL eventAutoReset;
|
BOOL eventAutoReset;
|
||||||
BOOL eventState;
|
BOOL eventState;
|
||||||
|
|
||||||
|
// HANDLE_TYPE_WINDOW
|
||||||
HDC windowDC;
|
HDC windowDC;
|
||||||
|
|
||||||
|
// HANDLE_TYPE_ICON
|
||||||
|
HBITMAP icon;
|
||||||
};
|
};
|
||||||
typedef struct _HANDLE * HANDLE;
|
typedef struct _HANDLE * HANDLE;
|
||||||
|
|
||||||
|
@ -1227,6 +1236,7 @@ void clipboardCopyText(const TCHAR * text);
|
||||||
const TCHAR * clipboardPasteText();
|
const TCHAR * clipboardPasteText();
|
||||||
void performHapticFeedback();
|
void performHapticFeedback();
|
||||||
void sendByteUdp(unsigned char byteSent);
|
void sendByteUdp(unsigned char byteSent);
|
||||||
|
void setKMLIcon(int imageWidth, int imageHeight, LPBYTE buffer, int bufferSize);
|
||||||
|
|
||||||
typedef int SOCKET;
|
typedef int SOCKET;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,316 @@
|
||||||
|
package org.emulator.calculator;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
public class LCDOverlappingView extends View {
|
||||||
|
|
||||||
|
protected static final String TAG = "LCDOverlappingView";
|
||||||
|
protected final boolean debug = false;
|
||||||
|
|
||||||
|
private SharedPreferences sharedPreferences;
|
||||||
|
private Paint paint = new Paint();
|
||||||
|
private Bitmap bitmapLCD;
|
||||||
|
private float bitmapRatio = -1;
|
||||||
|
private float minViewSize = 200.0f;
|
||||||
|
private int overlappingLCDMode = 1;
|
||||||
|
private MainScreenView mainScreenView;
|
||||||
|
|
||||||
|
public LCDOverlappingView(Context context, MainScreenView mainScreenView) {
|
||||||
|
super(context);
|
||||||
|
|
||||||
|
this.mainScreenView = mainScreenView;
|
||||||
|
this.mainScreenView.setOnUpdateLayoutListener(() -> this.updateLayout(this.mainScreenView.viewPanOffsetX, this.mainScreenView.viewPanOffsetY, this.mainScreenView.viewScaleFactorX, this.mainScreenView.viewScaleFactorY));
|
||||||
|
|
||||||
|
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
|
||||||
|
|
||||||
|
paint.setFilterBitmap(true);
|
||||||
|
paint.setAntiAlias(true);
|
||||||
|
|
||||||
|
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||||
|
((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
|
||||||
|
bitmapLCD = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
|
||||||
|
bitmapLCD.eraseColor(Color.BLACK);
|
||||||
|
|
||||||
|
this.setFocusable(true);
|
||||||
|
this.setFocusableInTouchMode(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float previousX0 = -1.0f, previousY0 = -1.0f, previousX1 = -1.0f, previousY1 = -1.0f;
|
||||||
|
private float previousDownX0 = 0, previousDownY0 = 0;
|
||||||
|
|
||||||
|
private float distanceBetweenTwoPoints(float fromPointX, float fromPointY, float toPointX, float toPointY) {
|
||||||
|
float x = toPointX - fromPointX;
|
||||||
|
float y = toPointY - fromPointY;
|
||||||
|
return (float)Math.sqrt(x * x + y * y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
|
if(debug) Log.d(TAG, "onTouchEvent() getAction(): " + event.getAction() + ", getPointerCount(): " + event.getPointerCount());
|
||||||
|
|
||||||
|
int touchCount = event.getPointerCount();
|
||||||
|
float currentX0 = 0f, currentY0 = 0f, currentX1 = 0f, currentY1 = 0f;
|
||||||
|
|
||||||
|
|
||||||
|
if(touchCount > 0) {
|
||||||
|
currentX0 = event.getX(0);
|
||||||
|
currentY0 = event.getY(0);
|
||||||
|
}
|
||||||
|
if(touchCount > 1) {
|
||||||
|
currentX1 = event.getX(1);
|
||||||
|
currentY1 = event.getY(1);
|
||||||
|
}
|
||||||
|
if(debug) {
|
||||||
|
Log.d(TAG, "onTouchEvent() currentX0: " + currentX0 + ", currentY0: " + currentY0);
|
||||||
|
Log.d(TAG, "onTouchEvent() currentX1: " + currentX1 + ", currentY1: " + currentY1);
|
||||||
|
Log.d(TAG, "onTouchEvent() touchCount: " + touchCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
int action = event.getAction();
|
||||||
|
switch (action) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
if(debug) Log.d(TAG, "onTouchEvent() touchesBegan count: " + touchCount);
|
||||||
|
|
||||||
|
previousDownX0 = currentX0;
|
||||||
|
previousDownY0 = currentY0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
//if(debug) Log.d(TAG, "touchesMoved count: " + touchCount);
|
||||||
|
|
||||||
|
if (touchCount == 1) {
|
||||||
|
FrameLayout.LayoutParams viewFlowLayout = (FrameLayout.LayoutParams)getLayoutParams();
|
||||||
|
viewFlowLayout.leftMargin += currentX0 - previousDownX0;
|
||||||
|
viewFlowLayout.topMargin += currentY0 - previousDownY0;
|
||||||
|
setLayoutParams(viewFlowLayout);
|
||||||
|
changeOverlappingLCDMode();
|
||||||
|
} else if (touchCount == 2) {
|
||||||
|
if(previousX0 != -1.0f) {
|
||||||
|
FrameLayout.LayoutParams viewFlowLayout = (FrameLayout.LayoutParams)getLayoutParams();
|
||||||
|
float scaleFactor = distanceBetweenTwoPoints(currentX0, currentY0, currentX1, currentY1) / distanceBetweenTwoPoints(previousX0, previousY0, previousX1, previousY1);
|
||||||
|
float scaledViewWidth = (float)viewFlowLayout.width * scaleFactor;
|
||||||
|
float scaledViewHeight = (float)viewFlowLayout.height * scaleFactor;
|
||||||
|
|
||||||
|
float deltaFactor = (scaleFactor - 1.0f) / 2.0f;
|
||||||
|
int deltaW = (int) ((float) viewFlowLayout.width * deltaFactor);
|
||||||
|
int deltaH = (int) ((float) viewFlowLayout.height * deltaFactor);
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
Log.d(TAG, "onTouchEvent() scaleFactor: " + scaleFactor + ", currentWidth: " + viewFlowLayout.width + ", currentHeight: " + viewFlowLayout.height
|
||||||
|
+ ", deltaW: " + deltaW + ", deltaH: " + deltaH);
|
||||||
|
if (debug)
|
||||||
|
Log.d(TAG, "onTouchEvent() BEFORE leftMargin: " + viewFlowLayout.leftMargin + ", topMargin: " + viewFlowLayout.topMargin
|
||||||
|
+ ", width: " + viewFlowLayout.width + ", height: " + viewFlowLayout.height);
|
||||||
|
|
||||||
|
viewFlowLayout.leftMargin -= deltaW;
|
||||||
|
viewFlowLayout.topMargin -= deltaH;
|
||||||
|
int newViewWidth, newViewHeight;
|
||||||
|
if(bitmapRatio > 0.0f) {
|
||||||
|
if(bitmapRatio < 1.0f) {
|
||||||
|
newViewWidth = (int) scaledViewWidth;
|
||||||
|
newViewHeight = (int) (newViewWidth * bitmapRatio);
|
||||||
|
} else {
|
||||||
|
newViewHeight = (int) scaledViewHeight;
|
||||||
|
newViewWidth = (int) (newViewHeight / bitmapRatio);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newViewWidth = (int) scaledViewWidth;
|
||||||
|
newViewHeight = (int) scaledViewHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(newViewWidth >= minViewSize && newViewWidth >= minViewSize) {
|
||||||
|
viewFlowLayout.width = newViewWidth;
|
||||||
|
viewFlowLayout.height = newViewHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
Log.d(TAG, "onTouchEvent() AFTER leftMargin: " + viewFlowLayout.leftMargin + ", topMargin: " + viewFlowLayout.topMargin
|
||||||
|
+ ", width: " + viewFlowLayout.width + ", height: " + viewFlowLayout.height);
|
||||||
|
|
||||||
|
setLayoutParams(viewFlowLayout);
|
||||||
|
changeOverlappingLCDMode();
|
||||||
|
}
|
||||||
|
previousX0 = currentX0;
|
||||||
|
previousY0 = currentY0;
|
||||||
|
previousX1 = currentX1;
|
||||||
|
previousY1 = currentY1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
previousX0 = -1.0f;
|
||||||
|
previousY0 = -1.0f;
|
||||||
|
previousX1 = -1.0f;
|
||||||
|
previousY1 = -1.0f;
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
break;
|
||||||
|
case MotionEvent.ACTION_OUTSIDE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return true; // processed
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
//if(debug) Log.d(TAG, "onDraw()");
|
||||||
|
|
||||||
|
canvas.drawColor(Color.RED);
|
||||||
|
|
||||||
|
if(this.overlappingLCDMode > 0 && bitmapLCD != null) {
|
||||||
|
canvas.save();
|
||||||
|
if (bitmapLCD.getWidth() > 0 && bitmapLCD.getHeight() > 0)
|
||||||
|
canvas.scale((float) getWidth() / (float) bitmapLCD.getWidth(), (float) getHeight() / (float) bitmapLCD.getHeight());
|
||||||
|
canvas.drawBitmap(bitmapLCD, 0, 0, paint);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int updateCallback(int type, int param1, int param2, String param3, String param4) {
|
||||||
|
if(this.overlappingLCDMode == 0)
|
||||||
|
return -1;
|
||||||
|
switch (type) {
|
||||||
|
case NativeLib.CALLBACK_TYPE_INVALIDATE:
|
||||||
|
//if(debug) Log.d(TAG, "PAINT updateCallback() postInvalidate()");
|
||||||
|
if(debug) Log.d(TAG, "updateCallback() CALLBACK_TYPE_INVALIDATE");
|
||||||
|
NativeLib.copyLCD(bitmapLCD);
|
||||||
|
postInvalidate();
|
||||||
|
break;
|
||||||
|
case NativeLib.CALLBACK_TYPE_WINDOW_RESIZE:
|
||||||
|
// New Bitmap size
|
||||||
|
int newLCDWidth = NativeLib.getScreenWidth();
|
||||||
|
int newLCDHeight = NativeLib.getScreenHeight();
|
||||||
|
if(bitmapLCD == null || bitmapLCD.getWidth() != newLCDWidth || bitmapLCD.getHeight() != newLCDHeight) {
|
||||||
|
int newWidth = Math.max(1, newLCDWidth);
|
||||||
|
int newHeight = Math.max(1, newLCDHeight);
|
||||||
|
|
||||||
|
if(debug) Log.d(TAG, "updateCallback() Bitmap.createBitmap(x: " + newWidth + ", y: " + newHeight + ")");
|
||||||
|
Bitmap oldBitmapLCD = bitmapLCD;
|
||||||
|
bitmapLCD = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
|
||||||
|
bitmapRatio = (float)newHeight / (float)newWidth;
|
||||||
|
if(oldBitmapLCD != null)
|
||||||
|
oldBitmapLCD.recycle();
|
||||||
|
|
||||||
|
if(this.overlappingLCDMode != 1) {
|
||||||
|
setVisibility(View.VISIBLE);
|
||||||
|
float scale = sharedPreferences.getFloat("settings_lcd_overlapping_scale", 1.0f);
|
||||||
|
if (scale < 0.01f)
|
||||||
|
scale = 0.01f;
|
||||||
|
int viewWidth = (int) (newWidth * scale);
|
||||||
|
int viewHeight = (int) (newHeight * scale);
|
||||||
|
if (viewWidth < minViewSize && viewHeight < minViewSize) {
|
||||||
|
if (bitmapRatio > 0.0f) {
|
||||||
|
if (bitmapRatio < 1.0f) {
|
||||||
|
viewWidth = (int) minViewSize;
|
||||||
|
viewHeight = (int) (viewWidth * bitmapRatio);
|
||||||
|
} else {
|
||||||
|
viewHeight = (int) minViewSize;
|
||||||
|
viewWidth = (int) (viewHeight / bitmapRatio);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
viewWidth = (int) minViewSize;
|
||||||
|
viewHeight = (int) minViewSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameLayout.LayoutParams viewFlowLayout = new FrameLayout.LayoutParams(viewWidth, viewHeight);
|
||||||
|
viewFlowLayout.leftMargin = sharedPreferences.getInt("settings_lcd_overlapping_x", 20);
|
||||||
|
viewFlowLayout.topMargin = sharedPreferences.getInt("settings_lcd_overlapping_y", 80);
|
||||||
|
if (viewFlowLayout.leftMargin + viewWidth < 0)
|
||||||
|
viewFlowLayout.leftMargin = 0;
|
||||||
|
if (viewFlowLayout.topMargin + viewHeight < 0)
|
||||||
|
viewFlowLayout.topMargin = 0;
|
||||||
|
setLayoutParams(viewFlowLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||||
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
|
|
||||||
|
if(debug) Log.d(TAG, "onSizeChanged() width: " + w + ", height: " + h);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateLayout(float viewPanOffsetX, float viewPanOffsetY, float viewScaleFactorX, float viewScaleFactorY) {
|
||||||
|
if(debug) Log.d(TAG, "updateLayout()");
|
||||||
|
if(this.overlappingLCDMode == 0) // No Overlapping LCD
|
||||||
|
return;
|
||||||
|
if(this.overlappingLCDMode == 1) { // Auto
|
||||||
|
int newLCDWidth = NativeLib.getScreenWidth();
|
||||||
|
int newLCDHeight = NativeLib.getScreenHeight();
|
||||||
|
int newWidth = Math.max(1, newLCDWidth);
|
||||||
|
int newHeight = Math.max(1, newLCDHeight);
|
||||||
|
|
||||||
|
post(() -> {
|
||||||
|
FrameLayout.LayoutParams viewFlowLayout = new FrameLayout.LayoutParams((int) (newWidth * viewScaleFactorX), (int) (newHeight * viewScaleFactorY));
|
||||||
|
viewFlowLayout.leftMargin = (int)(viewScaleFactorX * NativeLib.getScreenPositionX() + viewPanOffsetX);
|
||||||
|
viewFlowLayout.topMargin = (int)(viewScaleFactorY * NativeLib.getScreenPositionY() + viewPanOffsetY);
|
||||||
|
if(debug) Log.d(TAG, "updateLayout() leftMargin: " + viewFlowLayout.leftMargin + ", topMargin: " + viewFlowLayout.topMargin
|
||||||
|
+ ", width: " + viewFlowLayout.width + ", height: " + viewFlowLayout.height);
|
||||||
|
setLayoutParams(viewFlowLayout);
|
||||||
|
setVisibility(View.VISIBLE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveViewLayout() {
|
||||||
|
if(this.overlappingLCDMode > 0)
|
||||||
|
return;
|
||||||
|
FrameLayout.LayoutParams viewFlowLayout = (FrameLayout.LayoutParams)getLayoutParams();
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putString("settings_lcd_overlapping_mode", Integer.toString(this.overlappingLCDMode));
|
||||||
|
editor.putInt("settings_lcd_overlapping_x", viewFlowLayout.leftMargin);
|
||||||
|
editor.putInt("settings_lcd_overlapping_y", viewFlowLayout.topMargin);
|
||||||
|
editor.putFloat("settings_lcd_overlapping_scale", bitmapLCD != null && bitmapLCD.getWidth() > 0 ? (float)viewFlowLayout.width / (float)bitmapLCD.getWidth() : 1.0f);
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changeOverlappingLCDMode() {
|
||||||
|
if(this.overlappingLCDMode == 1) { // Mode Auto
|
||||||
|
this.overlappingLCDMode = 2; // We change the mode to Manual
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putString("settings_lcd_overlapping_mode", Integer.toString(this.overlappingLCDMode));
|
||||||
|
editor.apply();
|
||||||
|
Context context = getContext();
|
||||||
|
if(context != null)
|
||||||
|
Utils.showAlert(context, context.getString(Utils.resId(context, "string", "message_change_overlapping_lcd_mode_to_manual")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOverlappingLCDMode(int overlappingLCDMode, boolean isDynamic) {
|
||||||
|
if(debug) Log.d(TAG, "setOverlappingLCDMode(" + overlappingLCDMode + ")");
|
||||||
|
int previousOverlappingLCDMode = this.overlappingLCDMode;
|
||||||
|
this.overlappingLCDMode = overlappingLCDMode;
|
||||||
|
if(previousOverlappingLCDMode == 0) { // Off 0
|
||||||
|
if(overlappingLCDMode == 1) // Auto 1
|
||||||
|
this.updateLayout(this.mainScreenView.viewPanOffsetX, this.mainScreenView.viewPanOffsetY, this.mainScreenView.viewScaleFactorX, this.mainScreenView.viewScaleFactorY);
|
||||||
|
else if(overlappingLCDMode == 2) // Manual 2
|
||||||
|
setVisibility(VISIBLE);
|
||||||
|
} else if(previousOverlappingLCDMode == 1) { // Auto 1
|
||||||
|
if(overlappingLCDMode == 0) // Off 0
|
||||||
|
setVisibility(GONE);
|
||||||
|
} else if(previousOverlappingLCDMode == 2) { // Manual 2
|
||||||
|
if(overlappingLCDMode == 0) // Off 0
|
||||||
|
setVisibility(GONE);
|
||||||
|
else if(overlappingLCDMode == 1) // Auto 1
|
||||||
|
this.updateLayout(this.mainScreenView.viewPanOffsetX, this.mainScreenView.viewPanOffsetY, this.mainScreenView.viewScaleFactorX, this.mainScreenView.viewScaleFactorY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,7 +61,7 @@ public class MainScreenView extends PanAndScaleView {
|
||||||
|
|
||||||
DisplayMetrics displayMetrics = new DisplayMetrics();
|
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||||
((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
|
((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
|
||||||
bitmapMainScreen = Bitmap.createBitmap(displayMetrics.widthPixels, displayMetrics.heightPixels, Bitmap.Config.ARGB_8888);
|
bitmapMainScreen = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
|
||||||
bitmapMainScreen.eraseColor(Color.BLACK);
|
bitmapMainScreen.eraseColor(Color.BLACK);
|
||||||
enableZoomKeyboard = false;
|
enableZoomKeyboard = false;
|
||||||
|
|
||||||
|
@ -153,10 +153,6 @@ public class MainScreenView extends PanAndScaleView {
|
||||||
|
|
||||||
this.setFocusable(true);
|
this.setFocusable(true);
|
||||||
this.setFocusableInTouchMode(true);
|
this.setFocusableInTouchMode(true);
|
||||||
|
|
||||||
// This call is necessary, or else the
|
|
||||||
// draw method will not be called.
|
|
||||||
setWillNotDraw(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent accidental scroll when taping a calc button
|
// Prevent accidental scroll when taping a calc button
|
||||||
|
@ -285,6 +281,8 @@ public class MainScreenView extends PanAndScaleView {
|
||||||
viewPanOffsetY = translateY;
|
viewPanOffsetY = translateY;
|
||||||
|
|
||||||
constrainPan();
|
constrainPan();
|
||||||
|
if(this.onUpdateLayoutListener != null)
|
||||||
|
this.onUpdateLayoutListener.run();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,13 +290,19 @@ public class MainScreenView extends PanAndScaleView {
|
||||||
}
|
}
|
||||||
// Else, the screens orientations are the same, so we set the calculator in fullscreen
|
// Else, the screens orientations are the same, so we set the calculator in fullscreen
|
||||||
resetViewport();
|
resetViewport();
|
||||||
|
|
||||||
|
if(this.onUpdateLayoutListener != null)
|
||||||
|
this.onUpdateLayoutListener.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private Runnable onUpdateLayoutListener = null;
|
||||||
* Draw the score.
|
|
||||||
* @param canvas The canvas to draw to coming from the View.onDraw() method.
|
public void setOnUpdateLayoutListener(Runnable onUpdateLayoutListener) {
|
||||||
*/
|
this.onUpdateLayoutListener = onUpdateLayoutListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCustomDraw(Canvas canvas) {
|
protected void onCustomDraw(Canvas canvas) {
|
||||||
//Log.d(TAG, "onCustomDraw()");
|
//Log.d(TAG, "onCustomDraw()");
|
||||||
|
@ -307,17 +311,13 @@ public class MainScreenView extends PanAndScaleView {
|
||||||
canvas.drawBitmap(bitmapMainScreen, 0, 0, paint);
|
canvas.drawBitmap(bitmapMainScreen, 0, 0, paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
final int CALLBACK_TYPE_INVALIDATE = 0;
|
|
||||||
final int CALLBACK_TYPE_WINDOW_RESIZE = 1;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public int updateCallback(int type, int param1, int param2, String param3, String param4) {
|
public int updateCallback(int type, int param1, int param2, String param3, String param4) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case CALLBACK_TYPE_INVALIDATE:
|
case NativeLib.CALLBACK_TYPE_INVALIDATE:
|
||||||
//Log.d(TAG, "PAINT updateCallback() postInvalidate()");
|
//Log.d(TAG, "PAINT updateCallback() postInvalidate()");
|
||||||
postInvalidate();
|
postInvalidate();
|
||||||
break;
|
break;
|
||||||
case CALLBACK_TYPE_WINDOW_RESIZE:
|
case NativeLib.CALLBACK_TYPE_WINDOW_RESIZE:
|
||||||
// New Bitmap size
|
// New Bitmap size
|
||||||
if(bitmapMainScreen == null || bitmapMainScreen.getWidth() != param1 || bitmapMainScreen.getHeight() != param2) {
|
if(bitmapMainScreen == null || bitmapMainScreen.getWidth() != param1 || bitmapMainScreen.getHeight() != param2) {
|
||||||
if(debug) Log.d(TAG, "updateCallback() Bitmap.createBitmap(x: " + Math.max(1, param1) + ", y: " + Math.max(1, param2) + ")");
|
if(debug) Log.d(TAG, "updateCallback() Bitmap.createBitmap(x: " + Math.max(1, param1) + ", y: " + Math.max(1, param2) + ")");
|
||||||
|
@ -337,16 +337,11 @@ public class MainScreenView extends PanAndScaleView {
|
||||||
if(viewSized)
|
if(viewSized)
|
||||||
updateLayout();
|
updateLayout();
|
||||||
}
|
}
|
||||||
//postInvalidate();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bitmap getBitmapMainScreen() {
|
|
||||||
return bitmapMainScreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRotationMode(int rotationMode, boolean isDynamic) {
|
public void setRotationMode(int rotationMode, boolean isDynamic) {
|
||||||
this.rotationMode = rotationMode;
|
this.rotationMode = rotationMode;
|
||||||
if(isDynamic) {
|
if(isDynamic) {
|
||||||
|
|
|
@ -24,9 +24,13 @@ public class NativeLib {
|
||||||
System.loadLibrary("native-lib");
|
System.loadLibrary("native-lib");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static native void start(AssetManager mgr, Bitmap bitmapMainScreen, Activity activity, MainScreenView view);
|
public static final int CALLBACK_TYPE_INVALIDATE = 0;
|
||||||
|
public static final int CALLBACK_TYPE_WINDOW_RESIZE = 1;
|
||||||
|
|
||||||
|
public static native void start(AssetManager mgr, Activity activity);
|
||||||
public static native void stop();
|
public static native void stop();
|
||||||
public static native void changeBitmap(Bitmap bitmapMainScreen);
|
public static native void changeBitmap(Bitmap bitmapMainScreen);
|
||||||
|
public static native boolean copyLCD(Bitmap bitmapLCD);
|
||||||
public static native void draw();
|
public static native void draw();
|
||||||
public static native boolean buttonDown(int x, int y);
|
public static native boolean buttonDown(int x, int y);
|
||||||
public static native void buttonUp(int x, int y);
|
public static native void buttonUp(int x, int y);
|
||||||
|
@ -71,6 +75,8 @@ public class NativeLib {
|
||||||
public static native void setConfiguration(String key, int isDynamic, int intValue1, int intValue2, String stringValue);
|
public static native void setConfiguration(String key, int isDynamic, int intValue1, int intValue2, String stringValue);
|
||||||
public static native boolean isPortExtensionPossible();
|
public static native boolean isPortExtensionPossible();
|
||||||
public static native int getState();
|
public static native int getState();
|
||||||
|
public static native int getScreenPositionX();
|
||||||
|
public static native int getScreenPositionY();
|
||||||
public static native int getScreenWidth();
|
public static native int getScreenWidth();
|
||||||
public static native int getScreenHeight();
|
public static native int getScreenHeight();
|
||||||
}
|
}
|
||||||
|
|
|
@ -528,13 +528,13 @@ public class PanAndScaleView extends View {
|
||||||
// Keep the panning limits and the image centered.
|
// Keep the panning limits and the image centered.
|
||||||
float viewWidth = viewSizeWidth;
|
float viewWidth = viewSizeWidth;
|
||||||
float viewHeight = viewSizeHeight;
|
float viewHeight = viewSizeHeight;
|
||||||
if(viewWidth == 0.0f){
|
if(viewWidth == 0.0f) {
|
||||||
viewWidth = 1.0f;
|
viewWidth = 1.0f;
|
||||||
viewHeight = 1.0f;
|
viewHeight = 1.0f;
|
||||||
}
|
}
|
||||||
float virtualWidth = virtualSizeWidth;
|
float virtualWidth = virtualSizeWidth;
|
||||||
float virtualHeight = virtualSizeHeight;
|
float virtualHeight = virtualSizeHeight;
|
||||||
if(virtualWidth == 0.0f){
|
if(virtualWidth == 0.0f) {
|
||||||
virtualWidth = 1.0f;
|
virtualWidth = 1.0f;
|
||||||
virtualHeight = 1.0f;
|
virtualHeight = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,9 @@ import android.view.MenuItem;
|
||||||
import android.view.SubMenu;
|
import android.view.SubMenu;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
@ -56,6 +58,7 @@ import com.google.android.material.navigation.NavigationView;
|
||||||
|
|
||||||
import org.emulator.calculator.InfoActivity;
|
import org.emulator.calculator.InfoActivity;
|
||||||
import org.emulator.calculator.InfoWebActivity;
|
import org.emulator.calculator.InfoWebActivity;
|
||||||
|
import org.emulator.calculator.LCDOverlappingView;
|
||||||
import org.emulator.calculator.MainScreenView;
|
import org.emulator.calculator.MainScreenView;
|
||||||
import org.emulator.calculator.NativeLib;
|
import org.emulator.calculator.NativeLib;
|
||||||
import org.emulator.calculator.PrinterSimulator;
|
import org.emulator.calculator.PrinterSimulator;
|
||||||
|
@ -69,6 +72,7 @@ import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -92,6 +96,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
private NavigationView navigationView;
|
private NavigationView navigationView;
|
||||||
private DrawerLayout drawer;
|
private DrawerLayout drawer;
|
||||||
private MainScreenView mainScreenView;
|
private MainScreenView mainScreenView;
|
||||||
|
private LCDOverlappingView lcdOverlappingView;
|
||||||
private ImageButton imageButtonMenu;
|
private ImageButton imageButtonMenu;
|
||||||
|
|
||||||
public static final int INTENT_GETOPENFILENAME = 1;
|
public static final int INTENT_GETOPENFILENAME = 1;
|
||||||
|
@ -127,6 +132,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
|
|
||||||
private PrinterSimulator printerSimulator = new PrinterSimulator();
|
private PrinterSimulator printerSimulator = new PrinterSimulator();
|
||||||
private PrinterSimulatorFragment fragmentPrinterSimulator = new PrinterSimulatorFragment();
|
private PrinterSimulatorFragment fragmentPrinterSimulator = new PrinterSimulatorFragment();
|
||||||
|
private Bitmap bitmapIcon;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -151,23 +157,23 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
mainScreenView = new MainScreenView(this);
|
mainScreenView = new MainScreenView(this);
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||||
mainScreenView.setStatusBarColor(getWindow().getStatusBarColor());
|
mainScreenView.setStatusBarColor(getWindow().getStatusBarColor());
|
||||||
mainScreenView.setLayoutParams(new ViewGroup.LayoutParams(
|
mainScreenContainer.addView(mainScreenView, 0, new ViewGroup.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||||
mainScreenContainer.addView(mainScreenView, 0);
|
|
||||||
|
lcdOverlappingView = new LCDOverlappingView(this, mainScreenView);
|
||||||
|
lcdOverlappingView.setVisibility(View.GONE);
|
||||||
|
mainScreenContainer.addView(lcdOverlappingView, 1, new FrameLayout.LayoutParams(0, 0));
|
||||||
|
|
||||||
imageButtonMenu = findViewById(R.id.button_menu);
|
imageButtonMenu = findViewById(R.id.button_menu);
|
||||||
imageButtonMenu.setOnClickListener(new View.OnClickListener() {
|
imageButtonMenu.setOnClickListener(v -> {
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
if(drawer != null)
|
if(drawer != null)
|
||||||
drawer.openDrawer(GravityCompat.START);
|
drawer.openDrawer(GravityCompat.START);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
showCalculatorView(false);
|
showCalculatorView(false);
|
||||||
|
|
||||||
AssetManager assetManager = getResources().getAssets();
|
AssetManager assetManager = getResources().getAssets();
|
||||||
NativeLib.start(assetManager, mainScreenView.getBitmapMainScreen(), this, mainScreenView);
|
NativeLib.start(assetManager, this);
|
||||||
|
|
||||||
// By default Port1 is set
|
// By default Port1 is set
|
||||||
setPort1Settings(true, true);
|
setPort1Settings(true, true);
|
||||||
|
@ -278,6 +284,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
editor.putStringSet("MRU", mruLinkedHashMap.keySet());
|
editor.putStringSet("MRU", mruLinkedHashMap.keySet());
|
||||||
editor.apply();
|
editor.apply();
|
||||||
|
|
||||||
|
if(lcdOverlappingView != null)
|
||||||
|
lcdOverlappingView.saveViewLayout();
|
||||||
|
|
||||||
super.onStop();
|
super.onStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -842,9 +851,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
new AlertDialog.Builder(MainActivity.this)
|
new AlertDialog.Builder(MainActivity.this)
|
||||||
.setTitle(getString(R.string.message_kml_folder_selection_need_api_lollipop))
|
.setTitle(getString(R.string.message_kml_folder_selection_need_api_lollipop))
|
||||||
.setMessage(getString(R.string.message_kml_folder_selection_need_api_lollipop_description))
|
.setMessage(getString(R.string.message_kml_folder_selection_need_api_lollipop_description))
|
||||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
.setPositiveButton(android.R.string.ok, (dialog1, which1) -> {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
}
|
|
||||||
}).show();
|
}).show();
|
||||||
} else {
|
} else {
|
||||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||||
|
@ -880,9 +887,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
String[] stringArrayRAMCards = getResources().getStringArray(R.array.ram_cards);
|
String[] stringArrayRAMCards = getResources().getStringArray(R.array.ram_cards);
|
||||||
new AlertDialog.Builder(MainActivity.this)
|
new AlertDialog.Builder(MainActivity.this)
|
||||||
.setTitle(getResources().getString(R.string.create_ram_card_title))
|
.setTitle(getResources().getString(R.string.create_ram_card_title))
|
||||||
.setItems(stringArrayRAMCards, new DialogInterface.OnClickListener() {
|
.setItems(stringArrayRAMCards, (dialog, which) -> {
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
intent.setType("*/*");
|
intent.setType("*/*");
|
||||||
|
@ -920,7 +925,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
}
|
}
|
||||||
intent.putExtra(Intent.EXTRA_TITLE, "shared-" + sizeTitle + ".bin");
|
intent.putExtra(Intent.EXTRA_TITLE, "shared-" + sizeTitle + ".bin");
|
||||||
startActivityForResult(intent, INTENT_CREATE_RAM_CARD);
|
startActivityForResult(intent, INTENT_CREATE_RAM_CARD);
|
||||||
}
|
|
||||||
}).show();
|
}).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -941,12 +945,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMacroStop() {
|
private void OnMacroStop() {
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(() -> {
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
NativeLib.onToolMacroStop();
|
NativeLib.onToolMacroStop();
|
||||||
updateNavigationDrawerItems();
|
updateNavigationDrawerItems();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1003,11 +1004,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
new AlertDialog.Builder(this)
|
new AlertDialog.Builder(this)
|
||||||
.setTitle(getString(R.string.message_open_security))
|
.setTitle(getString(R.string.message_open_security))
|
||||||
.setMessage(getString(R.string.message_open_security_description))
|
.setMessage(getString(R.string.message_open_security_description))
|
||||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||||
startActivityForResult(intent, INTENT_PICK_KML_FOLDER_FOR_SECURITY);
|
startActivityForResult(intent, INTENT_PICK_KML_FOLDER_FOR_SECURITY);
|
||||||
}
|
|
||||||
}).show();
|
}).show();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1059,9 +1058,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
new AlertDialog.Builder(this)
|
new AlertDialog.Builder(this)
|
||||||
.setTitle(getString(R.string.message_open_security_retry))
|
.setTitle(getString(R.string.message_open_security_retry))
|
||||||
.setMessage(getString(R.string.message_open_security_retry_description))
|
.setMessage(getString(R.string.message_open_security_retry_description))
|
||||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
}
|
|
||||||
}).show();
|
}).show();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1122,11 +1119,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
|
|
||||||
if(url != null && !url.isEmpty())
|
if(url != null && !url.isEmpty())
|
||||||
mruLinkedHashMap.put(url, null);
|
mruLinkedHashMap.put(url, null);
|
||||||
navigationView.post(new Runnable() {
|
navigationView.post(this::updateMRU);
|
||||||
public void run() {
|
|
||||||
updateMRU();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void makeUriPersistable(Intent data, Uri uri) {
|
private void makeUriPersistable(Intent data, Uri uri) {
|
||||||
|
@ -1167,11 +1160,13 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
|
|
||||||
private void displayFilename(String url) {
|
private void displayFilename(String url) {
|
||||||
String displayName = getFilenameFromURL(url);
|
String displayName = getFilenameFromURL(url);
|
||||||
View header = displayKMLTitle();
|
View headerView = displayKMLTitle();
|
||||||
TextView textViewSubtitle = header.findViewById(R.id.nav_header_subtitle);
|
if(headerView != null) {
|
||||||
if(textViewSubtitle != null)
|
TextView textViewSubtitle = headerView.findViewById(R.id.nav_header_subtitle);
|
||||||
|
if (textViewSubtitle != null)
|
||||||
textViewSubtitle.setText(displayName);
|
textViewSubtitle.setText(displayName);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String getFilenameFromURL(String url) {
|
private String getFilenameFromURL(String url) {
|
||||||
String displayName = "";
|
String displayName = "";
|
||||||
|
@ -1184,12 +1179,32 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
}
|
}
|
||||||
|
|
||||||
private View displayKMLTitle() {
|
private View displayKMLTitle() {
|
||||||
|
View headerView = null;
|
||||||
NavigationView navigationView = findViewById(R.id.nav_view);
|
NavigationView navigationView = findViewById(R.id.nav_view);
|
||||||
View header = navigationView.getHeaderView(0);
|
if (navigationView != null) {
|
||||||
TextView textViewTitle = header.findViewById(R.id.nav_header_title);
|
headerView = navigationView.getHeaderView(0);
|
||||||
if(textViewTitle != null)
|
if (headerView != null) {
|
||||||
|
TextView textViewTitle = headerView.findViewById(R.id.nav_header_title);
|
||||||
|
if (textViewTitle != null)
|
||||||
textViewTitle.setText(NativeLib.getKMLTitle());
|
textViewTitle.setText(NativeLib.getKMLTitle());
|
||||||
return header;
|
changeHeaderIcon();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return headerView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changeHeaderIcon() {
|
||||||
|
NavigationView navigationView = findViewById(R.id.nav_view);
|
||||||
|
View headerView = navigationView.getHeaderView(0);
|
||||||
|
if (headerView != null) {
|
||||||
|
ImageView imageViewIcon = headerView.findViewById(R.id.nav_header_icon);
|
||||||
|
if (imageViewIcon != null) {
|
||||||
|
if (bitmapIcon != null)
|
||||||
|
imageViewIcon.setImageBitmap(bitmapIcon);
|
||||||
|
else
|
||||||
|
imageViewIcon.setImageDrawable(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showKMLLog() {
|
private void showKMLLog() {
|
||||||
|
@ -1203,14 +1218,21 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
new AlertDialog.Builder(this)
|
new AlertDialog.Builder(this)
|
||||||
.setTitle(getString(R.string.message_kml_script_compilation_result))
|
.setTitle(getString(R.string.message_kml_script_compilation_result))
|
||||||
.setMessage(kmlLog)
|
.setMessage(kmlLog)
|
||||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
}
|
|
||||||
}).show();
|
}).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method used from JNI!
|
// Method used from JNI!
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public int updateCallback(int type, int param1, int param2, String param3, String param4) {
|
||||||
|
|
||||||
|
mainScreenView.updateCallback(type, param1, param2, param3, param4);
|
||||||
|
lcdOverlappingView.updateCallback(type, param1, param2, param3, param4);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
final int GENERIC_READ = 1;
|
final int GENERIC_READ = 1;
|
||||||
final int GENERIC_WRITE = 2;
|
final int GENERIC_WRITE = 2;
|
||||||
SparseArray<ParcelFileDescriptor> parcelFileDescriptorPerFd = null;
|
SparseArray<ParcelFileDescriptor> parcelFileDescriptorPerFd = null;
|
||||||
|
@ -1421,6 +1443,25 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
printerSimulator.write(byteSent);
|
printerSimulator.write(byteSent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public synchronized void setKMLIcon(int imageWidth, int imageHeight, byte[] pixels) {
|
||||||
|
if(imageWidth > 0 && imageHeight > 0 && pixels != null) {
|
||||||
|
try {
|
||||||
|
bitmapIcon = Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888);
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(pixels);
|
||||||
|
bitmapIcon.copyPixelsFromBuffer(buffer);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
// Cannot load the icon
|
||||||
|
bitmapIcon.recycle();
|
||||||
|
bitmapIcon = null;
|
||||||
|
}
|
||||||
|
} else if(bitmapIcon != null) {
|
||||||
|
bitmapIcon.recycle();
|
||||||
|
bitmapIcon = null;
|
||||||
|
}
|
||||||
|
changeHeaderIcon();
|
||||||
|
}
|
||||||
|
|
||||||
private void setPort1Settings(boolean port1Plugged, boolean port1Writable) {
|
private void setPort1Settings(boolean port1Plugged, boolean port1Writable) {
|
||||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
editor.putBoolean("settings_port1en", port1Plugged);
|
editor.putBoolean("settings_port1en", port1Plugged);
|
||||||
|
@ -1433,7 +1474,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
int isDynamicValue = isDynamic ? 1 : 0;
|
int isDynamicValue = isDynamic ? 1 : 0;
|
||||||
if(key == null) {
|
if(key == null) {
|
||||||
String[] settingKeys = {
|
String[] settingKeys = {
|
||||||
"settings_realspeed", "settings_grayscale", "settings_rotation", "settings_auto_layout", "settings_allow_pinch_zoom",
|
"settings_realspeed", "settings_grayscale", "settings_rotation", "settings_auto_layout", "settings_allow_pinch_zoom", "settings_lcd_overlapping_mode",
|
||||||
"settings_hide_bar", "settings_hide_button_menu", "settings_sound_volume", "settings_haptic_feedback",
|
"settings_hide_bar", "settings_hide_button_menu", "settings_sound_volume", "settings_haptic_feedback",
|
||||||
"settings_background_kml_color", "settings_background_fallback_color",
|
"settings_background_kml_color", "settings_background_fallback_color",
|
||||||
"settings_printer_model", "settings_printer_prevent_line_wrap", "settings_macro",
|
"settings_printer_model", "settings_printer_prevent_line_wrap", "settings_macro",
|
||||||
|
@ -1471,6 +1512,15 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
case "settings_allow_pinch_zoom":
|
case "settings_allow_pinch_zoom":
|
||||||
mainScreenView.setAllowPinchZoom(sharedPreferences.getBoolean("settings_allow_pinch_zoom", true));
|
mainScreenView.setAllowPinchZoom(sharedPreferences.getBoolean("settings_allow_pinch_zoom", true));
|
||||||
break;
|
break;
|
||||||
|
case "settings_lcd_overlapping_mode":
|
||||||
|
int overlappingLCDMode = 0;
|
||||||
|
try {
|
||||||
|
overlappingLCDMode = Integer.parseInt(sharedPreferences.getString("settings_lcd_overlapping_mode", "0"));
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
// Catch bad number format
|
||||||
|
}
|
||||||
|
lcdOverlappingView.setOverlappingLCDMode(overlappingLCDMode, isDynamic);
|
||||||
|
break;
|
||||||
case "settings_hide_bar":
|
case "settings_hide_bar":
|
||||||
case "settings_hide_bar_status":
|
case "settings_hide_bar_status":
|
||||||
case "settings_hide_bar_nav":
|
case "settings_hide_bar_nav":
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:id="@+id/main_screen_container"
|
android:id="@+id/main_screen_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="fill_parent"
|
||||||
android:background="#00808080"
|
android:background="#00808080">
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
|
||||||
tools:showIn="@layout/activity_main">
|
|
||||||
|
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/button_menu"
|
android:id="@+id/button_menu"
|
||||||
|
@ -18,7 +13,5 @@
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:src="@drawable/ic_more_vert_black_24dp"
|
android:src="@drawable/ic_more_vert_black_24dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
android:contentDescription="@string/button_main_menu_content_description" />
|
android:contentDescription="@string/button_main_menu_content_description" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</FrameLayout>
|
|
@ -1,29 +1,52 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/linearLayout"
|
||||||
android:layout_height="90dp"
|
|
||||||
android:background="@drawable/side_nav_bar"
|
|
||||||
android:gravity="bottom"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/nav_header_title"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/side_nav_bar"
|
||||||
|
android:gravity="bottom"
|
||||||
|
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/nav_header_icon"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:contentDescription="@string/nav_header_desc"
|
||||||
android:paddingTop="@dimen/nav_header_vertical_spacing"
|
android:paddingTop="@dimen/nav_header_vertical_spacing"
|
||||||
android:text=""
|
app:layout_constraintBottom_toTopOf="@+id/nav_header_title"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/nav_header_subtitle"
|
android:id="@+id/nav_header_subtitle"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
android:paddingTop="@dimen/nav_header_vertical_spacing"
|
android:paddingTop="@dimen/nav_header_vertical_spacing"
|
||||||
android:text=""
|
android:text=""
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/nav_header_icon"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/nav_header_icon" />
|
||||||
|
|
||||||
</LinearLayout>
|
<TextView
|
||||||
|
android:id="@+id/nav_header_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:paddingTop="@dimen/nav_header_vertical_spacing"
|
||||||
|
android:text=""
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
@ -36,6 +36,17 @@
|
||||||
<item>2</item>
|
<item>2</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="settings_lcd_overlapping_mode_item">
|
||||||
|
<item>No Overlapping LCD</item>
|
||||||
|
<item>Auto</item>
|
||||||
|
<item>Manual</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="settings_lcd_overlapping_mode_value">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string-array name="ram_cards">
|
<string-array name="ram_cards">
|
||||||
<item>32kb (1 port: 2)</item>
|
<item>32kb (1 port: 2)</item>
|
||||||
<item>128kb (1 port: 2)</item>
|
<item>128kb (1 port: 2)</item>
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
<string name="action_settings">Settings</string>
|
<string name="action_settings">Settings</string>
|
||||||
<string name="navigation_drawer_open">Open navigation drawer</string>
|
<string name="navigation_drawer_open">Open navigation drawer</string>
|
||||||
<string name="navigation_drawer_close">Close navigation drawer</string>
|
<string name="navigation_drawer_close">Close navigation drawer</string>
|
||||||
|
<string name="nav_header_desc">Navigation header</string>
|
||||||
<string name="button_main_menu_content_description">Open the main menu</string>
|
<string name="button_main_menu_content_description">Open the main menu</string>
|
||||||
<string name="nav_new">New...</string>
|
<string name="nav_new">New...</string>
|
||||||
<string name="nav_open">Open...</string>
|
<string name="nav_open">Open...</string>
|
||||||
|
@ -84,7 +85,7 @@
|
||||||
<string name="message_printer_share_text">Save printer paper as text</string>
|
<string name="message_printer_share_text">Save printer paper as text</string>
|
||||||
<string name="message_printer_share_graphic">Save printer paper as image</string>
|
<string name="message_printer_share_graphic">Save printer paper as image</string>
|
||||||
<string name="message_printer_out_of_paper">Out of paper error for the graphic printer (max line: %d, max pixel line: %d).</string>
|
<string name="message_printer_out_of_paper">Out of paper error for the graphic printer (max line: %d, max pixel line: %d).</string>
|
||||||
|
<string name="message_change_overlapping_lcd_mode_to_manual">The overlapping LCD mode has been changed to "Manual".</string>
|
||||||
|
|
||||||
|
|
||||||
<string name="settings_category_general_title">General</string>
|
<string name="settings_category_general_title">General</string>
|
||||||
|
@ -102,6 +103,8 @@
|
||||||
<string name="settings_rotation_summary">Allow to rotate, or force Portrait or Landscape orientation</string>
|
<string name="settings_rotation_summary">Allow to rotate, or force Portrait or Landscape orientation</string>
|
||||||
|
|
||||||
<string name="settings_allow_pinch_zoom_title">Allow to pinch to zoom</string>
|
<string name="settings_allow_pinch_zoom_title">Allow to pinch to zoom</string>
|
||||||
|
<string name="settings_lcd_overlapping_mode_title">Overlapping LCD mode</string>
|
||||||
|
<string name="settings_lcd_overlapping_mode_summary">Select the overlapping LCD mode. A pan or pinch gesture will change the mode to manual.</string>
|
||||||
|
|
||||||
<string name="settings_hide_bar_status">Hide the status bar</string>
|
<string name="settings_hide_bar_status">Hide the status bar</string>
|
||||||
<string name="settings_hide_bar_nav">Hide the navigation bar</string>
|
<string name="settings_hide_bar_nav">Hide the navigation bar</string>
|
||||||
|
|
|
@ -48,6 +48,17 @@
|
||||||
android:key="settings_allow_pinch_zoom"
|
android:key="settings_allow_pinch_zoom"
|
||||||
android:title="@string/settings_allow_pinch_zoom_title"
|
android:title="@string/settings_allow_pinch_zoom_title"
|
||||||
android:defaultValue="true" />
|
android:defaultValue="true" />
|
||||||
|
<ListPreference
|
||||||
|
android:key="settings_lcd_overlapping_mode"
|
||||||
|
android:title="@string/settings_lcd_overlapping_mode_title"
|
||||||
|
android:dialogTitle="@string/settings_lcd_overlapping_mode_title"
|
||||||
|
android:summary="@string/settings_lcd_overlapping_mode_summary"
|
||||||
|
android:entries="@array/settings_lcd_overlapping_mode_item"
|
||||||
|
android:entryValues="@array/settings_lcd_overlapping_mode_value"
|
||||||
|
android:defaultValue="0"
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:key="settings_hide_bar_status"
|
android:key="settings_hide_bar_status"
|
||||||
android:title="@string/settings_hide_bar_status"
|
android:title="@string/settings_hide_bar_status"
|
||||||
|
|
Loading…
Reference in a new issue