mirror of
https://github.com/dgis/emu48android
synced 2024-12-26 09:58:49 +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"
|
||||
|
||||
extern AAssetManager * assetManager;
|
||||
static jobject viewToUpdate = NULL;
|
||||
static jobject mainActivity = NULL;
|
||||
jobject bitmapMainScreen;
|
||||
jobject bitmapMainScreen = NULL;
|
||||
AndroidBitmapInfo androidBitmapInfo;
|
||||
enum DialogBoxMode currentDialogBoxMode;
|
||||
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
|
||||
int mainViewCallback(int type, int param1, int param2, const TCHAR * param3, const TCHAR * param4) {
|
||||
if (viewToUpdate) {
|
||||
if (mainActivity) {
|
||||
JNIEnv *jniEnv = getJNIEnvironment();
|
||||
if(jniEnv) {
|
||||
jclass viewToUpdateClass = (*jniEnv)->GetObjectClass(jniEnv, viewToUpdate);
|
||||
if(viewToUpdateClass) {
|
||||
jmethodID midStr = (*jniEnv)->GetMethodID(jniEnv, viewToUpdateClass, "updateCallback", "(IIILjava/lang/String;Ljava/lang/String;)I");
|
||||
jclass mainActivityClass = (*jniEnv)->GetObjectClass(jniEnv, mainActivity);
|
||||
if(mainActivityClass) {
|
||||
jmethodID midStr = (*jniEnv)->GetMethodID(jniEnv, mainActivityClass, "updateCallback", "(IIILjava/lang/String;Ljava/lang/String;)I");
|
||||
jstring utfParam3 = (*jniEnv)->NewStringUTF(jniEnv, param3);
|
||||
jstring utfParam4 = (*jniEnv)->NewStringUTF(jniEnv, param4);
|
||||
int result = (*jniEnv)->CallIntMethod(jniEnv, viewToUpdate, midStr, type, param1, param2, utfParam3, utfParam4);
|
||||
(*jniEnv)->DeleteLocalRef(jniEnv, viewToUpdateClass);
|
||||
int result = (*jniEnv)->CallIntMethod(jniEnv, mainActivity, midStr, type, param1, param2, utfParam3, utfParam4);
|
||||
(*jniEnv)->DeleteLocalRef(jniEnv, mainActivityClass);
|
||||
//if(needDetach) ret = (*java_machine)->DetachCurrentThread(java_machine);
|
||||
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;
|
||||
szChosenCurrentKml[0] = '\0';
|
||||
|
||||
bitmapMainScreen = (*env)->NewGlobalRef(env, bitmapMainScreen0);
|
||||
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);
|
||||
|
||||
|
@ -394,10 +403,6 @@ JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_stop(JNIEnv *env,
|
|||
SoundClose(); // close waveform-audio output device
|
||||
soundEnabled = FALSE;
|
||||
|
||||
if (viewToUpdate) {
|
||||
(*env)->DeleteGlobalRef(env, viewToUpdate);
|
||||
viewToUpdate = NULL;
|
||||
}
|
||||
if(bitmapMainScreen) {
|
||||
(*env)->DeleteGlobalRef(env, bitmapMainScreen);
|
||||
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) {
|
||||
draw();
|
||||
|
@ -1117,6 +1190,12 @@ JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_getState(JNIEnv *e
|
|||
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) {
|
||||
return 131*nLcdZoom*nGdiXZoom;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include "core/resource.h"
|
||||
#include "win32-layer.h"
|
||||
#include "emu.h"
|
||||
#include "core/lodepng.h"
|
||||
|
||||
|
||||
extern JavaVM *java_machine;
|
||||
extern jobject bitmapMainScreen;
|
||||
|
@ -837,9 +839,189 @@ BOOL GetSaveFileName(LPOPENFILENAME openFilename) {
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
HANDLE LoadImage(HINSTANCE hInst, LPCSTR name, UINT type, int cx, int cy, UINT fuLoad) {
|
||||
//TODO
|
||||
// Almost the same function as the private core function DibNumColors()
|
||||
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;
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -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);
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -1996,8 +2187,7 @@ HBITMAP CreateBitmap( int nWidth, int nHeight, UINT nPlanes, UINT nBitCount, CON
|
|||
|
||||
BITMAPINFO * newBitmapInfo = malloc(sizeof(BITMAPINFO));
|
||||
memset(newBitmapInfo, 0, sizeof(BITMAPINFO));
|
||||
//newBitmapInfo->bmiHeader.biBitCount = 32; //TODO should be nBitCount
|
||||
newBitmapInfo->bmiHeader.biBitCount = nBitCount; //TODO should be nBitCount
|
||||
newBitmapInfo->bmiHeader.biBitCount = (WORD) nBitCount;
|
||||
newBitmapInfo->bmiHeader.biClrUsed = 0;
|
||||
newBitmapInfo->bmiHeader.biWidth = nWidth;
|
||||
newBitmapInfo->bmiHeader.biHeight = -nHeight;
|
||||
|
|
|
@ -507,20 +507,24 @@ enum HANDLE_TYPE {
|
|||
HANDLE_TYPE_EVENT,
|
||||
HANDLE_TYPE_THREAD,
|
||||
HANDLE_TYPE_WINDOW,
|
||||
HANDLE_TYPE_ICON,
|
||||
};
|
||||
struct _HANDLE {
|
||||
enum HANDLE_TYPE handleType;
|
||||
|
||||
// HANDLE_TYPE_FILE*
|
||||
int fileDescriptor;
|
||||
BOOL fileOpenFileFromContentResolver;
|
||||
|
||||
AAsset* fileAsset;
|
||||
|
||||
// HANDLE_TYPE_FILE_MAPPING*
|
||||
off_t fileMappingOffset;
|
||||
size_t fileMappingSize;
|
||||
void* fileMappingAddress;
|
||||
DWORD fileMappingProtect;
|
||||
|
||||
// HANDLE_TYPE_THREAD
|
||||
pthread_t threadId;
|
||||
DWORD (*threadStartAddress)(LPVOID);
|
||||
LPVOID threadParameter;
|
||||
|
@ -528,12 +532,17 @@ struct _HANDLE {
|
|||
struct tagMSG threadMessage;
|
||||
int threadIndex;
|
||||
|
||||
// HANDLE_TYPE_EVENT
|
||||
pthread_cond_t eventCVariable;
|
||||
pthread_mutex_t eventMutex;
|
||||
BOOL eventAutoReset;
|
||||
BOOL eventState;
|
||||
|
||||
// HANDLE_TYPE_WINDOW
|
||||
HDC windowDC;
|
||||
|
||||
// HANDLE_TYPE_ICON
|
||||
HBITMAP icon;
|
||||
};
|
||||
typedef struct _HANDLE * HANDLE;
|
||||
|
||||
|
@ -1227,6 +1236,7 @@ void clipboardCopyText(const TCHAR * text);
|
|||
const TCHAR * clipboardPasteText();
|
||||
void performHapticFeedback();
|
||||
void sendByteUdp(unsigned char byteSent);
|
||||
void setKMLIcon(int imageWidth, int imageHeight, LPBYTE buffer, int bufferSize);
|
||||
|
||||
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();
|
||||
((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);
|
||||
enableZoomKeyboard = false;
|
||||
|
||||
|
@ -153,10 +153,6 @@ public class MainScreenView extends PanAndScaleView {
|
|||
|
||||
this.setFocusable(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
|
||||
|
@ -285,6 +281,8 @@ public class MainScreenView extends PanAndScaleView {
|
|||
viewPanOffsetY = translateY;
|
||||
|
||||
constrainPan();
|
||||
if(this.onUpdateLayoutListener != null)
|
||||
this.onUpdateLayoutListener.run();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -292,13 +290,19 @@ public class MainScreenView extends PanAndScaleView {
|
|||
}
|
||||
// Else, the screens orientations are the same, so we set the calculator in fullscreen
|
||||
resetViewport();
|
||||
|
||||
if(this.onUpdateLayoutListener != null)
|
||||
this.onUpdateLayoutListener.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the score.
|
||||
* @param canvas The canvas to draw to coming from the View.onDraw() method.
|
||||
*/
|
||||
private Runnable onUpdateLayoutListener = null;
|
||||
|
||||
public void setOnUpdateLayoutListener(Runnable onUpdateLayoutListener) {
|
||||
this.onUpdateLayoutListener = onUpdateLayoutListener;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCustomDraw(Canvas canvas) {
|
||||
//Log.d(TAG, "onCustomDraw()");
|
||||
|
@ -307,17 +311,13 @@ public class MainScreenView extends PanAndScaleView {
|
|||
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) {
|
||||
switch (type) {
|
||||
case CALLBACK_TYPE_INVALIDATE:
|
||||
case NativeLib.CALLBACK_TYPE_INVALIDATE:
|
||||
//Log.d(TAG, "PAINT updateCallback() postInvalidate()");
|
||||
postInvalidate();
|
||||
break;
|
||||
case CALLBACK_TYPE_WINDOW_RESIZE:
|
||||
case NativeLib.CALLBACK_TYPE_WINDOW_RESIZE:
|
||||
// New Bitmap size
|
||||
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) + ")");
|
||||
|
@ -337,16 +337,11 @@ public class MainScreenView extends PanAndScaleView {
|
|||
if(viewSized)
|
||||
updateLayout();
|
||||
}
|
||||
//postInvalidate();
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public Bitmap getBitmapMainScreen() {
|
||||
return bitmapMainScreen;
|
||||
}
|
||||
|
||||
public void setRotationMode(int rotationMode, boolean isDynamic) {
|
||||
this.rotationMode = rotationMode;
|
||||
if(isDynamic) {
|
||||
|
|
|
@ -24,9 +24,13 @@ public class NativeLib {
|
|||
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 changeBitmap(Bitmap bitmapMainScreen);
|
||||
public static native boolean copyLCD(Bitmap bitmapLCD);
|
||||
public static native void draw();
|
||||
public static native boolean buttonDown(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 boolean isPortExtensionPossible();
|
||||
public static native int getState();
|
||||
public static native int getScreenPositionX();
|
||||
public static native int getScreenPositionY();
|
||||
public static native int getScreenWidth();
|
||||
public static native int getScreenHeight();
|
||||
}
|
||||
|
|
|
@ -37,7 +37,9 @@ import android.view.MenuItem;
|
|||
import android.view.SubMenu;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
@ -56,6 +58,7 @@ import com.google.android.material.navigation.NavigationView;
|
|||
|
||||
import org.emulator.calculator.InfoActivity;
|
||||
import org.emulator.calculator.InfoWebActivity;
|
||||
import org.emulator.calculator.LCDOverlappingView;
|
||||
import org.emulator.calculator.MainScreenView;
|
||||
import org.emulator.calculator.NativeLib;
|
||||
import org.emulator.calculator.PrinterSimulator;
|
||||
|
@ -69,6 +72,7 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
|
@ -92,6 +96,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
private NavigationView navigationView;
|
||||
private DrawerLayout drawer;
|
||||
private MainScreenView mainScreenView;
|
||||
private LCDOverlappingView lcdOverlappingView;
|
||||
private ImageButton imageButtonMenu;
|
||||
|
||||
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 PrinterSimulatorFragment fragmentPrinterSimulator = new PrinterSimulatorFragment();
|
||||
private Bitmap bitmapIcon;
|
||||
|
||||
|
||||
@Override
|
||||
|
@ -151,23 +157,23 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
mainScreenView = new MainScreenView(this);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
|
||||
mainScreenView.setStatusBarColor(getWindow().getStatusBarColor());
|
||||
mainScreenView.setLayoutParams(new ViewGroup.LayoutParams(
|
||||
mainScreenContainer.addView(mainScreenView, 0, new ViewGroup.LayoutParams(
|
||||
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.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
imageButtonMenu.setOnClickListener(v -> {
|
||||
if(drawer != null)
|
||||
drawer.openDrawer(GravityCompat.START);
|
||||
}
|
||||
});
|
||||
showCalculatorView(false);
|
||||
|
||||
AssetManager assetManager = getResources().getAssets();
|
||||
NativeLib.start(assetManager, mainScreenView.getBitmapMainScreen(), this, mainScreenView);
|
||||
NativeLib.start(assetManager, this);
|
||||
|
||||
// By default Port1 is set
|
||||
setPort1Settings(true, true);
|
||||
|
@ -278,6 +284,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
editor.putStringSet("MRU", mruLinkedHashMap.keySet());
|
||||
editor.apply();
|
||||
|
||||
if(lcdOverlappingView != null)
|
||||
lcdOverlappingView.saveViewLayout();
|
||||
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
|
@ -842,9 +851,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
new AlertDialog.Builder(MainActivity.this)
|
||||
.setTitle(getString(R.string.message_kml_folder_selection_need_api_lollipop))
|
||||
.setMessage(getString(R.string.message_kml_folder_selection_need_api_lollipop_description))
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
}
|
||||
.setPositiveButton(android.R.string.ok, (dialog1, which1) -> {
|
||||
}).show();
|
||||
} else {
|
||||
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);
|
||||
new AlertDialog.Builder(MainActivity.this)
|
||||
.setTitle(getResources().getString(R.string.create_ram_card_title))
|
||||
.setItems(stringArrayRAMCards, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
.setItems(stringArrayRAMCards, (dialog, which) -> {
|
||||
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("*/*");
|
||||
|
@ -920,7 +925,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
}
|
||||
intent.putExtra(Intent.EXTRA_TITLE, "shared-" + sizeTitle + ".bin");
|
||||
startActivityForResult(intent, INTENT_CREATE_RAM_CARD);
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
|
@ -941,12 +945,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
}
|
||||
|
||||
private void OnMacroStop() {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
runOnUiThread(() -> {
|
||||
NativeLib.onToolMacroStop();
|
||||
updateNavigationDrawerItems();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1003,11 +1004,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
new AlertDialog.Builder(this)
|
||||
.setTitle(getString(R.string.message_open_security))
|
||||
.setMessage(getString(R.string.message_open_security_description))
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
startActivityForResult(intent, INTENT_PICK_KML_FOLDER_FOR_SECURITY);
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
break;
|
||||
|
@ -1059,9 +1058,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
new AlertDialog.Builder(this)
|
||||
.setTitle(getString(R.string.message_open_security_retry))
|
||||
.setMessage(getString(R.string.message_open_security_retry_description))
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
}
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
}).show();
|
||||
break;
|
||||
}
|
||||
|
@ -1122,11 +1119,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
|
||||
if(url != null && !url.isEmpty())
|
||||
mruLinkedHashMap.put(url, null);
|
||||
navigationView.post(new Runnable() {
|
||||
public void run() {
|
||||
updateMRU();
|
||||
}
|
||||
});
|
||||
navigationView.post(this::updateMRU);
|
||||
}
|
||||
|
||||
private void makeUriPersistable(Intent data, Uri uri) {
|
||||
|
@ -1167,11 +1160,13 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
|
||||
private void displayFilename(String url) {
|
||||
String displayName = getFilenameFromURL(url);
|
||||
View header = displayKMLTitle();
|
||||
TextView textViewSubtitle = header.findViewById(R.id.nav_header_subtitle);
|
||||
View headerView = displayKMLTitle();
|
||||
if(headerView != null) {
|
||||
TextView textViewSubtitle = headerView.findViewById(R.id.nav_header_subtitle);
|
||||
if (textViewSubtitle != null)
|
||||
textViewSubtitle.setText(displayName);
|
||||
}
|
||||
}
|
||||
|
||||
private String getFilenameFromURL(String url) {
|
||||
String displayName = "";
|
||||
|
@ -1184,12 +1179,32 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
}
|
||||
|
||||
private View displayKMLTitle() {
|
||||
View headerView = null;
|
||||
NavigationView navigationView = findViewById(R.id.nav_view);
|
||||
View header = navigationView.getHeaderView(0);
|
||||
TextView textViewTitle = header.findViewById(R.id.nav_header_title);
|
||||
if (navigationView != null) {
|
||||
headerView = navigationView.getHeaderView(0);
|
||||
if (headerView != null) {
|
||||
TextView textViewTitle = headerView.findViewById(R.id.nav_header_title);
|
||||
if (textViewTitle != null)
|
||||
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() {
|
||||
|
@ -1203,14 +1218,21 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
new AlertDialog.Builder(this)
|
||||
.setTitle(getString(R.string.message_kml_script_compilation_result))
|
||||
.setMessage(kmlLog)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
}
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
}).show();
|
||||
}
|
||||
|
||||
// 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_WRITE = 2;
|
||||
SparseArray<ParcelFileDescriptor> parcelFileDescriptorPerFd = null;
|
||||
|
@ -1421,6 +1443,25 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
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) {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putBoolean("settings_port1en", port1Plugged);
|
||||
|
@ -1433,7 +1474,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
int isDynamicValue = isDynamic ? 1 : 0;
|
||||
if(key == null) {
|
||||
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_background_kml_color", "settings_background_fallback_color",
|
||||
"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":
|
||||
mainScreenView.setAllowPinchZoom(sharedPreferences.getBoolean("settings_allow_pinch_zoom", true));
|
||||
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_status":
|
||||
case "settings_hide_bar_nav":
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/main_screen_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#00808080"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:showIn="@layout/activity_main">
|
||||
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="#00808080">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/button_menu"
|
||||
|
@ -18,7 +13,5 @@
|
|||
android:layout_marginTop="16dp"
|
||||
android:background="@android:color/transparent"
|
||||
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" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</FrameLayout>
|
|
@ -1,29 +1,52 @@
|
|||
<?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:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
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:id="@+id/linearLayout"
|
||||
android:layout_width="match_parent"
|
||||
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:text=""
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
|
||||
app:layout_constraintBottom_toTopOf="@+id/nav_header_title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/nav_header_subtitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:paddingTop="@dimen/nav_header_vertical_spacing"
|
||||
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>
|
||||
</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">
|
||||
<item>32kb (1 port: 2)</item>
|
||||
<item>128kb (1 port: 2)</item>
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
<string name="action_settings">Settings</string>
|
||||
<string name="navigation_drawer_open">Open 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="nav_new">New...</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_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_change_overlapping_lcd_mode_to_manual">The overlapping LCD mode has been changed to "Manual".</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_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_nav">Hide the navigation bar</string>
|
||||
|
|
|
@ -48,6 +48,17 @@
|
|||
android:key="settings_allow_pinch_zoom"
|
||||
android:title="@string/settings_allow_pinch_zoom_title"
|
||||
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
|
||||
android:key="settings_hide_bar_status"
|
||||
android:title="@string/settings_hide_bar_status"
|
||||
|
|
Loading…
Reference in a new issue