Add LCD pixel borders and add support for the dark theme.

This commit is contained in:
dgis 2020-04-09 00:34:18 +02:00
parent 44250272e7
commit 214f1df318
19 changed files with 138 additions and 89 deletions

View file

@ -63,9 +63,11 @@ LINKS
CHANGES
Version 1.8beta2 (2019-12-19)
Version 1.8beta3 (2020-04-XX)
- Intercept the ESC keyboard key to allow the use of the BACK soft key.
- Add LCD pixel borders.
- Add support for the dark theme.
Version 1.7 (2019-12-12)

View file

@ -10,8 +10,6 @@
android:resizeableActivity="true"
android:theme="@style/AppTheme"
android:fullBackupContent="@xml/backup_descriptor">
<!--android:icon="@mipmap/ic_launcher"-->
<!--android:roundIcon="@mipmap/ic_launcher_round"-->
<activity
android:name=".MainActivity"
android:label="@string/app_name"

View file

@ -1112,7 +1112,7 @@ JNIEXPORT void JNICALL Java_org_emulator_calculator_NativeLib_setConfiguration(J
}
JNIEXPORT jboolean JNICALL Java_org_emulator_calculator_NativeLib_isPortExtensionPossible(JNIEnv *env, jobject thisz) {
return (cCurrentRomType=='S' || cCurrentRomType=='G' || cCurrentRomType==0 ? JNI_TRUE : JNI_FALSE);
return (uint8_t)(cCurrentRomType=='S' || cCurrentRomType=='G' || cCurrentRomType==0 ? JNI_TRUE : JNI_FALSE);
}
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_getState(JNIEnv *env, jobject thisz) {
@ -1131,3 +1131,17 @@ JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_getScreenWidth(JNI
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_getScreenHeight(JNIEnv *env, jobject thisz) {
return SCREENHEIGHT*nLcdZoom*nGdiYZoom;
}
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_getScreenWidthNative(JNIEnv *env, jobject thisz) {
return 131;
}
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_getScreenHeightNative(JNIEnv *env, jobject thisz) {
return SCREENHEIGHT;
}
JNIEXPORT jint JNICALL Java_org_emulator_calculator_NativeLib_getLCDBackgroundColor(JNIEnv *env, jobject thisz) {
if (hLcdDC && hLcdDC->realizedPalette && hLcdDC->realizedPalette->paletteLog &&
hLcdDC->realizedPalette->paletteLog->palPalEntry) {
PALETTEENTRY *palPalEntry = hLcdDC->realizedPalette->paletteLog->palPalEntry;
return palPalEntry[0].peRed << 16 | palPalEntry[0].peGreen << 8 | palPalEntry[0].peBlue;
}
return -1;
}

View file

@ -306,6 +306,7 @@ DWORD GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) {
} else if(hFile->handleType == HANDLE_TYPE_FILE_ASSET) {
return (DWORD) AAsset_getLength64(hFile->fileAsset);
}
return 0;
}
//** https://www.ibm.com/developerworks/systems/library/es-MigratingWin32toLinux.html
@ -554,7 +555,7 @@ extern int jniDetachCurrentThread();
#define MAX_CREATED_THREAD 30
static HANDLE threads[MAX_CREATED_THREAD];
static DWORD ThreadStart(LPVOID lpThreadParameter) {
static void ThreadStart(LPVOID lpThreadParameter) {
HANDLE handle = (HANDLE)lpThreadParameter;
if(handle) {
handle->threadStartAddress(handle->threadParameter);

View file

@ -38,7 +38,6 @@ public class LCDOverlappingView extends View {
private Paint paint = new Paint();
private Rect srcBitmapCopy = new Rect();
private Rect dstBitmapCopy = new Rect();
private Bitmap bitmapLCD;
private float bitmapRatio = -1;
private float minViewSize = 200.0f;
public static int OVERLAPPING_LCD_MODE_NONE = 0;
@ -62,8 +61,6 @@ public class LCDOverlappingView extends View {
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);
@ -219,7 +216,7 @@ public class LCDOverlappingView extends View {
protected void onDraw(Canvas canvas) {
//if(debug) Log.d(TAG, "onDraw()");
if(this.overlappingLCDMode != OVERLAPPING_LCD_MODE_NONE && bitmapLCD != null) {
if(this.overlappingLCDMode != OVERLAPPING_LCD_MODE_NONE) {
int x = NativeLib.getScreenPositionX();
int y = NativeLib.getScreenPositionY();
srcBitmapCopy.set(x, y, x + NativeLib.getScreenWidth(), y + NativeLib.getScreenHeight());
@ -228,37 +225,6 @@ public class LCDOverlappingView extends View {
}
}
public void updateCallback(int type, int param1, int param2, String param3, String param4) {
if(this.overlappingLCDMode == OVERLAPPING_LCD_MODE_NONE)
return;
switch (type) {
case NativeLib.CALLBACK_TYPE_INVALIDATE:
//if(debug) Log.d(TAG, "updateCallback() CALLBACK_TYPE_INVALIDATE");
if(bitmapLCD.getWidth() > 1)
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(viewSized)
updateLayout();
}
break;
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
@ -353,7 +319,7 @@ public class LCDOverlappingView extends View {
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.putFloat("settings_lcd_overlapping_scale", (float)viewFlowLayout.width / (float)Math.max(1, NativeLib.getScreenWidth()));
editor.apply();
}

View file

@ -22,6 +22,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseIntArray;
@ -38,8 +39,10 @@ public class MainScreenView extends PanAndScaleView {
protected static final String TAG = "MainScreenView";
protected final boolean debug = false;
private Paint paint = new Paint();
private Paint paintFullCalc = new Paint();
private Paint paintLCD = new Paint();
private Bitmap bitmapMainScreen;
private Rect srcBitmapCopy = new Rect();
private SparseIntArray vkmap;
private HashMap<Character, Integer> charmap;
private int kmlBackgroundColor = Color.BLACK;
@ -49,7 +52,8 @@ public class MainScreenView extends PanAndScaleView {
private boolean viewSized = false;
private int rotationMode = 0;
private boolean autoRotation = false;
private boolean autoZoom = false;
private boolean autoZoom = false;
private boolean usePixelBorders = false;
public float defaultViewScaleFactorX = 1.0f;
public float defaultViewScaleFactorY = 1.0f;
@ -63,8 +67,12 @@ public class MainScreenView extends PanAndScaleView {
setShowScaleThumbnail(true);
setAllowDoubleTapZoom(false);
paint.setFilterBitmap(true);
paint.setAntiAlias(true);
paintFullCalc.setFilterBitmap(true);
paintFullCalc.setAntiAlias(true);
paintLCD.setStyle(Paint.Style.STROKE);
paintLCD.setStrokeWidth(1.0f);
paintLCD.setAntiAlias(false);
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
@ -248,6 +256,7 @@ public class MainScreenView extends PanAndScaleView {
updateLayout();
}
@SuppressLint("SourceLockedOrientationActivity")
protected void updateLayout() {
if(bitmapMainScreen != null && virtualSizeHeight > 1) {
if (virtualSizeWidth > 0.0f && viewSizeWidth > 0.0f) {
@ -335,13 +344,55 @@ public class MainScreenView extends PanAndScaleView {
this.onUpdateLayoutListener = onUpdateLayoutListener;
}
@Override
protected void onCustomDraw(Canvas canvas) {
//Log.d(TAG, "onCustomDraw()");
canvas.drawColor(getBackgroundColor());
// Copy the full calculator with antialiasing
canvas.drawBitmap(bitmapMainScreen, 0, 0, paintFullCalc);
if(usePixelBorders) {
// Copy the LCD part only without antialiasing
int x = NativeLib.getScreenPositionX();
int y = NativeLib.getScreenPositionY();
srcBitmapCopy.set(x, y, x + NativeLib.getScreenWidth(), y + NativeLib.getScreenHeight());
canvas.drawBitmap(bitmapMainScreen, srcBitmapCopy, srcBitmapCopy, paintLCD);
}
}
@Override
protected void onCustomDraw(Canvas canvas) {
//Log.d(TAG, "onCustomDraw()");
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(getBackgroundColor());
canvas.drawBitmap(bitmapMainScreen, 0, 0, paint);
if(usePixelBorders) {
int lcdPositionX = NativeLib.getScreenPositionX();
int lcdPositionY = NativeLib.getScreenPositionY();
int lcdWidth = NativeLib.getScreenWidth();
int lcdHeight = NativeLib.getScreenHeight();
int lcdWidthNative = NativeLib.getScreenWidthNative();
int lcdHeightNative = NativeLib.getScreenHeightNative();
float screenPositionX = lcdPositionX * viewScaleFactorX + viewPanOffsetX;
float screenPositionY = lcdPositionY * viewScaleFactorY + viewPanOffsetY;
float screenWidth = lcdWidth * viewScaleFactorX;
float screenHeight = lcdHeight * viewScaleFactorY;
// Draw the LCD grid lines without antialiasing to emulate the genuine pixels borders
int lcdBackgroundColor = 0xFF000000 | NativeLib.getLCDBackgroundColor();
paintLCD.setColor(lcdBackgroundColor);
float stepX = screenWidth / lcdWidthNative;
for(int x = 0; x < lcdWidthNative; x++) {
float screenX = screenPositionX + x * stepX;
canvas.drawLine(screenX, screenPositionY, screenX, screenPositionY + screenHeight, paintLCD);
}
float stepY = screenHeight / lcdHeightNative;
for(int y = 0; y < lcdHeightNative; y++) {
float screenY = screenPositionY + y * stepY;
canvas.drawLine(screenPositionX, screenY, screenPositionX + screenWidth, screenY, paintLCD);
}
}
}
public void updateCallback(int type, int param1, int param2, String param3, String param4) {
@ -406,6 +457,11 @@ public class MainScreenView extends PanAndScaleView {
this.statusBarColor = statusBarColor;
}
public void setUsePixelBorders(boolean usePixelBorders) {
this.usePixelBorders = usePixelBorders;
postInvalidate();
}
private int getBackgroundColor() {

View file

@ -58,7 +58,7 @@ public class NativeLib {
public static native String[] getObjectsToSave();
public static native int onObjectSave(String filename, boolean[] objectsToSaveItemChecked);
public static native void onViewCopy(Bitmap bitmapScreen);
public static native void onViewCopy(Bitmap bitmapScreen);
public static native void onStackCopy();
public static native void onStackPaste();
public static native void onViewReset();
@ -78,4 +78,7 @@ public class NativeLib {
public static native int getScreenPositionY();
public static native int getScreenWidth();
public static native int getScreenHeight();
public static native int getScreenWidthNative();
public static native int getScreenHeightNative();
public static native int getLCDBackgroundColor();
}

View file

@ -63,7 +63,7 @@ public class PrinterSimulatorFragment extends AppCompatDialogFragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(AppCompatDialogFragment.STYLE_NO_FRAME, android.R.style.Theme_Material);
setStyle(AppCompatDialogFragment.STYLE_NO_FRAME, Utils.resId(this, "style", "AppTheme"));
}
@NonNull
@ -241,6 +241,8 @@ public class PrinterSimulatorFragment extends AppCompatDialogFragment {
private void commonInitialization() {
setShowScaleThumbnail(true);
scaleThumbnailColor = Color.GRAY;
paintBitmap.setAntiAlias(false);
}
public void setBitmap(Bitmap bitmap) {

View file

@ -69,7 +69,6 @@ import org.emulator.calculator.Utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@ -702,9 +701,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
filename = emuXX + "-state.e38";
break;
case 'E': // HP39G/(HP39G+/HP39GS)/HP40G/HP40GS
filename = emuXX + "-state.e39";
break;
case 'P': // HP39G+/HP39GS
case 'P': // HP39G+/HP39GS
filename = emuXX + "-state.e39";
break;
case '2': // HP48GII
@ -1122,8 +1119,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
fileOutputStream.flush();
fileOutputStream.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
@ -1259,7 +1254,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
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;
}
@ -1531,7 +1525,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_lcd_overlapping_mode",
"settings_realspeed", "settings_grayscale", "settings_rotation", "settings_auto_layout", "settings_allow_pinch_zoom", "settings_lcd_overlapping_mode", "settings_lcd_pixel_borders",
"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",
@ -1578,6 +1572,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
}
lcdOverlappingView.setOverlappingLCDMode(overlappingLCDMode);
break;
case "settings_lcd_pixel_borders":
mainScreenView.setUsePixelBorders(sharedPreferences.getBoolean("settings_lcd_pixel_borders", false));
break;
case "settings_hide_bar":
case "settings_hide_bar_status":
case "settings_hide_bar_nav":

View file

@ -1,23 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
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_coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
android:background="?attr/colorPrimary" />
</com.google.android.material.appbar.AppBarLayout>

View file

@ -10,9 +10,7 @@
android:id="@+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:navigationIcon="?android:attr/homeAsUpIndicator" />
<org.emulator.calculator.ViewPagerNoSwipe

View file

@ -8,7 +8,7 @@
https://github.com/google/material-design-icons/tree/master/action/drawable-anydpi-v21
-->
<group android:checkableBehavior="single">
<group android:checkableBehavior="none">
<item
android:id="@+id/nav_new"
android:icon="@drawable/ic_insert_drive_file_black_24dp"

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#AAAAAA</color>
<color name="colorPrimaryDark">#32312B</color>
</resources>

View file

@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--<color name="colorPrimary">#008577</color>-->
<!--<color name="colorPrimaryDark">#00574B</color>-->
<!--<color name="colorAccent">#D81B60</color>-->
<color name="colorPrimary">#444341</color>
<color name="colorPrimaryDark">#32312B</color>
<color name="colorSecondary">#5A5A5A</color>
<color name="colorAccent">#8DB4D3</color>
</resources>

View file

@ -128,6 +128,9 @@
<string name="settings_lcd_overlapping_mode_item_1">Auto (Double touch)</string>
<string name="settings_lcd_overlapping_mode_item_2">Manual (Zoom or pan)</string>
<string name="settings_lcd_pixel_borders_title">Show the LCD pixel borders</string>
<string name="settings_lcd_pixel_borders_summary">Experimental feature which show a more realistic pixel. Note: Due to the difference in screen resolution between Android and the calculator, the pixels are not necessarily uniform in size.</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_button_menu">Hide the button menu</string>

View file

@ -1,26 +1,33 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<!--
Base application theme, dependent on API level. This theme is replaced
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
-->
<!-- https://material.io/develop/android/theming/dark/-->
<style name="AppBaseTheme" parent="@style/Theme.MaterialComponents.DayNight">
<!--
Theme customizations available in newer API levels can go in
res/values-vXX/styles.xml, while customizations related to
backward-compatibility can go here.
-->
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorSecondary">@color/colorSecondary</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="actionOverflowButtonStyle">@style/MyOverflowButtonStyle</item>
</style>
</style>
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="MyOverflowButtonStyle" parent="Widget.AppCompat.ActionButton.Overflow">
<item name="android:tint">#FFFFFF</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>

View file

@ -57,7 +57,11 @@
android:entryValues="@array/settings_lcd_overlapping_mode_value"
android:defaultValue="0"
/>
<SwitchPreference
android:key="settings_lcd_pixel_borders"
android:title="@string/settings_lcd_pixel_borders_title"
android:summary="@string/settings_lcd_pixel_borders_summary"
android:defaultValue="false" />
<SwitchPreference
android:key="settings_hide_bar_status"

View file

@ -7,7 +7,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.android.tools.build:gradle:3.6.2'
// NOTE: Do not place your application dependencies here; they belong

View file

@ -1,6 +1,6 @@
#Tue Oct 22 17:19:08 CEST 2019
#Wed Feb 26 12:01:15 CET 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip