Add graphical toolbox, instead of text menu.
This commit is contained in:
parent
b0fc1df080
commit
486c342f86
@ -524,7 +524,7 @@ public class ProgramakerCustomBlockPart implements Part, ProgramakerSignalListen
|
|||||||
// Listen to signal
|
// Listen to signal
|
||||||
ProgramakerApi api = _partGrid.getApi();
|
ProgramakerApi api = _partGrid.getApi();
|
||||||
if (api == null) {
|
if (api == null) {
|
||||||
Log.e(LogTag, "Cannot listen to API (API not found)");
|
Log.i(LogTag, "Cannot listen to API. API not found, probably on a showcase.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,22 +70,22 @@ public class RoundButton implements Part {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int get_left() {
|
public int get_left() {
|
||||||
return _xCenter - _outerRadius / 2;
|
return _xCenter - _outerRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int get_right() {
|
public int get_right() {
|
||||||
return _xCenter + _outerRadius / 2;
|
return _xCenter + _outerRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int get_top() {
|
public int get_top() {
|
||||||
return _yCenter - _outerRadius / 2;
|
return _yCenter - _outerRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int get_bottom() {
|
public int get_bottom() {
|
||||||
return _yCenter + _outerRadius / 2;
|
return _yCenter + _outerRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,95 @@
|
|||||||
|
package com.codigoparallevar.minicards.toolbox;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.codigoparallevar.minicards.PartInstantiator;
|
||||||
|
import com.codigoparallevar.minicards.ScrolledCanvas;
|
||||||
|
import com.codigoparallevar.minicards.SignalListenerManager;
|
||||||
|
import com.codigoparallevar.minicards.types.Part;
|
||||||
|
import com.codigoparallevar.minicards.types.PartGrid;
|
||||||
|
import com.codigoparallevar.minicards.types.Selectable;
|
||||||
|
import com.codigoparallevar.minicards.types.connectors.input.AnyInputConnector;
|
||||||
|
import com.codigoparallevar.minicards.types.connectors.input.BooleanInputConnector;
|
||||||
|
import com.codigoparallevar.minicards.types.connectors.input.SignalInputConnector;
|
||||||
|
import com.codigoparallevar.minicards.types.connectors.input.StringInputConnector;
|
||||||
|
import com.codigoparallevar.minicards.types.functional.Tuple2;
|
||||||
|
import com.programaker.api.ProgramakerApi;
|
||||||
|
|
||||||
|
class PartShowcaseView extends View implements PartGrid {
|
||||||
|
private final Context ctx;
|
||||||
|
private final PartInstantiator instantiator;
|
||||||
|
private final Part part;
|
||||||
|
private final int partWidth;
|
||||||
|
private Tuple2<Integer, Integer> center = new Tuple2<>(0, 0);
|
||||||
|
|
||||||
|
public PartShowcaseView(Context ctx, PartInstantiator instantiator) {
|
||||||
|
super(ctx);
|
||||||
|
|
||||||
|
this.ctx = ctx;
|
||||||
|
this.instantiator = instantiator;
|
||||||
|
this.part = instantiator.build(this);
|
||||||
|
this.part.pause();
|
||||||
|
int height = this.part.get_bottom() - this.part.get_top();
|
||||||
|
partWidth = this.part.get_right() - this.part.get_left();
|
||||||
|
|
||||||
|
this.setMinimumHeight(height * 2);
|
||||||
|
this.setMinimumWidth(partWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw(Canvas canvas) {
|
||||||
|
int centerx = - Math.max(canvas.getWidth(), partWidth) / 2;
|
||||||
|
int centery = - canvas.getHeight() / 2;
|
||||||
|
this.center = new Tuple2<>(centerx, centery);
|
||||||
|
ScrolledCanvas scrolledCanvas = new ScrolledCanvas(canvas, getCenteredOn());
|
||||||
|
this.part.draw(scrolledCanvas, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Most interactive functionalities are not implemented, as it's not needed for the showcase
|
||||||
|
@Override
|
||||||
|
public Selectable getPartOn(int x, int y) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProgramakerApi getApi() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SignalListenerManager getListenerManager() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SignalInputConnector getSignalInputConnectorOn(int x, int y) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BooleanInputConnector getBooleanInputConnectorOn(int x, int y) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnyInputConnector getAnyInputConnectorOn(int x, int y) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StringInputConnector getStringInputConnectorOn(int xEnd, int yEnd) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Tuple2<Integer, Integer> getCenteredOn() {
|
||||||
|
return center;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -2,9 +2,16 @@ package com.codigoparallevar.minicards.toolbox;
|
|||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.graphics.Color;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.ScrollView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
import com.codigoparallevar.minicards.CanvasView;
|
import com.codigoparallevar.minicards.CanvasView;
|
||||||
import com.codigoparallevar.minicards.PartInstantiator;
|
import com.codigoparallevar.minicards.PartInstantiator;
|
||||||
@ -14,12 +21,13 @@ import com.codigoparallevar.minicards.parts.logic.Toggle;
|
|||||||
import com.codigoparallevar.minicards.parts.samples.ColorBox;
|
import com.codigoparallevar.minicards.parts.samples.ColorBox;
|
||||||
import com.codigoparallevar.minicards.parts.strings.ConvertToString;
|
import com.codigoparallevar.minicards.parts.strings.ConvertToString;
|
||||||
import com.codigoparallevar.minicards.types.Part;
|
import com.codigoparallevar.minicards.types.Part;
|
||||||
|
import com.codigoparallevar.minicards.types.functional.Consumer;
|
||||||
import com.codigoparallevar.minicards.types.functional.Tuple2;
|
import com.codigoparallevar.minicards.types.functional.Tuple2;
|
||||||
|
import com.codigoparallevar.minicards.utils.Box;
|
||||||
import com.programaker.api.data.ProgramakerBridgeInfo;
|
import com.programaker.api.data.ProgramakerBridgeInfo;
|
||||||
import com.programaker.api.data.ProgramakerCustomBlock;
|
import com.programaker.api.data.ProgramakerCustomBlock;
|
||||||
import com.programaker.api.data.api_results.ProgramakerBridgeCustomBlockResult;
|
import com.programaker.api.data.api_results.ProgramakerBridgeCustomBlockResult;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -42,6 +50,7 @@ public class PartsHolder {
|
|||||||
add(new PartCategory("Testing", BuiltInParts));
|
add(new PartCategory("Testing", BuiltInParts));
|
||||||
}};
|
}};
|
||||||
private Map<String, ProgramakerBridgeInfo> bridgeInfoMap;
|
private Map<String, ProgramakerBridgeInfo> bridgeInfoMap;
|
||||||
|
private final static String LogTag = "PartsHolder";
|
||||||
|
|
||||||
public PartsHolder(Context context) {
|
public PartsHolder(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@ -49,61 +58,113 @@ public class PartsHolder {
|
|||||||
|
|
||||||
public void openAddPartModal(final CanvasView canvasView) {
|
public void openAddPartModal(final CanvasView canvasView) {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||||
Map<String, PartCategory> categoryOptions = getPartCategories();
|
|
||||||
String[] categoryNames = categoryOptions.keySet().toArray(new String[0]);
|
|
||||||
|
|
||||||
builder.setTitle("Choose part category")
|
// HACK : Nasty trick to make the accordion be able to close a dialog that still doesn't exist
|
||||||
.setItems(categoryNames, new DialogInterface.OnClickListener() {
|
Box<Dialog> openedDialog = new Box<>();
|
||||||
public void onClick(DialogInterface dialog, int whichCategory) {
|
Consumer<Void> onComplete = _void -> {
|
||||||
if ((whichCategory >= 0) && (whichCategory < categoryNames.length)){
|
if (openedDialog.get() == null) {
|
||||||
Map<String, PartInstantiator> parts = getPartTypes(categoryOptions.get(categoryNames[whichCategory]));
|
Log.e(LogTag, "Expected dialog to be opened already");
|
||||||
String[] partNames = parts.keySet().toArray(new String[0]);
|
|
||||||
|
|
||||||
builder.setTitle("Choose part type")
|
|
||||||
.setItems(partNames, (dialog1, whichPart) -> {
|
|
||||||
if ((whichPart >= 0) && (whichPart < partNames.length)) {
|
|
||||||
String partName = partNames[whichPart];
|
|
||||||
|
|
||||||
Log.d("Minicards partsHolder",
|
|
||||||
"Spawning " + partName);
|
|
||||||
|
|
||||||
PartInstantiator instantiator = parts.get(partName);
|
|
||||||
PartsHolder.this.runInstantiator(instantiator, canvasView);
|
|
||||||
}
|
}
|
||||||
});
|
else {
|
||||||
|
openedDialog.get().cancel();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Dialog dialog2 = builder.create();
|
View categoryAccordion = generateCategoryAccordion(canvasView, onComplete);
|
||||||
dialog2.show();
|
|
||||||
}
|
builder.setTitle("Choose part")
|
||||||
}
|
.setView(categoryAccordion);
|
||||||
});
|
|
||||||
|
|
||||||
Dialog dialog = builder.create();
|
Dialog dialog = builder.create();
|
||||||
|
openedDialog.set(dialog);
|
||||||
dialog.show();
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runInstantiator(PartInstantiator instantiator, CanvasView canvasView) {
|
private View generateCategoryAccordion(final CanvasView canvasView, Consumer<Void> signalComplete) {
|
||||||
Part part = instantiator.build(canvasView);
|
ScrollView view = new ScrollView(context);
|
||||||
canvasView.addPart(part);
|
LinearLayout layout = new LinearLayout(context);
|
||||||
|
layout.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
layout.setDividerPadding(10);
|
||||||
|
layout.setShowDividers(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE);
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
layout.setDividerDrawable(context.getDrawable(android.R.drawable.divider_horizontal_bright));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String,PartCategory> getPartCategories() {
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||||
Map<String, PartCategory> partTypes = new LinkedHashMap<>(Categories.size());
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
|
||||||
for (int i = 0; i < Categories.size(); i++) {
|
for (int i = 0; i < Categories.size(); i++) {
|
||||||
partTypes.put(Categories.get(i).getName(), Categories.get(i));
|
PartCategory category = Categories.get(i);
|
||||||
|
|
||||||
|
LinearLayout categoryRow = new LinearLayout(context);
|
||||||
|
LinearLayout showcases = new LinearLayout(context);
|
||||||
|
|
||||||
|
TextView categoryName = new TextView(context); //Creating Button
|
||||||
|
|
||||||
|
// Add category name
|
||||||
|
categoryName.setId(i); //Setting Id for using in future
|
||||||
|
categoryName.setText(category.getName()); //Setting text
|
||||||
|
categoryName.setTextSize(15); //Text Size
|
||||||
|
categoryName.setPadding(50, 50, 50, 50); //padding
|
||||||
|
categoryName.setLayoutParams(params); //Setting Layout Params
|
||||||
|
categoryName.setTextColor(Color.parseColor("#000000")); //Text Color
|
||||||
|
categoryName.setBackgroundColor(Color.parseColor("#ffffff"));
|
||||||
|
categoryName.setGravity(Gravity.CENTER);
|
||||||
|
categoryName.setClickable(true);
|
||||||
|
categoryName.setOnClickListener(v -> {
|
||||||
|
if (showcases.getVisibility() == View.GONE) {
|
||||||
|
showcases.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
showcases.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
showcases.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
showcases.setBackgroundColor(Color.parseColor("#BBBBBB"));
|
||||||
|
showcases.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
showcases.setDividerPadding(10);
|
||||||
|
showcases.setShowDividers(LinearLayout.SHOW_DIVIDER_BEGINNING | LinearLayout.SHOW_DIVIDER_MIDDLE);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
showcases.setDividerDrawable(context.getDrawable(android.R.drawable.divider_horizontal_bright));
|
||||||
}
|
}
|
||||||
|
|
||||||
return partTypes;
|
// Add showcases
|
||||||
|
int partHeights = 0;
|
||||||
|
for (Tuple2<String, PartInstantiator> entry : category.getParts()) {
|
||||||
|
PartShowcaseView showcase = new PartShowcaseView(context, entry.item2);
|
||||||
|
|
||||||
|
showcase.setClickable(true);
|
||||||
|
showcase.setOnClickListener(v -> {
|
||||||
|
Part part = entry.item2.build(canvasView);
|
||||||
|
canvasView.addPart(part);
|
||||||
|
try {
|
||||||
|
signalComplete.apply(null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
partHeights += showcase.getHeight();
|
||||||
|
|
||||||
|
showcases.addView(showcase);
|
||||||
|
}
|
||||||
|
showcases.setMinimumHeight(partHeights);
|
||||||
|
|
||||||
|
// Tie everything
|
||||||
|
categoryRow.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
categoryRow.addView(categoryName);
|
||||||
|
showcases.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
categoryRow.addView(showcases);
|
||||||
|
|
||||||
|
layout.addView(categoryRow);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, PartInstantiator> getPartTypes(PartCategory categoryOption) {
|
view.addView(layout);
|
||||||
HashMap<String, PartInstantiator> partMap = new LinkedHashMap<>();
|
return view;
|
||||||
|
|
||||||
for (Tuple2<String, PartInstantiator> part : categoryOption.getParts()) {
|
|
||||||
partMap.put(part.item1, part.item2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return partMap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCustomBlocks(List<ProgramakerBridgeInfo> bridgeInfo, List<ProgramakerBridgeCustomBlockResult> customBlocks) {
|
public void addCustomBlocks(List<ProgramakerBridgeInfo> bridgeInfo, List<ProgramakerBridgeCustomBlockResult> customBlocks) {
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.codigoparallevar.minicards.utils;
|
||||||
|
|
||||||
|
public class Box<T> {
|
||||||
|
private T val = null;
|
||||||
|
|
||||||
|
public Box() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Box(T val) {
|
||||||
|
this.val = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T get() {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(T val) {
|
||||||
|
this.val = val;
|
||||||
|
}
|
||||||
|
}
|
17
app/src/main/res/layout/toolbox_accordion.xml
Normal file
17
app/src/main/res/layout/toolbox_accordion.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?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"
|
||||||
|
android:id="@+id/linearLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
android:id="@+id/toolbox_accordion_list"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in New Issue
Block a user