Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fb16805739 | |||
| a8c108aa85 | |||
| 1451fe274c | |||
| 4246b6ff8c | |||
| 26b4ce849a | |||
| 89f960173c | |||
| da8974dbf1 | |||
| c4da71792b | |||
| 53e20fdaae | |||
| 7f56cba79d | |||
| 596f0f6dda |
@@ -12,6 +12,12 @@ It is based on PrusaSlicer's core and well optimized for Android touchscreen int
|
||||
# Quick Start
|
||||
Just download APK from [Releases tab](https://github.com/utkabobr/SliceBeam/releases/latest) and follow setup instructions. Google Play builds will be available later.
|
||||
|
||||
# Where to get printer profiles?
|
||||
|
||||
It is recommended to use PrusaSlicer's profiles, Slice Beam profiles are using Prusa's format. You can import PrusaSlicer's profiles and vice versa.
|
||||
|
||||
But, there is an experimental OrcaSlicer profile support, please open Issue tickets with your .orca_printer files, so I can check what wents wrong on your specific case.
|
||||
|
||||
# Some screenshots
|
||||
   
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ android {
|
||||
applicationId "ru.ytkab0bp.slicebeam"
|
||||
minSdk 21
|
||||
targetSdk 34
|
||||
versionCode 2
|
||||
versionName "0.1.0"
|
||||
versionCode 5
|
||||
versionName "0.1.2"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
@@ -34,8 +34,12 @@ android {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
buildConfigField "boolean", "IS_GOOGLE_PLAY", "true"
|
||||
buildConfigField "boolean", "IS_GOOGLE_PLAY", "false"
|
||||
buildConfigField "String", "COMMIT", "\"" + commit + "\""
|
||||
ndk {
|
||||
//noinspection ChromeOsAbiSupport
|
||||
abiFilters "armeabi-v7a", "arm64-v8a"
|
||||
}
|
||||
}
|
||||
debug {
|
||||
buildConfigField "boolean", "IS_GOOGLE_PLAY", "false"
|
||||
|
||||
@@ -66,7 +66,7 @@ public class SliceBeam extends Application {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
WebView.setWebContentsDebuggingEnabled(true);
|
||||
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG);
|
||||
|
||||
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
|
||||
StringWriter sw = new StringWriter();
|
||||
|
||||
@@ -45,6 +45,7 @@ import ru.ytkab0bp.slicebeam.view.BeamButton;
|
||||
import ru.ytkab0bp.slicebeam.view.BoostySubsView;
|
||||
|
||||
public class ChangeLogBottomSheet extends BottomSheetDialog {
|
||||
private BoostySubsView subsView;
|
||||
private ScrollView scrollView;
|
||||
private ViewPager pager;
|
||||
|
||||
@@ -154,7 +155,7 @@ public class ChangeLogBottomSheet extends BottomSheetDialog {
|
||||
subtitle.setPadding(ViewUtils.dp(12), 0, ViewUtils.dp(12), 0);
|
||||
ll.addView(subtitle);
|
||||
|
||||
BoostySubsView subsView = new BoostySubsView(context);
|
||||
subsView = new BoostySubsView(context);
|
||||
if (SliceBeam.SERVER_DATA != null) {
|
||||
List<String> list = new ArrayList<>(SliceBeam.SERVER_DATA.boostySubscribers);
|
||||
Collections.shuffle(list);
|
||||
@@ -238,6 +239,11 @@ public class ChangeLogBottomSheet extends BottomSheetDialog {
|
||||
|
||||
@EventHandler(runOnMainThread = true)
|
||||
public void onDataUpdated(BeamServerDataUpdatedEvent e) {
|
||||
if (SliceBeam.SERVER_DATA != null) {
|
||||
List<String> list = new ArrayList<>(SliceBeam.SERVER_DATA.boostySubscribers);
|
||||
Collections.shuffle(list);
|
||||
subsView.setStrings(list);
|
||||
}
|
||||
pager.getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ public abstract class UnfoldMenu {
|
||||
protected BedFragment fragment;
|
||||
|
||||
private boolean isVisible;
|
||||
private boolean isDismissing;
|
||||
private SpringAnimation spring;
|
||||
private DynamicAnimation.OnAnimationUpdateListener updateListener;
|
||||
private FrameLayout containerLayout;
|
||||
@@ -73,7 +74,9 @@ public abstract class UnfoldMenu {
|
||||
|
||||
private void show(View from, BedFragment fragment, FrameLayout into) {
|
||||
if (isVisible) return;
|
||||
this.fragment = fragment;
|
||||
if (fragment != null) {
|
||||
this.fragment = fragment;
|
||||
}
|
||||
this.isVisible = true;
|
||||
this.containerLayout = into;
|
||||
|
||||
@@ -95,7 +98,7 @@ public abstract class UnfoldMenu {
|
||||
fromTranslationX = pos[0] - intoPos[0];
|
||||
fromTranslationY = pos[1] - intoPos[1];
|
||||
toTranslationX = 0;
|
||||
toTranslationY = portrait ? into.getHeight() - side : 0;
|
||||
toTranslationY = portrait ? into.getHeight() - side - into.getPaddingTop() - into.getPaddingBottom() : 0;
|
||||
rootView = new FrameLayout(ctx) {
|
||||
{
|
||||
setWillNotDraw(false);
|
||||
@@ -121,13 +124,21 @@ public abstract class UnfoldMenu {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
|
||||
if (isVisible) {
|
||||
onCreate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
|
||||
if (isVisible) {
|
||||
onDestroy();
|
||||
isVisible = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -138,7 +149,6 @@ public abstract class UnfoldMenu {
|
||||
rootView.setTranslationX(fromTranslationX);
|
||||
rootView.setTranslationY(fromTranslationY);
|
||||
|
||||
onCreate();
|
||||
dimmView = new View(ctx);
|
||||
dimmView.setBackgroundColor(0x40000000);
|
||||
dimmView.setTranslationX(toTranslationX);
|
||||
@@ -207,6 +217,10 @@ public abstract class UnfoldMenu {
|
||||
updateListener.onAnimationUpdate(spring, 1f, 0f);
|
||||
}
|
||||
|
||||
public boolean isAttached() {
|
||||
return rootView.getParent() != null && !isDismissing;
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
dismiss(false);
|
||||
}
|
||||
@@ -215,7 +229,9 @@ public abstract class UnfoldMenu {
|
||||
if (!isVisible) return;
|
||||
this.isVisible = false;
|
||||
|
||||
isDismissing = true;
|
||||
onDestroy();
|
||||
isDismissing = false;
|
||||
|
||||
if (alphaOnly) {
|
||||
ValueAnimator anim = ValueAnimator.ofFloat(0, 1).setDuration(150);
|
||||
|
||||
@@ -124,7 +124,7 @@ public class WebViewMenu extends UnfoldMenu {
|
||||
|
||||
@Override
|
||||
public int getRequestedSize(FrameLayout into, boolean portrait) {
|
||||
return portrait ? into.getHeight() : into.getWidth();
|
||||
return portrait ? into.getHeight() - into.getPaddingTop() - into.getPaddingBottom() : into.getWidth();
|
||||
}
|
||||
|
||||
private final class Bridge {
|
||||
|
||||
@@ -18,6 +18,8 @@ import androidx.core.graphics.ColorUtils;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
@@ -36,13 +38,16 @@ import ru.ytkab0bp.slicebeam.components.UnfoldMenu;
|
||||
import ru.ytkab0bp.slicebeam.components.WebViewMenu;
|
||||
import ru.ytkab0bp.slicebeam.config.ConfigObject;
|
||||
import ru.ytkab0bp.slicebeam.events.NeedDismissCalibrationsMenu;
|
||||
import ru.ytkab0bp.slicebeam.events.NeedSnackbarEvent;
|
||||
import ru.ytkab0bp.slicebeam.events.ObjectsListChangedEvent;
|
||||
import ru.ytkab0bp.slicebeam.events.SelectedObjectChangedEvent;
|
||||
import ru.ytkab0bp.slicebeam.fragment.BedFragment;
|
||||
import ru.ytkab0bp.slicebeam.recycler.PreferenceItem;
|
||||
import ru.ytkab0bp.slicebeam.recycler.SimpleRecyclerAdapter;
|
||||
import ru.ytkab0bp.slicebeam.recycler.SimpleRecyclerItem;
|
||||
import ru.ytkab0bp.slicebeam.recycler.SpaceItem;
|
||||
import ru.ytkab0bp.slicebeam.slic3r.Bed3D;
|
||||
import ru.ytkab0bp.slicebeam.slic3r.Slic3rRuntimeError;
|
||||
import ru.ytkab0bp.slicebeam.theme.BeamTheme;
|
||||
import ru.ytkab0bp.slicebeam.theme.ThemesRepo;
|
||||
import ru.ytkab0bp.slicebeam.utils.ViewUtils;
|
||||
@@ -214,7 +219,7 @@ public class FileMenu extends ListBedMenu {
|
||||
public final class CalibrationsMenu extends UnfoldMenu {
|
||||
|
||||
public int getRequestedSize(FrameLayout into, boolean portrait) {
|
||||
return (int) (portrait ? into.getHeight() * 0.3f : into.getWidth() * 0.6f);
|
||||
return (int) (portrait ? into.getHeight() * 0.35f : into.getWidth() * 0.6f);
|
||||
}
|
||||
|
||||
private String loadJSLoader(String key) {
|
||||
@@ -309,6 +314,11 @@ public class FileMenu extends ListBedMenu {
|
||||
if (ctx instanceof MainActivity) {
|
||||
((MainActivity) ctx).showUnfoldMenu(new WebViewMenu(Uri.parse("https://k3d.tech/calibrations/retractions/calibrator/").buildUpon().appendQueryParameter("lang", getK3DLanguage()).build(), loadJSLoader("k3d_rct")).setFragment(fragment), v);
|
||||
}
|
||||
}),
|
||||
new PreferenceItem().setIcon(R.drawable.deployed_code_24).setTitle(ctx.getString(R.string.MenuFileCalibrationsModels)).setSubtitle(ctx.getString(R.string.MenuFileCalibrationsModelsDescription)).setOnClickListener(v -> {
|
||||
if (ctx instanceof MainActivity) {
|
||||
((MainActivity) ctx).showUnfoldMenu(new CalibrationModelsMenu().setFragment(fragment), v);
|
||||
}
|
||||
})
|
||||
));
|
||||
rv.setAdapter(adapter);
|
||||
@@ -359,4 +369,111 @@ public class FileMenu extends ListBedMenu {
|
||||
SliceBeam.EVENT_BUS.unregisterListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
public final static class CalibrationModelsMenu extends UnfoldMenu {
|
||||
private void loadModel(String key) {
|
||||
BedFragment fragment = this.fragment;
|
||||
ViewUtils.postOnMainThread(() -> {
|
||||
File f = new File(SliceBeam.getModelCacheDir(), "calibration_" + key + ".stl");
|
||||
new Thread(()->{
|
||||
try {
|
||||
InputStream in = SliceBeam.INSTANCE.getAssets().open("models/" + key + ".stl");
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
byte[] buffer = new byte[10240]; int c;
|
||||
while ((c = in.read(buffer)) != -1) {
|
||||
fos.write(buffer, 0, c);
|
||||
}
|
||||
fos.close();
|
||||
in.close();
|
||||
|
||||
ViewUtils.postOnMainThread(() -> {
|
||||
try {
|
||||
if (f.getName().endsWith(".gcode")) {
|
||||
fragment.loadGCode(f);
|
||||
} else {
|
||||
fragment.loadModel(f);
|
||||
SliceBeam.EVENT_BUS.fireEvent(new ObjectsListChangedEvent());
|
||||
}
|
||||
SliceBeam.EVENT_BUS.fireEvent(new NeedSnackbarEvent(R.string.MenuFileOpenFileLoaded));
|
||||
} catch (Slic3rRuntimeError e) {
|
||||
f.delete();
|
||||
|
||||
ViewUtils.postOnMainThread(() -> new BeamAlertDialogBuilder(fragment.getContext())
|
||||
.setTitle(R.string.MenuFileOpenFileFailed)
|
||||
.setMessage(e.toString())
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show());
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
f.delete();
|
||||
ViewUtils.postOnMainThread(() -> new BeamAlertDialogBuilder(fragment.getContext())
|
||||
.setTitle(R.string.MenuFileOpenFileFailed)
|
||||
.setMessage(e.toString())
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show());
|
||||
}
|
||||
}).start();
|
||||
}, 200);
|
||||
SliceBeam.EVENT_BUS.fireEvent(new NeedDismissCalibrationsMenu());
|
||||
dismiss(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View onCreateView(Context ctx, boolean portrait) {
|
||||
LinearLayout ll = new LinearLayout(ctx);
|
||||
ll.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
LinearLayout toolbar = new LinearLayout(ctx);
|
||||
toolbar.setPadding(ViewUtils.dp(12), 0, ViewUtils.dp(12), 0);
|
||||
toolbar.setOrientation(LinearLayout.HORIZONTAL);
|
||||
toolbar.setGravity(Gravity.CENTER_VERTICAL);
|
||||
toolbar.setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), 0));
|
||||
toolbar.setOnClickListener(v -> dismiss());
|
||||
|
||||
ImageView icon = new ImageView(ctx);
|
||||
icon.setImageResource(R.drawable.arrow_left_outline_28);
|
||||
icon.setColorFilter(ThemesRepo.getColor(android.R.attr.textColorSecondary));
|
||||
toolbar.addView(icon, new LinearLayout.LayoutParams(ViewUtils.dp(28), ViewUtils.dp(28)));
|
||||
|
||||
TextView title = new TextView(ctx);
|
||||
title.setText(R.string.MenuOrientationPositionBack);
|
||||
title.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM));
|
||||
title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
|
||||
title.setTextColor(ThemesRepo.getColor(android.R.attr.textColorPrimary));
|
||||
toolbar.addView(title, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f) {{
|
||||
leftMargin = ViewUtils.dp(12);
|
||||
}});
|
||||
ll.addView(toolbar, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(52)));
|
||||
|
||||
ll.addView(new DividerView(ctx), new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(1f)));
|
||||
|
||||
RecyclerView rv = new FadeRecyclerView(ctx);
|
||||
SimpleRecyclerAdapter adapter = new SimpleRecyclerAdapter();
|
||||
adapter.setItems(Arrays.asList(
|
||||
new PreferenceItem().setIcon(R.drawable.model_3dbenchy).setNoTint(true).setRoundRadius(ViewUtils.dp(8)).setTitle(ctx.getString(R.string.MenuFileCalibrationsModels3DBenchy)).setOnClickListener(v -> loadModel("3dbenchy")),
|
||||
new PreferenceItem().setIcon(R.drawable.model_xyz_cube).setNoTint(true).setRoundRadius(ViewUtils.dp(8)).setTitle(ctx.getString(R.string.MenuFileCalibrationsModelsXYZCube)).setOnClickListener(v -> loadModel("xyz_cube")),
|
||||
new PreferenceItem().setIcon(R.drawable.model_bunny).setNoTint(true).setRoundRadius(ViewUtils.dp(8)).setTitle(ctx.getString(R.string.MenuFileCalibrationsModelsBunny)).setOnClickListener(v -> loadModel("bunny")),
|
||||
new PreferenceItem().setIcon(R.drawable.model_fox).setNoTint(true).setRoundRadius(ViewUtils.dp(8)).setTitle(ctx.getString(R.string.MenuFileCalibrationsModelsFox)).setOnClickListener(v -> loadModel("fox")),
|
||||
new PreferenceItem().setIcon(R.drawable.model_box).setNoTint(true).setRoundRadius(ViewUtils.dp(8)).setTitle(ctx.getString(R.string.MenuFileCalibrationsModelsBox)).setOnClickListener(v -> loadModel("box")),
|
||||
new PreferenceItem().setIcon(R.drawable.model_cone).setNoTint(true).setRoundRadius(ViewUtils.dp(8)).setTitle(ctx.getString(R.string.MenuFileCalibrationsModelsCone)).setOnClickListener(v -> loadModel("cone")),
|
||||
new PreferenceItem().setIcon(R.drawable.model_cylinder).setNoTint(true).setRoundRadius(ViewUtils.dp(8)).setTitle(ctx.getString(R.string.MenuFileCalibrationsModelsCylinder)).setOnClickListener(v -> loadModel("cylinder")),
|
||||
new PreferenceItem().setIcon(R.drawable.model_pyramid).setNoTint(true).setRoundRadius(ViewUtils.dp(8)).setTitle(ctx.getString(R.string.MenuFileCalibrationsModelsPyramid)).setOnClickListener(v -> loadModel("pyramid")),
|
||||
new PreferenceItem().setIcon(R.drawable.model_sphere).setNoTint(true).setRoundRadius(ViewUtils.dp(8)).setTitle(ctx.getString(R.string.MenuFileCalibrationsModelsSphere)).setOnClickListener(v -> loadModel("sphere"))
|
||||
));
|
||||
rv.setAdapter(adapter);
|
||||
ll.addView(rv, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f));
|
||||
return ll;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRequestedSize(FrameLayout into, boolean portrait) {
|
||||
return portrait ? into.getHeight() - into.getPaddingTop() - into.getPaddingBottom() : into.getWidth();
|
||||
}
|
||||
|
||||
public CalibrationModelsMenu setFragment(BedFragment fragment) {
|
||||
this.fragment = fragment;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,17 @@ package ru.ytkab0bp.slicebeam.components.bed_menu;
|
||||
|
||||
import static ru.ytkab0bp.slicebeam.utils.DebugUtils.assertTrue;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
@@ -22,6 +25,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import com.google.android.material.checkbox.MaterialCheckBox;
|
||||
import com.loopj.android.http.AsyncHttpClient;
|
||||
import com.loopj.android.http.AsyncHttpResponseHandler;
|
||||
import com.loopj.android.http.RequestParams;
|
||||
@@ -32,6 +36,7 @@ import org.json.JSONObject;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -50,11 +55,15 @@ import ru.ytkab0bp.slicebeam.config.ConfigObject;
|
||||
import ru.ytkab0bp.slicebeam.events.NeedSnackbarEvent;
|
||||
import ru.ytkab0bp.slicebeam.fragment.BedFragment;
|
||||
import ru.ytkab0bp.slicebeam.recycler.SimpleRecyclerItem;
|
||||
import ru.ytkab0bp.slicebeam.slic3r.GCodeProcessorResult;
|
||||
import ru.ytkab0bp.slicebeam.slic3r.GCodeViewer;
|
||||
import ru.ytkab0bp.slicebeam.slic3r.Slic3rLocalization;
|
||||
import ru.ytkab0bp.slicebeam.theme.IThemeView;
|
||||
import ru.ytkab0bp.slicebeam.theme.ThemesRepo;
|
||||
import ru.ytkab0bp.slicebeam.utils.ViewUtils;
|
||||
import ru.ytkab0bp.slicebeam.view.DividerView;
|
||||
import ru.ytkab0bp.slicebeam.view.PositionScrollView;
|
||||
import ru.ytkab0bp.slicebeam.view.SegmentsView;
|
||||
|
||||
public class SliceMenu extends ListBedMenu {
|
||||
private AsyncHttpClient client = new AsyncHttpClient();
|
||||
@@ -71,7 +80,8 @@ public class SliceMenu extends ListBedMenu {
|
||||
protected List<SimpleRecyclerItem> onCreateItems(boolean portrait) {
|
||||
lastUid = SliceBeam.CONFIG_UID;
|
||||
List<SimpleRecyclerItem> items = new ArrayList<>(Arrays.asList(
|
||||
new BedMenuItem(R.string.MenuSliceInfo, R.drawable.square_stack_up_outline_28).onClick(v -> fragment.showUnfoldMenu(new PrintInfoMenu(), v)),
|
||||
new BedMenuItem(R.string.MenuSliceInfo, R.drawable.clock_circle_dashed_outline_24).onClick(v -> fragment.showUnfoldMenu(new InfoMenu(), v)),
|
||||
new BedMenuItem(R.string.MenuSliceLayers, R.drawable.square_stack_up_outline_28).onClick(v -> fragment.showUnfoldMenu(new LayersMenu(), v)),
|
||||
new BedMenuItem(R.string.MenuSliceExportToFile, R.drawable.folder_simple_arrow_right_outline_28).onClick(v -> {
|
||||
if (fragment.getContext() instanceof Activity) {
|
||||
Activity act = (Activity) fragment.getContext();
|
||||
@@ -176,15 +186,328 @@ public class SliceMenu extends ListBedMenu {
|
||||
});
|
||||
}
|
||||
|
||||
private final static class PrintInfoMenu extends UnfoldMenu {
|
||||
private final static class InfoMenu extends UnfoldMenu implements IThemeView {
|
||||
private TextView totalView;
|
||||
private SegmentsView segmentsView;
|
||||
private ExtrusionRoleView[] roleViews = new ExtrusionRoleView[GCodeViewer.EXTRUSION_ROLES_COUNT];
|
||||
private static DecimalFormat format = new DecimalFormat("0.##");
|
||||
|
||||
private GCodeViewer getViewer() {
|
||||
return fragment.getGlView().getRenderer().getViewer();
|
||||
}
|
||||
|
||||
private GCodeProcessorResult getResult() {
|
||||
return fragment.getGlView().getRenderer().getGcodeResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View onCreateView(Context ctx, boolean portrait) {
|
||||
LinearLayout ll = new LinearLayout(ctx);
|
||||
ll.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
ll.addView(new Space(ctx), new LinearLayout.LayoutParams(0, 0, 1f));
|
||||
|
||||
for (int i = 0; i < GCodeViewer.EXTRUSION_ROLES_COUNT; i++) {
|
||||
ll.addView(roleViews[i] = new ExtrusionRoleView(ctx));
|
||||
}
|
||||
|
||||
ll.addView(new DividerView(ctx), new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(1f)));
|
||||
|
||||
totalView = new TextView(ctx);
|
||||
totalView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13);
|
||||
totalView.setGravity(Gravity.CENTER);
|
||||
ll.addView(totalView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(18)) {{
|
||||
topMargin = ViewUtils.dp(8);
|
||||
}});
|
||||
|
||||
segmentsView = new SegmentsView(ctx);
|
||||
ll.addView(segmentsView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(12)) {{
|
||||
leftMargin = rightMargin = ViewUtils.dp(12);
|
||||
topMargin = bottomMargin = ViewUtils.dp(8);
|
||||
}});
|
||||
|
||||
ll.addView(new DividerView(ctx), new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(1f)));
|
||||
LinearLayout toolbar = new LinearLayout(ctx);
|
||||
toolbar.setPadding(ViewUtils.dp(12), 0, ViewUtils.dp(12), 0);
|
||||
toolbar.setOrientation(LinearLayout.HORIZONTAL);
|
||||
toolbar.setGravity(Gravity.CENTER_VERTICAL);
|
||||
toolbar.setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), 0));
|
||||
toolbar.setOnClickListener(v -> dismiss());
|
||||
|
||||
ImageView icon = new ImageView(ctx);
|
||||
icon.setImageResource(R.drawable.arrow_left_outline_28);
|
||||
icon.setColorFilter(ThemesRepo.getColor(android.R.attr.textColorSecondary));
|
||||
toolbar.addView(icon, new LinearLayout.LayoutParams(ViewUtils.dp(28), ViewUtils.dp(28)));
|
||||
|
||||
TextView title = new TextView(ctx);
|
||||
title.setText(R.string.MenuOrientationPositionBack);
|
||||
title.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM));
|
||||
title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
|
||||
title.setTextColor(ThemesRepo.getColor(android.R.attr.textColorPrimary));
|
||||
toolbar.addView(title, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f) {{
|
||||
leftMargin = ViewUtils.dp(12);
|
||||
}});
|
||||
|
||||
ll.addView(toolbar, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(52)));
|
||||
onApplyTheme();
|
||||
return ll;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
GCodeViewer viewer = getViewer();
|
||||
GCodeProcessorResult result = getResult();
|
||||
if (viewer != null) {
|
||||
for (int i = 0; i < GCodeViewer.EXTRUSION_ROLES_COUNT; i++) {
|
||||
boolean visible = viewer.getEstimatedTime(i) != 0;
|
||||
roleViews[i].setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||
if (visible) {
|
||||
roleViews[i].bind(viewer, result, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
updateValues();
|
||||
ViewUtils.postOnMainThread(() -> segmentsView.startAnimation(), 50);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
segmentsView.setNotVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRequestedSize(FrameLayout into, boolean portrait) {
|
||||
if (portrait) {
|
||||
GCodeViewer viewer = getViewer();
|
||||
if (viewer != null) {
|
||||
int visibleCount = 0;
|
||||
for (int i = 0; i < GCodeViewer.EXTRUSION_ROLES_COUNT; i++) {
|
||||
if (viewer.getEstimatedTime(i) != 0) {
|
||||
visibleCount++;
|
||||
}
|
||||
}
|
||||
return ViewUtils.dp(42) * visibleCount + ViewUtils.dp(28) + ViewUtils.dp(52) + ViewUtils.dp(18 + 8);
|
||||
}
|
||||
}
|
||||
return super.getRequestedSize(into, portrait);
|
||||
}
|
||||
|
||||
private float getTotalEstimatedTime() {
|
||||
GCodeViewer viewer = getViewer();
|
||||
if (viewer == null) return 0;
|
||||
float total = 0;
|
||||
for (int i = 0; i < GCodeViewer.EXTRUSION_ROLES_COUNT; i++) {
|
||||
if (viewer.isExtrusionRoleVisible(i)) {
|
||||
total += viewer.getEstimatedTime(i);
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private void updateValues() {
|
||||
GCodeViewer viewer = getViewer();
|
||||
GCodeProcessorResult result = getResult();
|
||||
if (viewer == null) return;
|
||||
|
||||
float[] values = new float[2 + GCodeViewer.EXTRUSION_ROLES_COUNT];
|
||||
double totalWeight = 0;
|
||||
double totalLength = 0;
|
||||
values[0] = 0;
|
||||
values[values.length - 1] = 1;
|
||||
float prev = 0;
|
||||
int lastVisible = 0;
|
||||
float totalTime = getTotalEstimatedTime();
|
||||
for (int i = 0; i < GCodeViewer.EXTRUSION_ROLES_COUNT; i++) {
|
||||
if (viewer.isExtrusionRoleVisible(i)) {
|
||||
float percent = viewer.getEstimatedTime(i) / totalTime;
|
||||
values[i + 1] = prev + percent;
|
||||
lastVisible = i;
|
||||
prev = values[i + 1];
|
||||
totalLength += result.getUsedFilamentMM(i);
|
||||
totalWeight += result.getUsedFilamentG(i);
|
||||
} else {
|
||||
values[i + 1] = prev;
|
||||
}
|
||||
}
|
||||
|
||||
values[lastVisible] = 1;
|
||||
|
||||
segmentsView.setValues(values);
|
||||
totalView.setText(formatComplex(totalWeight, totalLength, totalTime));
|
||||
}
|
||||
|
||||
private static String formatComplex(double weight, double length, float time) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (weight > 0) {
|
||||
sb.append(format.format(weight)).append(" ").append(SliceBeam.INSTANCE.getString(R.string.MenuSliceInfoWeight)).append(" | ");
|
||||
}
|
||||
sb.append(format.format(length)).append(" ").append(SliceBeam.INSTANCE.getString(R.string.MenuSliceInfoLength)).append(" | ");
|
||||
sb.append(formatTime(time));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String formatTime(float time) {
|
||||
int secondsTotal = (int) Math.round(Math.ceil(time));
|
||||
int seconds = secondsTotal % 60;
|
||||
int minutes = ((secondsTotal - seconds) / 60) % 60;
|
||||
int hours = ((secondsTotal - seconds) / 60) / 60;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (hours > 0) {
|
||||
sb.append(hours).append(" ").append(SliceBeam.INSTANCE.getString(R.string.MenuSliceInfoHour));
|
||||
}
|
||||
if (minutes > 0) {
|
||||
if (sb.length() > 0) sb.append(" ");
|
||||
|
||||
sb.append(minutes).append(" ").append(SliceBeam.INSTANCE.getString(R.string.MenuSliceInfoMinute));
|
||||
}
|
||||
if (seconds > 0 || sb.length() == 0) {
|
||||
if (sb.length() > 0) sb.append(" ");
|
||||
|
||||
sb.append(seconds).append(" ").append(SliceBeam.INSTANCE.getString(R.string.MenuSliceInfoSecond));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplyTheme() {
|
||||
totalView.setTextColor(ThemesRepo.getColor(android.R.attr.textColorSecondary));
|
||||
}
|
||||
|
||||
private final class ExtrusionRoleView extends LinearLayout implements IThemeView {
|
||||
private MaterialCheckBox checkBox;
|
||||
private TextView titleView;
|
||||
private TextView timeView;
|
||||
|
||||
private Runnable invalidateGl;
|
||||
|
||||
public ExtrusionRoleView(Context context) {
|
||||
super(context);
|
||||
setOrientation(HORIZONTAL);
|
||||
setGravity(Gravity.CENTER_VERTICAL);
|
||||
setPadding(ViewUtils.dp(12), 0, ViewUtils.dp(16), 0);
|
||||
|
||||
checkBox = new MaterialCheckBox(getContext()) {
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent event) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
addView(checkBox, new LinearLayout.LayoutParams(ViewUtils.dp(28), ViewUtils.dp(28)));
|
||||
|
||||
titleView = new TextView(context);
|
||||
titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
|
||||
addView(titleView, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f) {{
|
||||
leftMargin = ViewUtils.dp(12);
|
||||
rightMargin = ViewUtils.dp(8);
|
||||
}});
|
||||
|
||||
timeView = new TextView(context);
|
||||
timeView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12);
|
||||
addView(timeView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
|
||||
setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(42)));
|
||||
onApplyTheme();
|
||||
}
|
||||
|
||||
public void bind(GCodeViewer viewer, GCodeProcessorResult result, @GCodeViewer.ExtrusionRole int role) {
|
||||
switch (role) {
|
||||
case GCodeViewer.EXTRUSION_ROLE_NONE:
|
||||
titleView.setText(Slic3rLocalization.getString("Unknown"));
|
||||
break;
|
||||
case GCodeViewer.EXTRUSION_ROLE_PERIMETER:
|
||||
titleView.setText(Slic3rLocalization.getString("Perimeter"));
|
||||
break;
|
||||
case GCodeViewer.EXTRUSION_ROLE_EXTERNAL_PERIMETER:
|
||||
titleView.setText(Slic3rLocalization.getString("External perimeter"));
|
||||
break;
|
||||
case GCodeViewer.EXTRUSION_ROLE_OVERHANG_PERIMETER:
|
||||
titleView.setText(Slic3rLocalization.getString("Overhang perimeter"));
|
||||
break;
|
||||
case GCodeViewer.EXTRUSION_ROLE_INTERNAL_INFILL:
|
||||
titleView.setText(Slic3rLocalization.getString("Internal infill"));
|
||||
break;
|
||||
case GCodeViewer.EXTRUSION_ROLE_SOLID_INFILL:
|
||||
titleView.setText(Slic3rLocalization.getString("Solid infill"));
|
||||
break;
|
||||
case GCodeViewer.EXTRUSION_ROLE_TOP_SOLID_INFILL:
|
||||
titleView.setText(Slic3rLocalization.getString("Top solid infill"));
|
||||
break;
|
||||
case GCodeViewer.EXTRUSION_ROLE_IRONING:
|
||||
titleView.setText(Slic3rLocalization.getString("Ironing"));
|
||||
break;
|
||||
case GCodeViewer.EXTRUSION_ROLE_BRIDGE_INFILL:
|
||||
titleView.setText(Slic3rLocalization.getString("Bridge infill"));
|
||||
break;
|
||||
case GCodeViewer.EXTRUSION_ROLE_GAP_FILL:
|
||||
titleView.setText(Slic3rLocalization.getString("Gap fill"));
|
||||
break;
|
||||
case GCodeViewer.EXTRUSION_ROLE_SKIRT:
|
||||
titleView.setText(Slic3rLocalization.getString("Skirt/Brim"));
|
||||
break;
|
||||
case GCodeViewer.EXTRUSION_ROLE_SUPPORT_MATERIAL:
|
||||
titleView.setText(Slic3rLocalization.getString("Support material"));
|
||||
break;
|
||||
case GCodeViewer.EXTRUSION_ROLE_SUPPORT_MATERIAL_INTERFACE:
|
||||
titleView.setText(Slic3rLocalization.getString("Support material interface"));
|
||||
break;
|
||||
case GCodeViewer.EXTRUSION_ROLE_WIPE_TOWER:
|
||||
titleView.setText(Slic3rLocalization.getString("Wipe tower"));
|
||||
break;
|
||||
case GCodeViewer.EXTRUSION_ROLE_CUSTOM:
|
||||
titleView.setText(Slic3rLocalization.getString("Custom"));
|
||||
break;
|
||||
}
|
||||
|
||||
timeView.setText(formatComplex(result.getUsedFilamentG(role), result.getUsedFilamentMM(role), viewer.getEstimatedTime(role)));
|
||||
|
||||
checkBox.setChecked(viewer.isExtrusionRoleVisible(role));
|
||||
checkBox.setButtonTintList(ColorStateList.valueOf(SegmentsView.mapColor(role)));
|
||||
setOnClickListener(v -> {
|
||||
if (getTotalEstimatedTime() == viewer.getEstimatedTime(role)) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewer.toggleExtrusionRoleVisible(role);
|
||||
checkBox.setChecked(!checkBox.isChecked());
|
||||
updateValues();
|
||||
if (invalidateGl != null) ViewUtils.removeCallbacks(invalidateGl);
|
||||
ViewUtils.postOnMainThread(invalidateGl = () -> {
|
||||
Pair<Long, Long> p = viewer.getLayersViewRange();
|
||||
viewer.setLayersViewRange(p.first, p.second);
|
||||
fragment.getGlView().requestRender();
|
||||
}, 250);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplyTheme() {
|
||||
titleView.setTextColor(ThemesRepo.getColor(android.R.attr.textColorPrimary));
|
||||
timeView.setTextColor(ThemesRepo.getColor(android.R.attr.textColorSecondary));
|
||||
setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), 12));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final static class LayersMenu extends UnfoldMenu {
|
||||
private PositionScrollView fromTrack, toTrack;
|
||||
private TextView title;
|
||||
|
||||
private Runnable applyCallback;
|
||||
|
||||
private GCodeViewer getViewer() {
|
||||
return fragment.getGlView().getRenderer().getViewer();
|
||||
}
|
||||
|
||||
private void applyView(int from, int to) {
|
||||
if (applyCallback != null) ViewUtils.removeCallbacks(applyCallback);
|
||||
|
||||
GCodeViewer viewer = getViewer();
|
||||
if (viewer == null) {
|
||||
return;
|
||||
@@ -218,15 +541,20 @@ public class SliceMenu extends ListBedMenu {
|
||||
if (toTrack.getCurrentPosition() < integer) {
|
||||
toTrack.setCurrentPosition(integer);
|
||||
}
|
||||
applyView(integer, toTrack.getCurrentPosition());
|
||||
title.setText(fragment.getContext().getString(R.string.MenuSliceInfoLayers, fromTrack.getCurrentPosition(), integer));
|
||||
|
||||
ViewUtils.removeCallbacks(applyCallback);
|
||||
ViewUtils.postOnMainThread(applyCallback = ()-> applyView(integer, toTrack.getCurrentPosition()), 50);
|
||||
});
|
||||
fromTrack.setListener(integer -> applyView(integer, toTrack.getCurrentPosition()));
|
||||
ll.addView(fromTrack, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(80)));
|
||||
|
||||
toTrack = new PositionScrollView(ctx);
|
||||
toTrack.setProgressListener(integer -> {
|
||||
// TODO: apply only visual?
|
||||
applyView(fromTrack.getCurrentPosition(), integer);
|
||||
title.setText(fragment.getContext().getString(R.string.MenuSliceInfoLayers, fromTrack.getCurrentPosition(), integer));
|
||||
|
||||
ViewUtils.removeCallbacks(applyCallback);
|
||||
ViewUtils.postOnMainThread(applyCallback = ()-> applyView(fromTrack.getCurrentPosition(), integer), 50);
|
||||
});
|
||||
toTrack.setListener(integer -> applyView(fromTrack.getCurrentPosition(), integer));
|
||||
ll.addView(toTrack, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(80)));
|
||||
@@ -267,6 +595,7 @@ public class SliceMenu extends ListBedMenu {
|
||||
super.onCreate();
|
||||
|
||||
GCodeViewer viewer = getViewer();
|
||||
if (viewer == null) return;
|
||||
long max = viewer.getLayersCount();
|
||||
fromTrack.setMinMax(1, (int) max);
|
||||
toTrack.setMinMax(1, (int) max);
|
||||
@@ -285,9 +614,6 @@ public class SliceMenu extends ListBedMenu {
|
||||
|
||||
fromTrack.stopScroll();
|
||||
toTrack.stopScroll();
|
||||
if (getViewer() != null) {
|
||||
applyView(1, (int) getViewer().getLayersCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,10 @@ public class BedFragment extends Fragment {
|
||||
public void showUnfoldMenu(UnfoldMenu menu, View from) {
|
||||
if (currentUnfoldMenu != null) return;
|
||||
|
||||
menu.setOnDismiss(()-> currentUnfoldMenu = null);
|
||||
menu.setOnDismiss(()-> {
|
||||
if (menu.isAttached()) return;
|
||||
currentUnfoldMenu = null;
|
||||
});
|
||||
currentUnfoldMenu = menu;
|
||||
menu.show(from, this);
|
||||
}
|
||||
@@ -469,6 +472,11 @@ public class BedFragment extends Fragment {
|
||||
super.onApplyTheme();
|
||||
|
||||
menuView.setBackgroundColor(ThemesRepo.getColor(android.R.attr.windowBackground));
|
||||
for (int i = 0; i < MenuCategory.values().length; i++) {
|
||||
if (i != currentMenuSlot) {
|
||||
ThemesRepo.invalidateView(menuMap.get(i).getView());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void constructMenuView(Context ctx, boolean portrait) {
|
||||
|
||||
@@ -39,13 +39,15 @@ public class FilamentConfigFragment extends ProfileListFragment {
|
||||
|
||||
List<ConfigObject> nList = new ArrayList<>(list.size());
|
||||
Slic3rUtils.ConfigChecker checker = new Slic3rUtils.ConfigChecker(SliceBeam.CONFIG.findPrinter(printer).serialize());
|
||||
Slic3rUtils.ConfigChecker printChecker = new Slic3rUtils.ConfigChecker(SliceBeam.CONFIG.findPrint(print).serialize());
|
||||
for (ConfigObject obj : list) {
|
||||
if (checker.checkCompatibility(obj.get("compatible_printers_condition")) && printChecker.checkCompatibility(obj.get("compatible_prints_condition"))) {
|
||||
nList.add(obj);
|
||||
if (SliceBeam.CONFIG.findPrint(print) != null) {
|
||||
Slic3rUtils.ConfigChecker printChecker = new Slic3rUtils.ConfigChecker(SliceBeam.CONFIG.findPrint(print).serialize());
|
||||
for (ConfigObject obj : list) {
|
||||
if (checker.checkCompatibility(obj.get("compatible_printers_condition")) && printChecker.checkCompatibility(obj.get("compatible_prints_condition"))) {
|
||||
nList.add(obj);
|
||||
}
|
||||
}
|
||||
printChecker.release();
|
||||
}
|
||||
printChecker.release();
|
||||
checker.release();
|
||||
lastPrinter = printer;
|
||||
lastPrint = print;
|
||||
|
||||
@@ -2,6 +2,8 @@ package ru.ytkab0bp.slicebeam.recycler;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
@@ -13,6 +15,8 @@ import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
@@ -29,6 +33,7 @@ public class PreferenceItem extends SimpleRecyclerItem<PreferenceItem.Preference
|
||||
private int textColorRes;
|
||||
private boolean noTint;
|
||||
private ValueProvider valueProvider;
|
||||
private float roundRadius;
|
||||
|
||||
public PreferenceItem setTitle(CharSequence title) {
|
||||
mTitle = title;
|
||||
@@ -70,6 +75,11 @@ public class PreferenceItem extends SimpleRecyclerItem<PreferenceItem.Preference
|
||||
return this;
|
||||
}
|
||||
|
||||
public PreferenceItem setRoundRadius(float roundRadius) {
|
||||
this.roundRadius = roundRadius;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PreferenceItem setTextColorRes(int textColorRes) {
|
||||
this.textColorRes = textColorRes;
|
||||
return this;
|
||||
@@ -94,6 +104,7 @@ public class PreferenceItem extends SimpleRecyclerItem<PreferenceItem.Preference
|
||||
private TextView title, subtitle;
|
||||
private ImageView icon;
|
||||
private TextView value;
|
||||
private float radius;
|
||||
|
||||
public PreferenceHolderView(Context context) {
|
||||
super(context);
|
||||
@@ -101,7 +112,23 @@ public class PreferenceItem extends SimpleRecyclerItem<PreferenceItem.Preference
|
||||
setOrientation(HORIZONTAL);
|
||||
setGravity(Gravity.CENTER_VERTICAL);
|
||||
|
||||
icon = new ImageView(context);
|
||||
icon = new AppCompatImageView(context) {
|
||||
private Path path = new Path();
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas) {
|
||||
if (radius != 0) {
|
||||
canvas.save();
|
||||
path.rewind();
|
||||
path.addRoundRect(0, 0, getWidth(), getHeight(), radius, radius, Path.Direction.CW);
|
||||
canvas.clipPath(path);
|
||||
}
|
||||
super.draw(canvas);
|
||||
if (radius != 0) {
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
};
|
||||
icon.setLayoutParams(new LayoutParams(ViewUtils.dp(28), ViewUtils.dp(28)) {{
|
||||
setMarginStart(ViewUtils.dp(4));
|
||||
setMarginEnd(ViewUtils.dp(8));
|
||||
@@ -178,6 +205,11 @@ public class PreferenceItem extends SimpleRecyclerItem<PreferenceItem.Preference
|
||||
} else {
|
||||
icon.setImageTintList(ColorStateList.valueOf(ThemesRepo.getColor(item.textColorRes != 0 ? item.textColorRes : android.R.attr.textColorSecondary)));
|
||||
}
|
||||
radius = item.roundRadius;
|
||||
icon.invalidate();
|
||||
|
||||
ViewGroup.LayoutParams params = icon.getLayoutParams();
|
||||
params.width = params.height = radius != 0 ? ViewUtils.dp(42) : ViewUtils.dp(28);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,6 +13,14 @@ public class GCodeProcessorResult {
|
||||
pointer = ptr;
|
||||
}
|
||||
|
||||
public double getUsedFilamentMM(@GCodeViewer.ExtrusionRole int role) {
|
||||
return Native.gcoderesult_get_used_filament_mm(pointer, role);
|
||||
}
|
||||
|
||||
public double getUsedFilamentG(@GCodeViewer.ExtrusionRole int role) {
|
||||
return Native.gcoderesult_get_used_filament_g(pointer, role);
|
||||
}
|
||||
|
||||
public String getRecommendedName() {
|
||||
return Native.gcoderesult_get_recommended_name(pointer);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,54 @@ import static ru.ytkab0bp.slicebeam.utils.DebugUtils.assertTrue;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import ru.ytkab0bp.slicebeam.R;
|
||||
import ru.ytkab0bp.slicebeam.theme.ThemesRepo;
|
||||
|
||||
public class GCodeViewer {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(value = {
|
||||
EXTRUSION_ROLE_NONE,
|
||||
EXTRUSION_ROLE_PERIMETER,
|
||||
EXTRUSION_ROLE_EXTERNAL_PERIMETER,
|
||||
EXTRUSION_ROLE_OVERHANG_PERIMETER,
|
||||
EXTRUSION_ROLE_INTERNAL_INFILL,
|
||||
EXTRUSION_ROLE_SOLID_INFILL,
|
||||
EXTRUSION_ROLE_TOP_SOLID_INFILL,
|
||||
EXTRUSION_ROLE_IRONING,
|
||||
EXTRUSION_ROLE_BRIDGE_INFILL,
|
||||
EXTRUSION_ROLE_GAP_FILL,
|
||||
EXTRUSION_ROLE_SKIRT,
|
||||
EXTRUSION_ROLE_SUPPORT_MATERIAL,
|
||||
EXTRUSION_ROLE_SUPPORT_MATERIAL_INTERFACE,
|
||||
EXTRUSION_ROLE_WIPE_TOWER,
|
||||
EXTRUSION_ROLE_CUSTOM
|
||||
})
|
||||
public @interface ExtrusionRole{}
|
||||
|
||||
public final static int EXTRUSION_ROLE_NONE = 0,
|
||||
EXTRUSION_ROLE_PERIMETER = 1,
|
||||
EXTRUSION_ROLE_EXTERNAL_PERIMETER = 2,
|
||||
EXTRUSION_ROLE_OVERHANG_PERIMETER = 3,
|
||||
EXTRUSION_ROLE_INTERNAL_INFILL = 4,
|
||||
EXTRUSION_ROLE_SOLID_INFILL = 5,
|
||||
EXTRUSION_ROLE_TOP_SOLID_INFILL = 6,
|
||||
EXTRUSION_ROLE_IRONING = 7,
|
||||
EXTRUSION_ROLE_BRIDGE_INFILL = 8,
|
||||
EXTRUSION_ROLE_GAP_FILL = 9,
|
||||
EXTRUSION_ROLE_SKIRT = 10,
|
||||
EXTRUSION_ROLE_SUPPORT_MATERIAL = 11,
|
||||
EXTRUSION_ROLE_SUPPORT_MATERIAL_INTERFACE = 12,
|
||||
EXTRUSION_ROLE_WIPE_TOWER = 13,
|
||||
EXTRUSION_ROLE_CUSTOM = 14,
|
||||
|
||||
EXTRUSION_ROLES_COUNT = 15;
|
||||
|
||||
private ThreadLocal<float[]> viewMatrixBuffer = new ThreadLocal<float[]>() {
|
||||
@Override
|
||||
protected float[] initialValue() {
|
||||
@@ -54,6 +96,22 @@ public class GCodeViewer {
|
||||
return Native.vgcode_get_layers_count(pointer);
|
||||
}
|
||||
|
||||
public float getEstimatedTime() {
|
||||
return Native.vgcode_get_estimated_time(pointer);
|
||||
}
|
||||
|
||||
public float getEstimatedTime(@ExtrusionRole int extrusionRole) {
|
||||
return Native.vgcode_get_estimated_time_role(pointer, extrusionRole);
|
||||
}
|
||||
|
||||
public boolean isExtrusionRoleVisible(@ExtrusionRole int extrusionRole) {
|
||||
return Native.vgcode_is_extrusion_role_visible(pointer, extrusionRole);
|
||||
}
|
||||
|
||||
public void toggleExtrusionRoleVisible(@ExtrusionRole int extrusionRole) {
|
||||
Native.vgcode_toggle_extrusion_role_visibility(pointer, extrusionRole);
|
||||
}
|
||||
|
||||
public void render(double[] viewMatrix, double[] projectionMatrix) {
|
||||
assertTrue(viewMatrix.length == 16);
|
||||
assertTrue(projectionMatrix.length == 16);
|
||||
|
||||
@@ -73,6 +73,8 @@ class Native {
|
||||
|
||||
static native long gcoderesult_load_file(String path, String name);
|
||||
static native String gcoderesult_get_recommended_name(long ptr);
|
||||
static native double gcoderesult_get_used_filament_mm(long ptr, int role);
|
||||
static native double gcoderesult_get_used_filament_g(long ptr, int role);
|
||||
static native void gcoderesult_release(long ptr);
|
||||
|
||||
static native long vgcode_create();
|
||||
@@ -84,6 +86,10 @@ class Native {
|
||||
static native void vgcode_render(long ptr, float[] viewMatrix, float[] projectionMatrix);
|
||||
static native void vgcode_set_layers_view_range(long ptr, long min, long max);
|
||||
static native long[] vgcode_get_layers_view_range(long ptr);
|
||||
static native float vgcode_get_estimated_time(long ptr);
|
||||
static native float vgcode_get_estimated_time_role(long ptr, int role);
|
||||
static native boolean vgcode_is_extrusion_role_visible(long ptr, int role);
|
||||
static native void vgcode_toggle_extrusion_role_visibility(long ptr, int role);
|
||||
static native void vgcode_reset(long ptr);
|
||||
static native void vgcode_release(long ptr);
|
||||
|
||||
|
||||
@@ -27,13 +27,21 @@ public class BeamTheme {
|
||||
colors.put(R.attr.modelHoverColor, 0xffffffff);
|
||||
colors.put(R.attr.textColorNegative, 0xffff464a);
|
||||
|
||||
colors.put(R.attr.gcodeViewerSkirt, 0x7FFF7F);
|
||||
colors.put(R.attr.gcodeViewerExternalPerimeter, 0xFFFF00);
|
||||
colors.put(R.attr.gcodeViewerSupportMaterial, 0x7FFF7F);
|
||||
colors.put(R.attr.gcodeViewerSupportMaterialInterface, 0x7FFF7F);
|
||||
colors.put(R.attr.gcodeViewerInternalInfill, 0xFF7F7F);
|
||||
colors.put(R.attr.gcodeViewerSolidInfill, 0xFF7F7F);
|
||||
colors.put(R.attr.gcodeViewerWipeTower, 0xF7FF7F);
|
||||
colors.put(R.attr.gcodeViewerNone, 0xFFE6B3B3);
|
||||
colors.put(R.attr.gcodeViewerPerimeter, 0xFFFFE64D);
|
||||
colors.put(R.attr.gcodeViewerExternalPerimeter, 0xFFFF7D38);
|
||||
colors.put(R.attr.gcodeViewerOverhangPerimeter, 0xFF1F1FFF);
|
||||
colors.put(R.attr.gcodeViewerInternalInfill, 0xFFB03029);
|
||||
colors.put(R.attr.gcodeViewerSolidInfill, 0xFF9654CC);
|
||||
colors.put(R.attr.gcodeViewerTopSolidInfill, 0xFFF04040);
|
||||
colors.put(R.attr.gcodeViewerIroning, 0xFFFF8C69);
|
||||
colors.put(R.attr.gcodeViewerBridgeInfill, 0xFF4D80BA);
|
||||
colors.put(R.attr.gcodeViewerGapFill, 0xFFFFFFFF);
|
||||
colors.put(R.attr.gcodeViewerSkirt, 0xFF00876E);
|
||||
colors.put(R.attr.gcodeViewerSupportMaterial, 0xFF00FF00);
|
||||
colors.put(R.attr.gcodeViewerSupportMaterialInterface, 0xFF008000);
|
||||
colors.put(R.attr.gcodeViewerWipeTower, 0xFFB3E3AB);
|
||||
colors.put(R.attr.gcodeViewerCustom, 0xFF5ED194);
|
||||
|
||||
colors.put(R.attr.xTrackColor, 0xffbf0000);
|
||||
colors.put(R.attr.yTrackColor, 0xff00bf00);
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
package ru.ytkab0bp.slicebeam.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.dynamicanimation.animation.FloatValueHolder;
|
||||
import androidx.dynamicanimation.animation.SpringAnimation;
|
||||
import androidx.dynamicanimation.animation.SpringForce;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import ru.ytkab0bp.slicebeam.R;
|
||||
import ru.ytkab0bp.slicebeam.slic3r.GCodeViewer;
|
||||
import ru.ytkab0bp.slicebeam.theme.ThemesRepo;
|
||||
import ru.ytkab0bp.slicebeam.utils.ViewUtils;
|
||||
|
||||
public class SegmentsView extends View {
|
||||
private Path path = new Path();
|
||||
private Paint paint = new Paint();
|
||||
private float showProgress;
|
||||
private boolean isVisible;
|
||||
private float[] currentValues;
|
||||
private SpringAnimation currentChangeAnimation;
|
||||
|
||||
public SegmentsView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void startAnimation() {
|
||||
isVisible = true;
|
||||
new SpringAnimation(new FloatValueHolder(0))
|
||||
.setMinimumVisibleChange(1 / 256f)
|
||||
.setSpring(new SpringForce(1f)
|
||||
.setStiffness(1000f)
|
||||
.setDampingRatio(1f))
|
||||
.addUpdateListener((animation, value, velocity) -> {
|
||||
showProgress = value;
|
||||
invalidate();
|
||||
})
|
||||
.start();
|
||||
}
|
||||
|
||||
public void setNotVisible() {
|
||||
isVisible = false;
|
||||
}
|
||||
|
||||
public void setValues(float[] values) {
|
||||
if (!isVisible || currentValues == null || currentValues.length != values.length) {
|
||||
currentValues = values;
|
||||
invalidate();
|
||||
} else {
|
||||
float[] prevValues = Arrays.copyOf(currentValues, currentValues.length);
|
||||
currentChangeAnimation = new SpringAnimation(new FloatValueHolder(0))
|
||||
.setMinimumVisibleChange(1 / 256f)
|
||||
.setSpring(new SpringForce(1f)
|
||||
.setStiffness(1000f)
|
||||
.setDampingRatio(1f))
|
||||
.addUpdateListener((animation, value, velocity) -> {
|
||||
for (int i = 0; i < currentValues.length; i++) {
|
||||
currentValues[i] = ViewUtils.lerp(prevValues[i], values[i], value);
|
||||
}
|
||||
invalidate();
|
||||
})
|
||||
.addEndListener((animation, canceled, value, velocity) -> {
|
||||
if (animation == currentChangeAnimation) {
|
||||
currentChangeAnimation = null;
|
||||
}
|
||||
});
|
||||
currentChangeAnimation.start();
|
||||
}
|
||||
}
|
||||
|
||||
public static int mapColor(@GCodeViewer.ExtrusionRole int index) {
|
||||
switch (index) {
|
||||
default:
|
||||
case GCodeViewer.EXTRUSION_ROLE_NONE:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerNone);
|
||||
case GCodeViewer.EXTRUSION_ROLE_PERIMETER:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerPerimeter);
|
||||
case GCodeViewer.EXTRUSION_ROLE_EXTERNAL_PERIMETER:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerExternalPerimeter);
|
||||
case GCodeViewer.EXTRUSION_ROLE_OVERHANG_PERIMETER:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerOverhangPerimeter);
|
||||
case GCodeViewer.EXTRUSION_ROLE_INTERNAL_INFILL:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerInternalInfill);
|
||||
case GCodeViewer.EXTRUSION_ROLE_SOLID_INFILL:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerSolidInfill);
|
||||
case GCodeViewer.EXTRUSION_ROLE_TOP_SOLID_INFILL:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerTopSolidInfill);
|
||||
case GCodeViewer.EXTRUSION_ROLE_IRONING:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerIroning);
|
||||
case GCodeViewer.EXTRUSION_ROLE_BRIDGE_INFILL:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerBridgeInfill);
|
||||
case GCodeViewer.EXTRUSION_ROLE_GAP_FILL:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerGapFill);
|
||||
case GCodeViewer.EXTRUSION_ROLE_SKIRT:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerSkirt);
|
||||
case GCodeViewer.EXTRUSION_ROLE_SUPPORT_MATERIAL:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerSupportMaterial);
|
||||
case GCodeViewer.EXTRUSION_ROLE_SUPPORT_MATERIAL_INTERFACE:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerSupportMaterialInterface);
|
||||
case GCodeViewer.EXTRUSION_ROLE_WIPE_TOWER:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerWipeTower);
|
||||
case GCodeViewer.EXTRUSION_ROLE_CUSTOM:
|
||||
return ThemesRepo.getColor(R.attr.gcodeViewerCustom);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(@NonNull Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
canvas.save();
|
||||
path.rewind();
|
||||
float cX = getWidth() / 2f;
|
||||
float l = 0, r = ViewUtils.lerp(0, getWidth(), showProgress);
|
||||
path.addRoundRect(l, 0, r, getHeight(), ViewUtils.dp(12), ViewUtils.dp(12), Path.Direction.CW);
|
||||
canvas.clipPath(path);
|
||||
if (currentValues != null) {
|
||||
float dw = r - l;
|
||||
for (int i = 1; i < currentValues.length; i++) {
|
||||
float prev = currentValues[i - 1];
|
||||
float to = currentValues[i];
|
||||
paint.setColor(mapColor(i - 1));
|
||||
canvas.drawRect(l + prev * dw, 0, l + to * dw, getHeight(), paint);
|
||||
}
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
@@ -637,6 +637,73 @@ extern "C" {
|
||||
return env->NewStringUTF(ref->name.c_str());
|
||||
}
|
||||
|
||||
GCodeExtrusionRole mapGCodeRole(int index) {
|
||||
GCodeExtrusionRole gRole;
|
||||
switch (index) {
|
||||
default:
|
||||
case 0:
|
||||
gRole = GCodeExtrusionRole::None;
|
||||
break;
|
||||
case 1:
|
||||
gRole = GCodeExtrusionRole::Perimeter;
|
||||
break;
|
||||
case 2:
|
||||
gRole = GCodeExtrusionRole::ExternalPerimeter;
|
||||
break;
|
||||
case 3:
|
||||
gRole = GCodeExtrusionRole::OverhangPerimeter;
|
||||
break;
|
||||
case 4:
|
||||
gRole = GCodeExtrusionRole::InternalInfill;
|
||||
break;
|
||||
case 5:
|
||||
gRole = GCodeExtrusionRole::SolidInfill;
|
||||
break;
|
||||
case 6:
|
||||
gRole = GCodeExtrusionRole::TopSolidInfill;
|
||||
break;
|
||||
case 7:
|
||||
gRole = GCodeExtrusionRole::Ironing;
|
||||
break;
|
||||
case 8:
|
||||
gRole = GCodeExtrusionRole::BridgeInfill;
|
||||
break;
|
||||
case 9:
|
||||
gRole = GCodeExtrusionRole::GapFill;
|
||||
break;
|
||||
case 10:
|
||||
gRole = GCodeExtrusionRole::Skirt;
|
||||
break;
|
||||
case 11:
|
||||
gRole = GCodeExtrusionRole::SupportMaterial;
|
||||
break;
|
||||
case 12:
|
||||
gRole = GCodeExtrusionRole::SupportMaterialInterface;
|
||||
break;
|
||||
case 13:
|
||||
gRole = GCodeExtrusionRole::WipeTower;
|
||||
break;
|
||||
case 14:
|
||||
gRole = GCodeExtrusionRole::Custom;
|
||||
break;
|
||||
}
|
||||
return gRole;
|
||||
}
|
||||
|
||||
JNIEXPORT jdouble JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_gcoderesult_1get_1used_1filament_1mm(JNIEnv* env, jclass, jlong ptr, jint role) {
|
||||
GCodeResultRef* ref = (GCodeResultRef*) (intptr_t) ptr;
|
||||
|
||||
std::pair<double, double> info = ref->result.print_statistics.used_filaments_per_role.find(mapGCodeRole(role))->second;
|
||||
return info.first * 1000.0 / 25.4;
|
||||
}
|
||||
|
||||
JNIEXPORT jdouble JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_gcoderesult_1get_1used_1filament_1g(JNIEnv* env, jclass, jlong ptr, jint role) {
|
||||
GCodeResultRef* ref = (GCodeResultRef*) (intptr_t) ptr;
|
||||
|
||||
std::pair<double, double> info = ref->result.print_statistics.used_filaments_per_role.find(mapGCodeRole(role))->second;
|
||||
return info.second;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_gcoderesult_1release(JNIEnv* env, jclass, jlong ptr) {
|
||||
GCodeResultRef* ref = (GCodeResultRef*) (intptr_t) ptr;
|
||||
delete ref;
|
||||
@@ -1139,4 +1206,77 @@ extern "C" {
|
||||
ref->viewer.shutdown();
|
||||
delete ref;
|
||||
}
|
||||
|
||||
JNIEXPORT jfloat JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_vgcode_1get_1estimated_1time(JNIEnv* env, jclass, jlong ptr) {
|
||||
GCodeViewerRef* ref = (GCodeViewerRef*) (intptr_t) ptr;
|
||||
return ref->viewer.get_estimated_time();
|
||||
}
|
||||
|
||||
libvgcode::EGCodeExtrusionRole mapRole(int index) {
|
||||
libvgcode::EGCodeExtrusionRole crole;
|
||||
switch (index) {
|
||||
default:
|
||||
case 0:
|
||||
crole = libvgcode::EGCodeExtrusionRole::None;
|
||||
break;
|
||||
case 1:
|
||||
crole = libvgcode::EGCodeExtrusionRole::Perimeter;
|
||||
break;
|
||||
case 2:
|
||||
crole = libvgcode::EGCodeExtrusionRole::ExternalPerimeter;
|
||||
break;
|
||||
case 3:
|
||||
crole = libvgcode::EGCodeExtrusionRole::OverhangPerimeter;
|
||||
break;
|
||||
case 4:
|
||||
crole = libvgcode::EGCodeExtrusionRole::InternalInfill;
|
||||
break;
|
||||
case 5:
|
||||
crole = libvgcode::EGCodeExtrusionRole::SolidInfill;
|
||||
break;
|
||||
case 6:
|
||||
crole = libvgcode::EGCodeExtrusionRole::TopSolidInfill;
|
||||
break;
|
||||
case 7:
|
||||
crole = libvgcode::EGCodeExtrusionRole::Ironing;
|
||||
break;
|
||||
case 8:
|
||||
crole = libvgcode::EGCodeExtrusionRole::BridgeInfill;
|
||||
break;
|
||||
case 9:
|
||||
crole = libvgcode::EGCodeExtrusionRole::GapFill;
|
||||
break;
|
||||
case 10:
|
||||
crole = libvgcode::EGCodeExtrusionRole::Skirt;
|
||||
break;
|
||||
case 11:
|
||||
crole = libvgcode::EGCodeExtrusionRole::SupportMaterial;
|
||||
break;
|
||||
case 12:
|
||||
crole = libvgcode::EGCodeExtrusionRole::SupportMaterialInterface;
|
||||
break;
|
||||
case 13:
|
||||
crole = libvgcode::EGCodeExtrusionRole::WipeTower;
|
||||
break;
|
||||
case 14:
|
||||
crole = libvgcode::EGCodeExtrusionRole::Custom;
|
||||
break;
|
||||
}
|
||||
return crole;
|
||||
}
|
||||
|
||||
JNIEXPORT jfloat JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_vgcode_1get_1estimated_1time_1role(JNIEnv* env, jclass, jlong ptr, jint role) {
|
||||
GCodeViewerRef* ref = (GCodeViewerRef*) (intptr_t) ptr;
|
||||
return ref->viewer.get_extrusion_role_estimated_time(mapRole(role));
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_vgcode_1is_1extrusion_1role_1visible(JNIEnv* env, jclass, jlong ptr, jint role) {
|
||||
GCodeViewerRef* ref = (GCodeViewerRef*) (intptr_t) ptr;
|
||||
return ref->viewer.is_extrusion_role_visible(mapRole(role));
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_ru_ytkab0bp_slicebeam_slic3r_Native_vgcode_1toggle_1extrusion_1role_1visibility(JNIEnv* env, jclass, jlong ptr, jint role) {
|
||||
GCodeViewerRef* ref = (GCodeViewerRef*) (intptr_t) ptr;
|
||||
ref->viewer.toggle_extrusion_role_visibility(mapRole(role));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="#000">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M440,777L440,503L200,364L200,638Q200,638 200,638Q200,638 200,638L440,777ZM520,777L760,638Q760,638 760,638Q760,638 760,638L760,364L520,503L520,777ZM480,434L717,297L480,160Q480,160 480,160Q480,160 480,160L243,297L480,434ZM160,708Q141,697 130.5,679Q120,661 120,639L120,321Q120,299 130.5,281Q141,263 160,252L440,91Q459,80 480,80Q501,80 520,91L800,252Q819,263 829.5,281Q840,299 840,321L840,639Q840,661 829.5,679Q819,697 800,708L520,869Q501,880 480,880Q459,880 440,869L160,708ZM480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480Z"/>
|
||||
</vector>
|
||||
|
After Width: | Height: | Size: 210 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 153 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 137 KiB |
|
After Width: | Height: | Size: 86 KiB |
@@ -18,6 +18,16 @@
|
||||
<string name="MenuFileCalibrationsLADescription">Калибровка Linear/Pressure Advance</string>
|
||||
<string name="MenuFileCalibrationsRetract">K3D Откаты</string>
|
||||
<string name="MenuFileCalibrationsRetractDescription">Калибровка расстояния и скорости откатов</string>
|
||||
<string name="MenuFileCalibrationsModels">Калибровочные модели</string>
|
||||
<string name="MenuFileCalibrationsModelsDescription">Библиотека калибровочных моделей</string>
|
||||
<string name="MenuFileCalibrationsModelsXYZCube">Калибровочный куб</string>
|
||||
<string name="MenuFileCalibrationsModelsBunny">Заяц</string>
|
||||
<string name="MenuFileCalibrationsModelsFox">Лис</string>
|
||||
<string name="MenuFileCalibrationsModelsBox">Куб</string>
|
||||
<string name="MenuFileCalibrationsModelsCone">Конус</string>
|
||||
<string name="MenuFileCalibrationsModelsCylinder">Цилиндр</string>
|
||||
<string name="MenuFileCalibrationsModelsPyramid">Пирамида</string>
|
||||
<string name="MenuFileCalibrationsModelsSphere">Сфера</string>
|
||||
<string name="MenuFileOpenFileLoaded">Файл загружен.</string>
|
||||
<string name="MenuFileImportProfiles">Импорт. профилей</string>
|
||||
<string name="MenuFileImportProfilesFailed">Не удалось импортировать</string>
|
||||
@@ -68,8 +78,13 @@
|
||||
<string name="MenuTransformMirrorZ">Отразить по Z</string>
|
||||
<string name="MenuModifiers">Модификаторы</string>
|
||||
<string name="MenuSlice">Нарезка</string>
|
||||
<!-- <string name="MenuSliceInfo">Информ.\nо печати</string>-->
|
||||
<string name="MenuSliceInfo">Слои</string>
|
||||
<string name="MenuSliceInfo">Информ.\nо печати</string>
|
||||
<string name="MenuSliceInfoSecond">с.</string>
|
||||
<string name="MenuSliceInfoMinute">мин.</string>
|
||||
<string name="MenuSliceInfoHour">ч.</string>
|
||||
<string name="MenuSliceInfoWeight">г.</string>
|
||||
<string name="MenuSliceInfoLength">мм.</string>
|
||||
<string name="MenuSliceLayers">Слои</string>
|
||||
<string name="MenuSliceInfoLayers">Слои %d - %d</string>
|
||||
<string name="MenuSliceExportToFile">Экспорт. в файл</string>
|
||||
<string name="MenuSliceShare">Отправка</string>
|
||||
|
||||
@@ -9,13 +9,21 @@
|
||||
<attr name="dividerColor" format="reference|color"/>
|
||||
<attr name="dividerContrastColor" format="reference|color"/>
|
||||
<attr name="dialogBackground" format="reference|color"/>
|
||||
<attr name="gcodeViewerSkirt" format="reference|color"/>
|
||||
<attr name="gcodeViewerNone" format="reference|color"/>
|
||||
<attr name="gcodeViewerPerimeter" format="reference|color"/>
|
||||
<attr name="gcodeViewerExternalPerimeter" format="reference|color"/>
|
||||
<attr name="gcodeViewerSupportMaterial" format="reference|color"/>
|
||||
<attr name="gcodeViewerSupportMaterialInterface" format="reference|color"/>
|
||||
<attr name="gcodeViewerOverhangPerimeter" format="reference|color"/>
|
||||
<attr name="gcodeViewerInternalInfill" format="reference|color"/>
|
||||
<attr name="gcodeViewerSolidInfill" format="reference|color"/>
|
||||
<attr name="gcodeViewerTopSolidInfill" format="reference|color"/>
|
||||
<attr name="gcodeViewerIroning" format="reference|color"/>
|
||||
<attr name="gcodeViewerBridgeInfill" format="reference|color"/>
|
||||
<attr name="gcodeViewerGapFill" format="reference|color"/>
|
||||
<attr name="gcodeViewerSkirt" format="reference|color"/>
|
||||
<attr name="gcodeViewerSupportMaterial" format="reference|color"/>
|
||||
<attr name="gcodeViewerSupportMaterialInterface" format="reference|color"/>
|
||||
<attr name="gcodeViewerWipeTower" format="reference|color"/>
|
||||
<attr name="gcodeViewerCustom" format="reference|color"/>
|
||||
<attr name="switchThumbUncheckedColor" format="reference|color"/>
|
||||
<attr name="boostyColorTop" format="reference|color"/>
|
||||
<attr name="boostyColorBottom" format="reference|color"/>
|
||||
|
||||
@@ -20,6 +20,17 @@
|
||||
<string name="MenuFileCalibrationsLADescription">Linear/Pressure Advance Calibration</string>
|
||||
<string name="MenuFileCalibrationsRetract">K3D Retractions</string>
|
||||
<string name="MenuFileCalibrationsRetractDescription">Retraction distance and speed calibration</string>
|
||||
<string name="MenuFileCalibrationsModels">Calibration models</string>
|
||||
<string name="MenuFileCalibrationsModelsDescription">Calibration models library</string>
|
||||
<string name="MenuFileCalibrationsModels3DBenchy" translatable="false">3D Benchy</string>
|
||||
<string name="MenuFileCalibrationsModelsXYZCube">Calibration cube</string>
|
||||
<string name="MenuFileCalibrationsModelsBunny">Bunny</string>
|
||||
<string name="MenuFileCalibrationsModelsFox">Fox</string>
|
||||
<string name="MenuFileCalibrationsModelsBox">Box</string>
|
||||
<string name="MenuFileCalibrationsModelsCone">Cone</string>
|
||||
<string name="MenuFileCalibrationsModelsCylinder">Cylinder</string>
|
||||
<string name="MenuFileCalibrationsModelsPyramid">Pyramid</string>
|
||||
<string name="MenuFileCalibrationsModelsSphere">Sphere</string>
|
||||
<string name="MenuFileImportProfiles">Import profiles</string>
|
||||
<string name="MenuFileImportProfilesFailed">Import failed</string>
|
||||
<string name="MenuFileImportProfilesFailedNotIni">Not an .ini file</string>
|
||||
@@ -69,8 +80,13 @@
|
||||
<string name="MenuTransformMirrorZ">Mirror Z</string>
|
||||
<string name="MenuModifiers">Modifiers</string>
|
||||
<string name="MenuSlice">Slice</string>
|
||||
<!-- <string name="MenuSliceInfo">Print\ninfo</string>-->
|
||||
<string name="MenuSliceInfo">Layers</string>
|
||||
<string name="MenuSliceInfo">Print\ninfo</string>
|
||||
<string name="MenuSliceInfoSecond">s.</string>
|
||||
<string name="MenuSliceInfoMinute">min.</string>
|
||||
<string name="MenuSliceInfoHour">h.</string>
|
||||
<string name="MenuSliceInfoWeight">g.</string>
|
||||
<string name="MenuSliceInfoLength">mm.</string>
|
||||
<string name="MenuSliceLayers">Layers</string>
|
||||
<string name="MenuSliceInfoLayers">Layers %d - %d</string>
|
||||
<string name="MenuSliceExportToFile">Export to file</string>
|
||||
<string name="MenuSliceShare">Share</string>
|
||||
|
||||