mirror of
https://github.com/bancika/diy-layout-creator
synced 2026-11-13 02:32:09 +10:00
Improved precision of rendering
This commit is contained in:
@@ -386,8 +386,8 @@ public class DrawingManager {
|
||||
g2dWrapper.setColor(CONTROL_POINT_COLOR);
|
||||
Point2D controlPoint = component.getControlPoint(i);
|
||||
int pointSize = CONTROL_POINT_SIZE - 2;
|
||||
g2dWrapper.fillOval((int) (controlPoint.getX() - pointSize / 2),
|
||||
(int) (controlPoint.getY() - pointSize / 2), pointSize, pointSize);
|
||||
g2dWrapper.fillOval((int) Math.round(controlPoint.getX() - pointSize / 2),
|
||||
(int) Math.round(controlPoint.getY() - pointSize / 2), pointSize, pointSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -403,11 +403,11 @@ public class DrawingManager {
|
||||
int pointSize = CONTROL_POINT_SIZE;
|
||||
|
||||
g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR.darker());
|
||||
g2dWrapper.fillOval((int) (controlPoint.getX() - pointSize / 2),
|
||||
(int) (controlPoint.getY() - pointSize / 2), pointSize, pointSize);
|
||||
g2dWrapper.fillOval((int) Math.round(controlPoint.getX() - pointSize / 2),
|
||||
(int) Math.round(controlPoint.getY() - pointSize / 2), pointSize, pointSize);
|
||||
g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR);
|
||||
g2dWrapper.fillOval((int) (controlPoint.getX() - CONTROL_POINT_SIZE / 2 + 1),
|
||||
(int) (controlPoint.getY() - CONTROL_POINT_SIZE / 2 + 1), CONTROL_POINT_SIZE - 2,
|
||||
g2dWrapper.fillOval((int) Math.round(controlPoint.getX() - CONTROL_POINT_SIZE / 2 + 1),
|
||||
(int) Math.round(controlPoint.getY() - CONTROL_POINT_SIZE / 2 + 1), CONTROL_POINT_SIZE - 2,
|
||||
CONTROL_POINT_SIZE - 2);
|
||||
}
|
||||
}
|
||||
@@ -437,12 +437,12 @@ public class DrawingManager {
|
||||
for (Point2D point : controlPointSlot) {
|
||||
if (point != null) {
|
||||
g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR.darker());
|
||||
g2dWrapper.fillOval((int) (point.getX() - CONTROL_POINT_SIZE / 2),
|
||||
(int) (point.getY() - CONTROL_POINT_SIZE / 2), CONTROL_POINT_SIZE,
|
||||
g2dWrapper.fillOval((int) Math.round(point.getX() - CONTROL_POINT_SIZE / 2),
|
||||
(int) Math.round(point.getY() - CONTROL_POINT_SIZE / 2), CONTROL_POINT_SIZE,
|
||||
CONTROL_POINT_SIZE);
|
||||
g2dWrapper.setColor(SELECTED_CONTROL_POINT_COLOR);
|
||||
g2dWrapper.fillOval((int) (point.getX() - CONTROL_POINT_SIZE / 2 + 1),
|
||||
(int) (point.getY() - CONTROL_POINT_SIZE / 2 + 1), CONTROL_POINT_SIZE - 2,
|
||||
g2dWrapper.fillOval((int) Math.round(point.getX() - CONTROL_POINT_SIZE / 2 + 1),
|
||||
(int) Math.round(point.getY() - CONTROL_POINT_SIZE / 2 + 1), CONTROL_POINT_SIZE - 2,
|
||||
CONTROL_POINT_SIZE - 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1289,8 +1289,8 @@ public class Presenter implements IPlugInPort {
|
||||
// If there's no selection, the only thing to do is update the
|
||||
// selection rectangle and refresh.
|
||||
Rectangle oldSelectionRect = selectionRect == null ? null : new Rectangle(selectionRect);
|
||||
this.selectionRect = Utils.createRectangle(new Point((int)scaledPoint.getX(), (int)scaledPoint.getY()),
|
||||
new Point((int)previousDragPoint.getX(), (int)previousDragPoint.getY()));
|
||||
this.selectionRect = Utils.createRectangle(new Point((int) Math.round(scaledPoint.getX()), (int) Math.round(scaledPoint.getY())),
|
||||
new Point((int) Math.round(previousDragPoint.getX()), (int) Math.round(previousDragPoint.getY())));
|
||||
if (selectionRect.equals(oldSelectionRect)) {
|
||||
return true;
|
||||
}
|
||||
@@ -1621,8 +1621,8 @@ public class Presenter implements IPlugInPort {
|
||||
// If there's no selection finalize selectionRect and see which
|
||||
// components intersect with it.
|
||||
if (scaledPoint != null && previousDragPoint != null) {
|
||||
this.selectionRect = Utils.createRectangle(new Point((int)scaledPoint.getX(), (int)scaledPoint.getY()),
|
||||
new Point((int)previousDragPoint.getX(), (int)previousDragPoint.getY()));;
|
||||
this.selectionRect = Utils.createRectangle(new Point((int) Math.round(scaledPoint.getX()), (int) Math.round(scaledPoint.getY())),
|
||||
new Point((int) Math.round(previousDragPoint.getX()), (int) Math.round(previousDragPoint.getY())));;
|
||||
}
|
||||
List<IDIYComponent<?>> newSelection = new ArrayList<IDIYComponent<?>>();
|
||||
if (operationMode != OperationMode.HIGHLIGHT_CONNECTED_AREAS)
|
||||
|
||||
@@ -32,6 +32,8 @@ import com.thoughtworks.xstream.converters.UnmarshallingContext;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||
|
||||
import org.diylc.utils.MathUtils;
|
||||
|
||||
/**
|
||||
* Serializes {@link Area} objects by converting coordinates from pixels to inches, thus avoiding
|
||||
* the resolution to affect point placement.
|
||||
@@ -66,7 +68,7 @@ public class AreaConverter implements Converter {
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
writer.startNode("coordinate");
|
||||
writer.setValue(String.valueOf(coord[i]));
|
||||
writer.setValue(MathUtils.formatDouble(coord[i]));
|
||||
writer.endNode();
|
||||
}
|
||||
writer.endNode();
|
||||
@@ -87,7 +89,7 @@ public class AreaConverter implements Converter {
|
||||
List<java.lang.Double> values = new ArrayList<java.lang.Double>();
|
||||
while (reader.hasMoreChildren()) {
|
||||
reader.moveDown();
|
||||
values.add(java.lang.Double.parseDouble(reader.getValue()));
|
||||
values.add(MathUtils.parseDouble(reader.getValue()));
|
||||
reader.moveUp();
|
||||
}
|
||||
java.lang.Double[] coord = values.toArray(new java.lang.Double[0]);
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||
|
||||
import org.diylc.utils.Constants;
|
||||
import org.diylc.utils.MathUtils;
|
||||
|
||||
/**
|
||||
* Serializes {@link Point2D} objects by converting coordinates from pixels to inches, thus avoiding
|
||||
@@ -42,26 +43,27 @@ public class PointConverter implements Converter {
|
||||
@Override
|
||||
public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) {
|
||||
Point2D point = (Point2D) object;
|
||||
writer.addAttribute("x", Double.toString(1d * point.getX() / Constants.PIXELS_PER_INCH));
|
||||
writer.addAttribute("y", Double.toString(1d * point.getY() / Constants.PIXELS_PER_INCH));
|
||||
writer.addAttribute("x", MathUtils.formatDouble(1d * point.getX() / Constants.PIXELS_PER_INCH));
|
||||
writer.addAttribute("y", MathUtils.formatDouble(1d * point.getY() / Constants.PIXELS_PER_INCH));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
|
||||
double x;
|
||||
double y;
|
||||
if (reader.hasMoreChildren()) {
|
||||
reader.moveDown();
|
||||
x = Double.parseDouble(reader.getValue());
|
||||
x = MathUtils.parseDouble(reader.getValue());
|
||||
reader.moveUp();
|
||||
reader.moveDown();
|
||||
y = Double.parseDouble(reader.getValue());
|
||||
y = MathUtils.parseDouble(reader.getValue());
|
||||
reader.moveUp();
|
||||
return new Point2D.Double(x, y);
|
||||
} else {
|
||||
x = Double.parseDouble(reader.getAttribute("x"));
|
||||
y = Double.parseDouble(reader.getAttribute("y"));
|
||||
return new Point2D.Double(x * Constants.PIXELS_PER_INCH, y * Constants.PIXELS_PER_INCH);
|
||||
x = MathUtils.round(Double.parseDouble(reader.getAttribute("x")) * Constants.PIXELS_PER_INCH);
|
||||
y = MathUtils.round(Double.parseDouble(reader.getAttribute("y")) * Constants.PIXELS_PER_INCH);
|
||||
return new Point2D.Double(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.utils;
|
||||
|
||||
public class MathUtils {
|
||||
|
||||
public static String formatDouble(double value) {
|
||||
return Double.toString(Math.round(value * 1e8) / 1e8);
|
||||
}
|
||||
|
||||
public static Double round(double value) {
|
||||
return Math.round(value * 1e8) / 1e8;
|
||||
}
|
||||
|
||||
public static double parseDouble(String str) {
|
||||
return Math.round(Double.parseDouble(str) * 1e8) / 1e8;
|
||||
}
|
||||
}
|
||||
@@ -397,6 +397,10 @@
|
||||
<changeType>NEW_FEATURE</changeType>
|
||||
<description>Detect the style of a treble bleed based on the topology and component values (e.g. Fender, DiMarzio, Kinman, etc)</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>IMPROVEMENT</changeType>
|
||||
<description>Improved precision of rendering, in some cases there was a sub-pixel misalignment between the lines that should meet exactly</description>
|
||||
</org.diylc.appframework.update.Change>
|
||||
<org.diylc.appframework.update.Change>
|
||||
<changeType>BUG_FIX</changeType>
|
||||
<description>Tone capacitor mistaken for treble bleed when connected to the input lug of the volume pot</description>
|
||||
|
||||
@@ -1,173 +1,173 @@
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.testcomponents;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
import org.diylc.components.AbstractComponent;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.measures.Capacitance;
|
||||
import org.diylc.core.measures.CapacitanceUnit;
|
||||
import org.diylc.core.measures.Resistance;
|
||||
import org.diylc.core.measures.ResistanceUnit;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
|
||||
@ComponentDescriptor(name = "Mock", author = "bancika", category = "Sample", instanceNamePrefix = "M",
|
||||
description = "test", zOrder = IDIYComponent.COMPONENT)
|
||||
public class MockDIYComponent extends AbstractComponent<Capacitance> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String testField = "Hello World";
|
||||
private Capacitance c = new Capacitance(100d, CapacitanceUnit.uF);
|
||||
private Resistance r = new Resistance(123d, ResistanceUnit.K);
|
||||
private Size s = new Size(1d, SizeUnit.cm);
|
||||
private Color color = Color.green;
|
||||
private Point2D leftTopCorner = new Point(0, 0);
|
||||
private String name = "something";
|
||||
|
||||
public MockDIYComponent(String testField, Capacitance c, Resistance r, Size s, Color color, Point leftTopCorner) {
|
||||
super();
|
||||
this.testField = testField;
|
||||
this.c = c;
|
||||
this.r = r;
|
||||
this.s = s;
|
||||
this.color = color;
|
||||
this.leftTopCorner = leftTopCorner;
|
||||
}
|
||||
|
||||
public MockDIYComponent() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canControlPointOverlap(int index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getControlPointCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isControlPointSticky(int index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisibilityPolicy getControlPointVisibilityPolicy(int index) {
|
||||
return VisibilityPolicy.WHEN_SELECTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point2D getControlPoint(int index) {
|
||||
return leftTopCorner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setControlPoint(Point2D point, int index) {
|
||||
leftTopCorner.setLocation(point);
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Test Field")
|
||||
public String getTestField() {
|
||||
return testField;
|
||||
}
|
||||
|
||||
public void setTestField(String testField) {
|
||||
this.testField = testField;
|
||||
}
|
||||
|
||||
@EditableProperty(defaultable = true)
|
||||
public Capacitance getValue() {
|
||||
return c;
|
||||
}
|
||||
|
||||
public void setValue(Capacitance c) {
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
@EditableProperty(defaultable = true)
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public Resistance getR() {
|
||||
return r;
|
||||
}
|
||||
|
||||
// Setter is commented out, ClassProcessor should ignore this property.
|
||||
// public void setR(Resistance r) {
|
||||
// this.r = r;
|
||||
// }
|
||||
|
||||
// No annotation, so this property should be ignored.
|
||||
public Size getS() {
|
||||
return s;
|
||||
}
|
||||
|
||||
public void setS(Size s) {
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
g2d.setColor(componentState.equals(ComponentState.SELECTED) ? color : color.darker());
|
||||
g2d.fillRect((int)leftTopCorner.getX(), (int)leftTopCorner.getY(), 200, 50);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
g2d.drawString("X", 10, 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
||||
DIY Layout Creator (DIYLC).
|
||||
Copyright (c) 2009-2025 held jointly by the individual authors.
|
||||
|
||||
This file is part of DIYLC.
|
||||
|
||||
DIYLC is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DIYLC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
package org.diylc.testcomponents;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
import org.diylc.components.AbstractComponent;
|
||||
import org.diylc.core.ComponentState;
|
||||
import org.diylc.core.IDIYComponent;
|
||||
import org.diylc.core.IDrawingObserver;
|
||||
import org.diylc.core.Project;
|
||||
import org.diylc.core.VisibilityPolicy;
|
||||
import org.diylc.core.annotations.ComponentDescriptor;
|
||||
import org.diylc.core.annotations.EditableProperty;
|
||||
import org.diylc.core.measures.Capacitance;
|
||||
import org.diylc.core.measures.CapacitanceUnit;
|
||||
import org.diylc.core.measures.Resistance;
|
||||
import org.diylc.core.measures.ResistanceUnit;
|
||||
import org.diylc.core.measures.Size;
|
||||
import org.diylc.core.measures.SizeUnit;
|
||||
|
||||
@ComponentDescriptor(name = "Mock", author = "bancika", category = "Sample", instanceNamePrefix = "M",
|
||||
description = "test", zOrder = IDIYComponent.COMPONENT)
|
||||
public class MockDIYComponent extends AbstractComponent<Capacitance> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String testField = "Hello World";
|
||||
private Capacitance c = new Capacitance(100d, CapacitanceUnit.uF);
|
||||
private Resistance r = new Resistance(123d, ResistanceUnit.K);
|
||||
private Size s = new Size(1d, SizeUnit.cm);
|
||||
private Color color = Color.green;
|
||||
private Point2D leftTopCorner = new Point(0, 0);
|
||||
private String name = "something";
|
||||
|
||||
public MockDIYComponent(String testField, Capacitance c, Resistance r, Size s, Color color, Point leftTopCorner) {
|
||||
super();
|
||||
this.testField = testField;
|
||||
this.c = c;
|
||||
this.r = r;
|
||||
this.s = s;
|
||||
this.color = color;
|
||||
this.leftTopCorner = leftTopCorner;
|
||||
}
|
||||
|
||||
public MockDIYComponent() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canControlPointOverlap(int index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getControlPointCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isControlPointSticky(int index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisibilityPolicy getControlPointVisibilityPolicy(int index) {
|
||||
return VisibilityPolicy.WHEN_SELECTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point2D getControlPoint(int index) {
|
||||
return leftTopCorner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setControlPoint(Point2D point, int index) {
|
||||
leftTopCorner.setLocation(point);
|
||||
}
|
||||
|
||||
@EditableProperty(name = "Test Field")
|
||||
public String getTestField() {
|
||||
return testField;
|
||||
}
|
||||
|
||||
public void setTestField(String testField) {
|
||||
this.testField = testField;
|
||||
}
|
||||
|
||||
@EditableProperty(defaultable = true)
|
||||
public Capacitance getValue() {
|
||||
return c;
|
||||
}
|
||||
|
||||
public void setValue(Capacitance c) {
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
@EditableProperty(defaultable = true)
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@EditableProperty
|
||||
public Resistance getR() {
|
||||
return r;
|
||||
}
|
||||
|
||||
// Setter is commented out, ClassProcessor should ignore this property.
|
||||
// public void setR(Resistance r) {
|
||||
// this.r = r;
|
||||
// }
|
||||
|
||||
// No annotation, so this property should be ignored.
|
||||
public Size getS() {
|
||||
return s;
|
||||
}
|
||||
|
||||
public void setS(Size s) {
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g2d, ComponentState componentState, boolean outlineMode, Project project,
|
||||
IDrawingObserver drawingObserver) {
|
||||
g2d.setColor(componentState.equals(ComponentState.SELECTED) ? color : color.darker());
|
||||
g2d.fillRect((int) Math.round(leftTopCorner.getX()), (int) Math.round(leftTopCorner.getY()), 200, 50);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawIcon(Graphics2D g2d, int width, int height) {
|
||||
g2d.drawString("X", 10, 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getControlPointNodeName(int index) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user