mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2024-12-19 13:07:52 +00:00
Improved separation between Widgets
This commit is contained in:
parent
dcbefa996c
commit
055a161b17
@ -90,11 +90,11 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
|
||||
|
||||
this.graphLayout.getNodesWidget().addOnNodeDraggingCallback((event: any, n: Node) => {
|
||||
const linksWidget = this.graphLayout.getLinksWidget();
|
||||
linksWidget.select(this.svg).each(function(this: SVGGElement, link: Link) {
|
||||
if (link.target.node_id === n.node_id || link.source.node_id === n.node_id) {
|
||||
const selection = select<SVGElement, Link>(this);
|
||||
linksWidget.revise(selection);
|
||||
}
|
||||
|
||||
const links = this.links.filter((link) => link.target.node_id === n.node_id || link.source.node_id === n.node_id)
|
||||
|
||||
links.forEach((link) => {
|
||||
linksWidget.redrawLink(this.svg, link);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -22,7 +22,7 @@ export class EllipseDrawingWidget implements DrawingWidget {
|
||||
const drawing_enter = drawing
|
||||
.enter()
|
||||
.append<SVGEllipseElement>('ellipse')
|
||||
.attr('class', 'ellipse_element noselect');
|
||||
.attr('class', 'ellipse_element noselect');
|
||||
|
||||
const merge = drawing.merge(drawing_enter);
|
||||
|
||||
|
74
src/app/cartography/widgets/interface-status.ts
Normal file
74
src/app/cartography/widgets/interface-status.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { select } from "d3-selection";
|
||||
|
||||
import { Widget } from "./widget";
|
||||
import { SVGSelection } from "../models/types";
|
||||
import { Link } from "../../models/link";
|
||||
import { LinkStatus } from "../models/link-status";
|
||||
|
||||
|
||||
export class InterfaceStatusWidget implements Widget {
|
||||
constructor() {}
|
||||
|
||||
public draw(view: SVGSelection) {
|
||||
view.each(function (this: SVGGElement, l: Link) {
|
||||
const link_group = select<SVGGElement, Link>(this);
|
||||
const link_path = link_group.select<SVGPathElement>('path');
|
||||
|
||||
const start_point: SVGPoint = link_path.node().getPointAtLength(45);
|
||||
const end_point: SVGPoint = link_path.node().getPointAtLength(link_path.node().getTotalLength() - 45);
|
||||
|
||||
let statuses = [];
|
||||
|
||||
|
||||
if (link_path.node().getTotalLength() > 2 * 45 + 10) {
|
||||
statuses = [
|
||||
new LinkStatus(start_point.x, start_point.y, l.source.status),
|
||||
new LinkStatus(end_point.x, end_point.y, l.target.status)
|
||||
];
|
||||
}
|
||||
|
||||
const status_started = link_group
|
||||
.selectAll<SVGCircleElement, LinkStatus>('circle.status_started')
|
||||
.data(statuses.filter((link_status: LinkStatus) => link_status.status === 'started'));
|
||||
|
||||
const status_started_enter = status_started
|
||||
.enter()
|
||||
.append<SVGCircleElement>('circle');
|
||||
|
||||
status_started
|
||||
.merge(status_started_enter)
|
||||
.attr('class', 'status_started')
|
||||
.attr('cx', (ls: LinkStatus) => ls.x)
|
||||
.attr('cy', (ls: LinkStatus) => ls.y)
|
||||
.attr('r', 6)
|
||||
.attr('fill', '#2ecc71');
|
||||
|
||||
status_started
|
||||
.exit()
|
||||
.remove();
|
||||
|
||||
const status_stopped = link_group
|
||||
.selectAll<SVGRectElement, LinkStatus>('rect.status_stopped')
|
||||
.data(statuses.filter((link_status: LinkStatus) => link_status.status === 'stopped'));
|
||||
|
||||
const status_stopped_enter = status_stopped
|
||||
.enter()
|
||||
.append<SVGRectElement>('rect');
|
||||
|
||||
const STOPPED_STATUS_RECT_WIDTH = 10;
|
||||
|
||||
status_stopped
|
||||
.merge(status_stopped_enter)
|
||||
.attr('class', 'status_stopped')
|
||||
.attr('x', (ls: LinkStatus) => ls.x - STOPPED_STATUS_RECT_WIDTH / 2.)
|
||||
.attr('y', (ls: LinkStatus) => ls.y - STOPPED_STATUS_RECT_WIDTH / 2.)
|
||||
.attr('width', STOPPED_STATUS_RECT_WIDTH)
|
||||
.attr('height', STOPPED_STATUS_RECT_WIDTH)
|
||||
.attr('fill', 'red');
|
||||
|
||||
status_stopped
|
||||
.exit()
|
||||
.remove();
|
||||
});
|
||||
}
|
||||
}
|
53
src/app/cartography/widgets/link.ts
Normal file
53
src/app/cartography/widgets/link.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { Widget } from "./widget";
|
||||
import { SVGSelection } from "../models/types";
|
||||
import { Link } from "../../models/link";
|
||||
import { SerialLinkWidget } from "./links/serial-link";
|
||||
import { EthernetLinkWidget } from "./links/ethernet-link";
|
||||
import { MultiLinkCalculatorHelper } from "../helpers/multi-link-calculator-helper";
|
||||
import { InterfaceLabelWidget } from "./interface-label";
|
||||
import { CssFixer } from "../helpers/css-fixer";
|
||||
import { InterfaceStatusWidget } from "./interface-status";
|
||||
|
||||
|
||||
export class LinkWidget implements Widget {
|
||||
private multiLinkCalculatorHelper = new MultiLinkCalculatorHelper();
|
||||
|
||||
constructor() {}
|
||||
|
||||
public getInterfaceLabelWidget() {
|
||||
return new InterfaceLabelWidget(new CssFixer());
|
||||
}
|
||||
|
||||
public getInterfaceStatusWidget() {
|
||||
return new InterfaceStatusWidget();
|
||||
}
|
||||
|
||||
public draw(view: SVGSelection) {
|
||||
const link_body = view.selectAll<SVGGElement, Link>("g.link_body")
|
||||
.data((l) => [l]);
|
||||
|
||||
const link_body_enter = link_body.enter()
|
||||
.append<SVGGElement>('g')
|
||||
.attr("class", "link_body");
|
||||
|
||||
const link_body_merge = link_body.merge(link_body_enter)
|
||||
.attr('transform', (link) => {
|
||||
const translation = this.multiLinkCalculatorHelper.linkTranslation(link.distance, link.source, link.target);
|
||||
return `translate (${translation.dx}, ${translation.dy})`;
|
||||
});
|
||||
|
||||
const serial_link_widget = new SerialLinkWidget();
|
||||
serial_link_widget.draw(link_body_merge);
|
||||
|
||||
const ethernet_link_widget = new EthernetLinkWidget();
|
||||
ethernet_link_widget.draw(link_body_merge);
|
||||
|
||||
link_body_merge
|
||||
.select<SVGPathElement>('path')
|
||||
.classed('selected', (l: Link) => l.is_selected);
|
||||
|
||||
this.getInterfaceLabelWidget().draw(link_body_merge);
|
||||
this.getInterfaceStatusWidget().draw(link_body_merge);
|
||||
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { anything, instance, mock, verify } from "ts-mockito";
|
||||
import { instance, mock } from "ts-mockito";
|
||||
import { Selection } from "d3-selection";
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import { Layer } from "../models/layer";
|
||||
import { LinksWidget } from "./links";
|
||||
import { Node } from "../models/node";
|
||||
import { Link } from "../../models/link";
|
||||
import { InterfaceLabelWidget } from "./interface-label";
|
||||
import { LinkWidget } from "./link";
|
||||
|
||||
|
||||
describe('LinksWidget', () => {
|
||||
@ -62,9 +62,9 @@ describe('LinksWidget', () => {
|
||||
});
|
||||
|
||||
it('should draw links', () => {
|
||||
const interfaceLabelWidgetMock = mock(InterfaceLabelWidget);
|
||||
const interfaceLabelWidget = instance(interfaceLabelWidgetMock);
|
||||
spyOn(widget, 'getInterfaceLabelWidget').and.returnValue(interfaceLabelWidget);
|
||||
const linkWidgetMock = mock(LinkWidget);
|
||||
const linkWidget = instance(linkWidgetMock);
|
||||
spyOn(widget, 'getLinkWidget').and.returnValue(linkWidget);
|
||||
|
||||
widget.draw(layersEnter);
|
||||
|
||||
@ -73,9 +73,6 @@ describe('LinksWidget', () => {
|
||||
expect(linkNode.getAttribute('link_id')).toEqual('link1');
|
||||
expect(linkNode.getAttribute('map-source')).toEqual('1');
|
||||
expect(linkNode.getAttribute('map-target')).toEqual('2');
|
||||
expect(linkNode.getAttribute('transform')).toEqual('translate (0, 0)');
|
||||
|
||||
verify(interfaceLabelWidgetMock.draw(anything())).called();
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -1,125 +1,27 @@
|
||||
import { select } from "d3-selection";
|
||||
|
||||
import { Widget } from "./widget";
|
||||
import { SVGSelection } from "../models/types";
|
||||
import { Link } from "../../models/link";
|
||||
import { LinkStatus } from "../models/link-status";
|
||||
import { MultiLinkCalculatorHelper } from "../helpers/multi-link-calculator-helper";
|
||||
import { SerialLinkWidget } from "./links/serial-link";
|
||||
import { EthernetLinkWidget } from "./links/ethernet-link";
|
||||
import { Layer } from "../models/layer";
|
||||
import { InterfaceLabelWidget } from "./interface-label";
|
||||
import { CssFixer } from "../helpers/css-fixer";
|
||||
import { LinkWidget } from "./link";
|
||||
|
||||
|
||||
export class LinksWidget implements Widget {
|
||||
private multiLinkCalculatorHelper = new MultiLinkCalculatorHelper();
|
||||
|
||||
private interfaceLabelWidget: InterfaceLabelWidget;
|
||||
private linkWidget = new LinkWidget();
|
||||
|
||||
constructor() {
|
||||
this.interfaceLabelWidget = new InterfaceLabelWidget(new CssFixer());
|
||||
}
|
||||
|
||||
public getInterfaceLabelWidget() {
|
||||
return this.interfaceLabelWidget;
|
||||
public getLinkWidget() {
|
||||
return this.linkWidget
|
||||
}
|
||||
|
||||
public setInterfaceLabelWidget(interfaceLabelWidget: InterfaceLabelWidget) {
|
||||
this.interfaceLabelWidget = interfaceLabelWidget;
|
||||
public redrawLink(view: SVGSelection, link: Link) {
|
||||
this.getLinkWidget().draw(this.selectLink(view, link));
|
||||
}
|
||||
|
||||
public getLinkWidget(link: Link) {
|
||||
if (link.link_type === 'serial') {
|
||||
return new SerialLinkWidget();
|
||||
}
|
||||
return new EthernetLinkWidget();
|
||||
}
|
||||
|
||||
public select(view: SVGSelection) {
|
||||
return view.selectAll<SVGGElement, Link>("g.link");
|
||||
}
|
||||
|
||||
public revise(selection: SVGSelection) {
|
||||
const self = this;
|
||||
|
||||
selection
|
||||
.each(function (this: SVGGElement, l: Link) {
|
||||
const link_group = select<SVGGElement, Link>(this);
|
||||
const link_widget = self.getLinkWidget(l);
|
||||
|
||||
link_widget.draw(link_group, l);
|
||||
|
||||
const link_path = link_group.select<SVGPathElement>('path');
|
||||
|
||||
const start_point: SVGPoint = link_path.node().getPointAtLength(45);
|
||||
const end_point: SVGPoint = link_path.node().getPointAtLength(link_path.node().getTotalLength() - 45);
|
||||
|
||||
let statuses = [];
|
||||
|
||||
if (link_path.node().getTotalLength() > 2 * 45 + 10) {
|
||||
statuses = [
|
||||
new LinkStatus(start_point.x, start_point.y, l.source.status),
|
||||
new LinkStatus(end_point.x, end_point.y, l.target.status)
|
||||
];
|
||||
}
|
||||
|
||||
const status_started = link_group
|
||||
.selectAll<SVGCircleElement, LinkStatus>('circle.status_started')
|
||||
.data(statuses.filter((link_status: LinkStatus) => link_status.status === 'started'));
|
||||
|
||||
const status_started_enter = status_started
|
||||
.enter()
|
||||
.append<SVGCircleElement>('circle');
|
||||
|
||||
status_started
|
||||
.merge(status_started_enter)
|
||||
.attr('class', 'status_started')
|
||||
.attr('cx', (ls: LinkStatus) => ls.x)
|
||||
.attr('cy', (ls: LinkStatus) => ls.y)
|
||||
.attr('r', 6)
|
||||
.attr('fill', '#2ecc71');
|
||||
|
||||
status_started
|
||||
.exit()
|
||||
.remove();
|
||||
|
||||
const status_stopped = link_group
|
||||
.selectAll<SVGRectElement, LinkStatus>('rect.status_stopped')
|
||||
.data(statuses.filter((link_status: LinkStatus) => link_status.status === 'stopped'));
|
||||
|
||||
const status_stopped_enter = status_stopped
|
||||
.enter()
|
||||
.append<SVGRectElement>('rect');
|
||||
|
||||
const STOPPED_STATUS_RECT_WIDTH = 10;
|
||||
|
||||
status_stopped
|
||||
.merge(status_stopped_enter)
|
||||
.attr('class', 'status_stopped')
|
||||
.attr('x', (ls: LinkStatus) => ls.x - STOPPED_STATUS_RECT_WIDTH / 2.)
|
||||
.attr('y', (ls: LinkStatus) => ls.y - STOPPED_STATUS_RECT_WIDTH / 2.)
|
||||
.attr('width', STOPPED_STATUS_RECT_WIDTH)
|
||||
.attr('height', STOPPED_STATUS_RECT_WIDTH)
|
||||
.attr('fill', 'red');
|
||||
|
||||
status_stopped
|
||||
.exit()
|
||||
.remove();
|
||||
|
||||
})
|
||||
.attr('transform', function(l) {
|
||||
if (l.source && l.target) {
|
||||
const translation = self.multiLinkCalculatorHelper.linkTranslation(l.distance, l.source, l.target);
|
||||
return `translate (${translation.dx}, ${translation.dy})`;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
this.getInterfaceLabelWidget().draw(selection);
|
||||
}
|
||||
|
||||
public draw(view: SVGSelection, links?: Link[]) {
|
||||
public draw(view: SVGSelection) {
|
||||
const link = view
|
||||
.selectAll<SVGGElement, Link>("g.link")
|
||||
.data((layer: Layer) => {
|
||||
@ -144,12 +46,14 @@ export class LinksWidget implements Widget {
|
||||
|
||||
const merge = link.merge(link_enter);
|
||||
|
||||
this.revise(merge);
|
||||
|
||||
this.getLinkWidget().draw(merge);
|
||||
|
||||
link
|
||||
.exit()
|
||||
.remove();
|
||||
}
|
||||
|
||||
private selectLink(view: SVGSelection, link: Link) {
|
||||
return view.selectAll<SVGGElement, Link>(`g.link[link_id="${link.link_id}"]`);
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,52 @@
|
||||
import { line } from "d3-shape";
|
||||
import { path } from "d3-path";
|
||||
|
||||
import { Widget } from "../widget";
|
||||
import { SVGSelection } from "../../models/types";
|
||||
import { Link } from "../../../models/link";
|
||||
|
||||
class EthernetLinkPath {
|
||||
constructor(
|
||||
public source: [number, number],
|
||||
public target: [number, number]
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
export class EthernetLinkWidget implements Widget {
|
||||
|
||||
public draw(view: SVGSelection, link: Link) {
|
||||
|
||||
const link_data = [[
|
||||
[link.source.x + link.source.width / 2., link.source.y + link.source.height / 2.],
|
||||
[link.target.x + link.target.width / 2., link.target.y + link.target.height / 2.]
|
||||
]];
|
||||
|
||||
const value_line = line();
|
||||
|
||||
let link_path = view.select<SVGPathElement>('path');
|
||||
link_path.classed('selected', (l: Link) => l.is_selected);
|
||||
|
||||
if (!link_path.node()) {
|
||||
link_path = view.append<SVGPathElement>('path');
|
||||
}
|
||||
|
||||
const link_path_data = link_path.data(link_data);
|
||||
|
||||
link_path_data
|
||||
.attr('d', value_line)
|
||||
.attr('stroke', '#000')
|
||||
.attr('stroke-width', '2');
|
||||
|
||||
private linktoEthernetLink(link: Link) {
|
||||
return new EthernetLinkPath(
|
||||
[link.source.x + link.source.width / 2., link.source.y + link.source.height / 2.],
|
||||
[link.target.x + link.target.width / 2., link.target.y + link.target.height / 2.]
|
||||
);
|
||||
}
|
||||
|
||||
public draw(view: SVGSelection) {
|
||||
|
||||
const link = view
|
||||
.selectAll<SVGPathElement, EthernetLinkPath>('path.ethernet_link')
|
||||
.data((link) => {
|
||||
if(link.link_type === 'ethernet') {
|
||||
return [this.linktoEthernetLink(link)];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
const link_enter = link.enter()
|
||||
.append<SVGPathElement>('path')
|
||||
.attr('class', 'ethernet_link');
|
||||
|
||||
link_enter
|
||||
.attr('stroke', '#000')
|
||||
.attr('stroke-width', '2');
|
||||
|
||||
const link_merge = link.merge(link_enter);
|
||||
|
||||
link_merge
|
||||
.attr('d', (ethernet) => {
|
||||
const line_generator = path();
|
||||
line_generator.moveTo(ethernet.source[0], ethernet.source[1]);
|
||||
line_generator.lineTo(ethernet.target[0], ethernet.target[1]);
|
||||
return line_generator.toString();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -5,63 +5,88 @@ import { SVGSelection } from "../../models/types";
|
||||
import { Link } from "../../../models/link";
|
||||
|
||||
|
||||
class SerialLinkPath {
|
||||
constructor(
|
||||
public source: [number, number],
|
||||
public source_angle: [number, number],
|
||||
public target_angle: [number, number],
|
||||
public target: [number, number]
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class SerialLinkWidget implements Widget {
|
||||
|
||||
public draw(view: SVGSelection, link: Link) {
|
||||
const source = {
|
||||
'x': link.source.x + link.source.width / 2,
|
||||
'y': link.source.y + link.source.height / 2
|
||||
};
|
||||
const target = {
|
||||
'x': link.target.x + link.target.width / 2,
|
||||
'y': link.target.y + link.target.height / 2
|
||||
};
|
||||
private linkToSerialLink(link: Link) {
|
||||
const source = {
|
||||
'x': link.source.x + link.source.width / 2,
|
||||
'y': link.source.y + link.source.height / 2
|
||||
};
|
||||
const target = {
|
||||
'x': link.target.x + link.target.width / 2,
|
||||
'y': link.target.y + link.target.height / 2
|
||||
};
|
||||
|
||||
const dx = target.x - source.x;
|
||||
const dy = target.y - source.y;
|
||||
const dx = target.x - source.x;
|
||||
const dy = target.y - source.y;
|
||||
|
||||
const vector_angle = Math.atan2(dy, dx);
|
||||
const rot_angle = -Math.PI / 4.0;
|
||||
const vect_rot = [
|
||||
Math.cos(vector_angle + rot_angle),
|
||||
Math.sin(vector_angle + rot_angle)
|
||||
];
|
||||
const vector_angle = Math.atan2(dy, dx);
|
||||
const rot_angle = -Math.PI / 4.0;
|
||||
const vect_rot = [
|
||||
Math.cos(vector_angle + rot_angle),
|
||||
Math.sin(vector_angle + rot_angle)
|
||||
];
|
||||
|
||||
const angle_source = [
|
||||
source.x + dx / 2.0 + 15 * vect_rot[0],
|
||||
source.y + dy / 2.0 + 15 * vect_rot[1]
|
||||
];
|
||||
const angle_source: [number, number] = [
|
||||
source.x + dx / 2.0 + 15 * vect_rot[0],
|
||||
source.y + dy / 2.0 + 15 * vect_rot[1]
|
||||
];
|
||||
|
||||
const angle_target = [
|
||||
target.x - dx / 2.0 - 15 * vect_rot[0],
|
||||
target.y - dy / 2.0 - 15 * vect_rot[1]
|
||||
];
|
||||
const angle_target: [number, number] = [
|
||||
target.x - dx / 2.0 - 15 * vect_rot[0],
|
||||
target.y - dy / 2.0 - 15 * vect_rot[1]
|
||||
];
|
||||
|
||||
const line_data = [
|
||||
[source.x, source.y],
|
||||
angle_source,
|
||||
angle_target,
|
||||
[target.x, target.y]
|
||||
];
|
||||
return new SerialLinkPath(
|
||||
[source.x, source.y],
|
||||
angle_source,
|
||||
angle_target,
|
||||
[target.x, target.y]
|
||||
);
|
||||
}
|
||||
|
||||
let link_path = view.select<SVGPathElement>('path');
|
||||
public draw(view: SVGSelection) {
|
||||
|
||||
if (!link_path.node()) {
|
||||
link_path = view.append<SVGPathElement>('path');
|
||||
}
|
||||
const link = view
|
||||
.selectAll<SVGPathElement, SerialLinkPath>('path.serial_link')
|
||||
.data((link) => {
|
||||
if(link.link_type === 'serial') {
|
||||
return [this.linkToSerialLink(link)];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
const line_generator = path();
|
||||
line_generator.moveTo(line_data[0][0], line_data[0][1]);
|
||||
line_generator.lineTo(line_data[1][0], line_data[1][1]);
|
||||
line_generator.lineTo(line_data[2][0], line_data[2][1]);
|
||||
line_generator.lineTo(line_data[3][0], line_data[3][1]);
|
||||
const link_enter = link.enter()
|
||||
.append<SVGPathElement>('path')
|
||||
.attr('class', 'serial_link');
|
||||
|
||||
link_path
|
||||
.attr('d', line_generator.toString())
|
||||
.attr('stroke', '#B22222')
|
||||
.attr('fill', 'none')
|
||||
.attr('stroke-width', '2');
|
||||
link_enter
|
||||
.attr('stroke', '#B22222')
|
||||
.attr('fill', 'none')
|
||||
.attr('stroke-width', '2');
|
||||
|
||||
const link_merge = link.merge(link_enter);
|
||||
|
||||
link_merge
|
||||
.attr('d', (serial) => {
|
||||
const line_generator = path();
|
||||
line_generator.moveTo(serial.source[0], serial.source[1]);
|
||||
line_generator.lineTo(serial.source_angle[0], serial.source_angle[1]);
|
||||
line_generator.lineTo(serial.target_angle[0], serial.target_angle[1]);
|
||||
line_generator.lineTo(serial.target[0], serial.target[1]);
|
||||
return line_generator.toString();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -232,7 +232,9 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
||||
this.mapChild.graphLayout.getSelectionTool().rectangleSelected)
|
||||
);
|
||||
|
||||
this.mapChild.graphLayout.getLinksWidget().getInterfaceLabelWidget().setEnabled(this.project.show_interface_labels);
|
||||
this.mapChild.graphLayout
|
||||
.getLinksWidget().getLinkWidget().getInterfaceLabelWidget().setEnabled(this.project.show_interface_labels);
|
||||
|
||||
this.mapChild.reload();
|
||||
}
|
||||
|
||||
@ -328,7 +330,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy {
|
||||
public toggleShowInterfaceLabels(enabled: boolean) {
|
||||
this.project.show_interface_labels = enabled;
|
||||
|
||||
this.mapChild.graphLayout.getLinksWidget().getInterfaceLabelWidget()
|
||||
this.mapChild.graphLayout.getLinksWidget().getLinkWidget().getInterfaceLabelWidget()
|
||||
.setEnabled(this.project.show_interface_labels);
|
||||
this.mapChild.reload();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user