or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

database-operations.mdfile-io.mdhierarchical-design.mdindex.mdlayout-viewer.mdshape-operations.mdtransformations.mdverification.md

layout-viewer.mddocs/

0

# Layout Viewer and GUI Components

1

2

GUI components for layout visualization, user interaction, layer management, and display customization when running in GUI mode with Qt support.

3

4

## Capabilities

5

6

### Layout Viewing

7

8

```python { .api }

9

class LayoutView:

10

def __init__(self):

11

"""Create a new layout view widget."""

12

13

def load_layout(self, layout: Layout, add_cellview: bool = True) -> int:

14

"""

15

Load a layout into the view.

16

17

Parameters:

18

- layout: Layout object to display

19

- add_cellview: Whether to add a cellview for this layout

20

21

Returns:

22

int: Cellview index

23

"""

24

25

def create_layout(self, add_cellview: bool = True) -> int:

26

"""

27

Create a new empty layout in the view.

28

29

Returns:

30

int: Cellview index

31

"""

32

33

def active_cellview_index(self) -> int:

34

"""Get the index of the currently active cellview."""

35

36

def set_active_cellview_index(self, index: int) -> None:

37

"""Set the active cellview by index."""

38

39

def cellview(self, index: int) -> CellView:

40

"""Get cellview by index."""

41

42

def zoom_fit(self) -> None:

43

"""Zoom to fit all visible content."""

44

45

def zoom_box(self, bbox: DBox) -> None:

46

"""

47

Zoom to specific bounding box.

48

49

Parameters:

50

- bbox: Bounding box to zoom to

51

"""

52

53

def pan_center(self, center: DPoint) -> None:

54

"""

55

Pan view to center on specified point.

56

57

Parameters:

58

- center: Point to center the view on

59

"""

60

61

def set_config(self, config_name: str, config_value: str) -> None:

62

"""Set configuration parameter."""

63

64

def get_config(self, config_name: str) -> str:

65

"""Get configuration parameter value."""

66

67

class CellView:

68

def __init__(self, layout: Layout = None):

69

"""

70

Create a cellview for a layout.

71

72

Parameters:

73

- layout: Layout to view (optional)

74

"""

75

76

@property

77

def layout(self) -> Layout:

78

"""Get the associated layout."""

79

80

@property

81

def cell_index(self) -> int:

82

"""Get the current top cell index."""

83

84

def set_cell(self, cell_index: int) -> None:

85

"""

86

Set the top cell to display.

87

88

Parameters:

89

- cell_index: Index of cell to display

90

"""

91

92

@property

93

def name(self) -> str:

94

"""Get cellview name."""

95

96

def set_name(self, name: str) -> None:

97

"""Set cellview name."""

98

99

def is_valid(self) -> bool:

100

"""Check if cellview is valid."""

101

102

def close(self) -> None:

103

"""Close the cellview."""

104

```

105

106

### Layer Management and Display

107

108

```python { .api }

109

class LayerPropertiesNode:

110

def __init__(self):

111

"""Create a layer properties node."""

112

113

def source_layer_info(self) -> LayerInfo:

114

"""Get source layer information."""

115

116

def set_source_layer_info(self, layer_info: LayerInfo) -> None:

117

"""Set source layer information."""

118

119

@property

120

def name(self) -> str:

121

"""Get layer name."""

122

123

def set_name(self, name: str) -> None:

124

"""Set layer name."""

125

126

@property

127

def visible(self) -> bool:

128

"""Check if layer is visible."""

129

130

def set_visible(self, visible: bool) -> None:

131

"""Set layer visibility."""

132

133

@property

134

def transparent(self) -> bool:

135

"""Check if layer is transparent."""

136

137

def set_transparent(self, transparent: bool) -> None:

138

"""Set layer transparency."""

139

140

@property

141

def width(self) -> int:

142

"""Get line width for layer display."""

143

144

def set_width(self, width: int) -> None:

145

"""Set line width for layer display."""

146

147

def fill_color(self) -> int:

148

"""Get fill color (RGB)."""

149

150

def set_fill_color(self, color: int) -> None:

151

"""Set fill color (RGB value)."""

152

153

def frame_color(self) -> int:

154

"""Get frame/outline color."""

155

156

def set_frame_color(self, color: int) -> None:

157

"""Set frame/outline color."""

158

159

class LayerPropertiesList:

160

def __init__(self):

161

"""Create layer properties list."""

162

163

def append(self, properties: LayerPropertiesNode) -> None:

164

"""Add layer properties to list."""

165

166

def insert(self, index: int, properties: LayerPropertiesNode) -> None:

167

"""Insert layer properties at specific index."""

168

169

def erase(self, index: int) -> None:

170

"""Remove layer properties at index."""

171

172

def clear(self) -> None:

173

"""Clear all layer properties."""

174

175

def size(self) -> int:

176

"""Get number of layer properties."""

177

178

def __getitem__(self, index: int) -> LayerPropertiesNode:

179

"""Get layer properties by index."""

180

```

181

182

### Annotations and Markers

183

184

```python { .api }

185

class Annotation:

186

def __init__(self):

187

"""Create an annotation object."""

188

189

@property

190

def id(self) -> int:

191

"""Get annotation ID."""

192

193

def set_text(self, text: str) -> None:

194

"""

195

Set annotation text.

196

197

Parameters:

198

- text: Text to display

199

"""

200

201

def text(self) -> str:

202

"""Get annotation text."""

203

204

def set_position(self, position: DPoint) -> None:

205

"""Set annotation position."""

206

207

def position(self) -> DPoint:

208

"""Get annotation position."""

209

210

def set_color(self, color: int) -> None:

211

"""Set annotation color."""

212

213

def color(self) -> int:

214

"""Get annotation color."""

215

216

def set_outline_color(self, color: int) -> None:

217

"""Set outline color."""

218

219

def outline_color(self) -> int:

220

"""Get outline color."""

221

222

class Marker:

223

def __init__(self):

224

"""Create a marker for highlighting areas."""

225

226

def set_color(self, color: int) -> None:

227

"""Set marker color."""

228

229

def color(self) -> int:

230

"""Get marker color."""

231

232

def set_vertex_size(self, size: int) -> None:

233

"""Set vertex marker size."""

234

235

def vertex_size(self) -> int:

236

"""Get vertex marker size."""

237

238

def set_line_width(self, width: int) -> None:

239

"""Set line width for marker."""

240

241

def line_width(self) -> int:

242

"""Get marker line width."""

243

244

def set(self, shape) -> None:

245

"""

246

Set marker to highlight a shape.

247

248

Parameters:

249

- shape: Shape to highlight (Box, Polygon, etc.)

250

"""

251

```

252

253

### Display State Management

254

255

```python { .api }

256

class DisplayState:

257

def __init__(self):

258

"""Create display state manager."""

259

260

def visible_layers(self) -> list[int]:

261

"""Get list of visible layer indices."""

262

263

def set_layer_visible(self, layer: int, visible: bool) -> None:

264

"""

265

Set layer visibility.

266

267

Parameters:

268

- layer: Layer index

269

- visible: Visibility state

270

"""

271

272

def layer_visible(self, layer: int) -> bool:

273

"""Check if layer is visible."""

274

275

def set_color(self, layer: int, color: int) -> None:

276

"""Set layer display color."""

277

278

def color(self, layer: int) -> int:

279

"""Get layer display color."""

280

281

class ViewObject:

282

def __init__(self):

283

"""Generic view object for custom display elements."""

284

285

def bbox(self) -> DBox:

286

"""Get bounding box of the view object."""

287

288

def set_visible(self, visible: bool) -> None:

289

"""Set object visibility."""

290

291

def visible(self) -> bool:

292

"""Check if object is visible."""

293

```

294

295

### GUI Utility Functions

296

297

```python { .api }

298

def has_gui() -> bool:

299

"""

300

Check if GUI functionality is available.

301

302

Returns:

303

bool: True if GUI is available (Qt is loaded)

304

"""

305

306

def can_create_layoutview() -> bool:

307

"""

308

Check if LayoutView can be created.

309

310

Returns:

311

bool: True if LayoutView creation is supported

312

"""

313

314

class Application:

315

@staticmethod

316

def instance() -> Application:

317

"""Get the application instance."""

318

319

def main_window(self):

320

"""Get the main application window."""

321

322

def set_config(self, key: str, value: str) -> None:

323

"""Set application configuration value."""

324

325

def get_config(self, key: str) -> str:

326

"""Get application configuration value."""

327

328

def exec_() -> int:

329

"""Run the application event loop."""

330

```

331

332

## Usage Examples

333

334

### Basic Layout Viewing

335

336

```python

337

import klayout.db as db

338

import klayout.lay as lay

339

340

# Check if GUI is available

341

if not lay.has_gui():

342

print("GUI not available - running in headless mode")

343

exit()

344

345

# Create layout with some content

346

layout = db.Layout()

347

top_cell = layout.create_cell("TOP")

348

349

# Add some shapes

350

layer1 = layout.layer(db.LayerInfo(1, 0))

351

layer2 = layout.layer(db.LayerInfo(2, 0))

352

353

top_cell.shapes(layer1).insert(db.Box(0, 0, 1000, 1000))

354

top_cell.shapes(layer2).insert(db.Box(200, 200, 800, 800))

355

356

# Create and configure layout view

357

if lay.can_create_layoutview():

358

view = lay.LayoutView()

359

360

# Load layout into view

361

cellview_index = view.load_layout(layout)

362

363

# Set the top cell

364

cellview = view.cellview(cellview_index)

365

cellview.set_cell(top_cell.cell_index)

366

367

# Zoom to fit content

368

view.zoom_fit()

369

370

print("Layout loaded in viewer")

371

```

372

373

### Layer Display Configuration

374

375

```python

376

import klayout.db as db

377

import klayout.lay as lay

378

379

layout = db.Layout()

380

layout.read("complex_design.gds")

381

382

if lay.can_create_layoutview():

383

view = lay.LayoutView()

384

cellview_index = view.load_layout(layout)

385

386

# Configure layer display properties

387

layer_props_list = lay.LayerPropertiesList()

388

389

# Metal 1 - Blue fill, solid

390

metal1_props = lay.LayerPropertiesNode()

391

metal1_props.set_source_layer_info(db.LayerInfo(1, 0))

392

metal1_props.set_name("METAL1")

393

metal1_props.set_fill_color(0x0000FF) # Blue

394

metal1_props.set_frame_color(0x000080) # Dark blue outline

395

metal1_props.set_visible(True)

396

metal1_props.set_transparent(False)

397

metal1_props.set_width(1)

398

layer_props_list.append(metal1_props)

399

400

# Metal 2 - Red fill, transparent

401

metal2_props = lay.LayerPropertiesNode()

402

metal2_props.set_source_layer_info(db.LayerInfo(2, 0))

403

metal2_props.set_name("METAL2")

404

metal2_props.set_fill_color(0xFF0000) # Red

405

metal2_props.set_frame_color(0x800000) # Dark red outline

406

metal2_props.set_visible(True)

407

metal2_props.set_transparent(True)

408

metal2_props.set_width(2)

409

layer_props_list.append(metal2_props)

410

411

# Via - Green outline only

412

via_props = lay.LayerPropertiesNode()

413

via_props.set_source_layer_info(db.LayerInfo(3, 0))

414

via_props.set_name("VIA")

415

via_props.set_fill_color(0x00FF00) # Green (not used for outline-only)

416

via_props.set_frame_color(0x00FF00) # Green outline

417

via_props.set_visible(True)

418

via_props.set_transparent(True) # Transparent fill

419

via_props.set_width(3)

420

layer_props_list.append(via_props)

421

422

print(f"Configured {layer_props_list.size()} layer display properties")

423

```

424

425

### Adding Annotations and Markers

426

427

```python

428

import klayout.db as db

429

import klayout.lay as lay

430

431

layout = db.Layout()

432

layout.read("design_with_issues.gds")

433

434

if lay.can_create_layoutview():

435

view = lay.LayoutView()

436

cellview_index = view.load_layout(layout)

437

438

# Add annotations for important features

439

annotation1 = lay.Annotation()

440

annotation1.set_text("Critical timing path")

441

annotation1.set_position(db.DPoint(100.5, 200.5))

442

annotation1.set_color(0xFF0000) # Red text

443

annotation1.set_outline_color(0x800000) # Dark red outline

444

445

annotation2 = lay.Annotation()

446

annotation2.set_text("Power distribution node")

447

annotation2.set_position(db.DPoint(500.0, 300.0))

448

annotation2.set_color(0x0000FF) # Blue text

449

450

# Create markers for highlighting specific areas

451

marker1 = lay.Marker()

452

marker1.set_color(0xFFFF00) # Yellow

453

marker1.set_line_width(3)

454

marker1.set_vertex_size(10)

455

456

# Highlight a specific polygon (e.g., design rule violation)

457

violation_area = db.Box(150, 150, 200, 200)

458

marker1.set(violation_area)

459

460

marker2 = lay.Marker()

461

marker2.set_color(0xFF00FF) # Magenta

462

marker2.set_line_width(2)

463

464

# Highlight another area

465

critical_path = db.Path([db.Point(0, 100), db.Point(500, 100),

466

db.Point(500, 400)], 10)

467

marker2.set(critical_path.polygon())

468

469

print("Added annotations and markers to highlight design features")

470

```

471

472

### Interactive View Control

473

474

```python

475

import klayout.db as db

476

import klayout.lay as lay

477

478

def setup_interactive_view(layout_file: str):

479

"""Set up an interactive layout view with custom controls."""

480

481

if not lay.has_gui():

482

print("GUI not available")

483

return None

484

485

layout = db.Layout()

486

layout.read(layout_file)

487

488

view = lay.LayoutView()

489

cellview_index = view.load_layout(layout)

490

491

# Configure view settings

492

view.set_config("grid-visible", "true")

493

view.set_config("grid-color", "#808080")

494

view.set_config("background-color", "#000000") # Black background

495

view.set_config("text-visible", "true")

496

497

# Set up zoom and pan shortcuts

498

bbox = layout.top_cell().bbox_per_layer(layout.layer(db.LayerInfo(1, 0)))

499

if not bbox.empty():

500

# Convert to double precision for view

501

dbbox = db.DBox(bbox.left, bbox.bottom, bbox.right, bbox.top)

502

view.zoom_box(dbbox)

503

504

# Pan to interesting area

505

center = db.DPoint(500.0, 500.0) # Adjust based on your design

506

view.pan_center(center)

507

508

return view

509

510

def create_custom_layer_setup(view: lay.LayoutView, layout: db.Layout):

511

"""Create a custom layer display setup."""

512

513

# Define layer colors and properties

514

layer_configs = [

515

{"layer": (1, 0), "name": "NWELL", "color": 0x80FF80, "transparent": True},

516

{"layer": (2, 0), "name": "ACTIVE", "color": 0x80FFFF, "transparent": False},

517

{"layer": (3, 0), "name": "POLY", "color": 0xFF8080, "transparent": False},

518

{"layer": (4, 0), "name": "CONTACT", "color": 0x8080FF, "transparent": False},

519

{"layer": (5, 0), "name": "METAL1", "color": 0x0080FF, "transparent": False},

520

{"layer": (6, 0), "name": "VIA1", "color": 0xFF0080, "transparent": True},

521

{"layer": (7, 0), "name": "METAL2", "color": 0xFF8000, "transparent": False},

522

]

523

524

layer_props_list = lay.LayerPropertiesList()

525

526

for config in layer_configs:

527

props = lay.LayerPropertiesNode()

528

layer_info = db.LayerInfo(config["layer"][0], config["layer"][1])

529

530

props.set_source_layer_info(layer_info)

531

props.set_name(config["name"])

532

props.set_fill_color(config["color"])

533

props.set_frame_color(config["color"] & 0x808080) # Darker frame

534

props.set_visible(True)

535

props.set_transparent(config["transparent"])

536

props.set_width(1)

537

538

layer_props_list.append(props)

539

540

print(f"Created custom layer setup with {len(layer_configs)} layers")

541

return layer_props_list

542

543

# Example usage

544

if __name__ == "__main__":

545

view = setup_interactive_view("my_design.gds")

546

if view:

547

print("Interactive view created successfully")

548

549

# If running in a Qt application context

550

if lay.Application.instance():

551

app = lay.Application.instance()

552

app.exec_() # Start event loop

553

```

554

555

### Programmatic View Navigation

556

557

```python

558

import klayout.db as db

559

import klayout.lay as lay

560

import time

561

562

def tour_layout(layout_file: str):

563

"""Create an automated tour of a layout."""

564

565

layout = db.Layout()

566

layout.read(layout_file)

567

568

if not lay.can_create_layoutview():

569

print("Cannot create layout view")

570

return

571

572

view = lay.LayoutView()

573

cellview_index = view.load_layout(layout)

574

575

# Find interesting areas to visit

576

tour_points = []

577

578

# Collect bounding boxes of all cells

579

for cell in layout.each_cell():

580

if not cell.is_empty():

581

bbox = cell.bbox()

582

if not bbox.empty():

583

center = db.DPoint((bbox.left + bbox.right) / 2.0,

584

(bbox.bottom + bbox.top) / 2.0)

585

# Create zoom box around center

586

zoom_size = max(bbox.width(), bbox.height()) * 1.2

587

zoom_box = db.DBox(center.x - zoom_size/2, center.y - zoom_size/2,

588

center.x + zoom_size/2, center.y + zoom_size/2)

589

tour_points.append((cell.name, center, zoom_box))

590

591

# Tour through the points

592

for cell_name, center, zoom_box in tour_points[:10]: # Limit to first 10

593

print(f"Visiting cell: {cell_name}")

594

595

# Pan to center

596

view.pan_center(center)

597

time.sleep(1) # Wait 1 second

598

599

# Zoom to show the cell

600

view.zoom_box(zoom_box)

601

time.sleep(2) # Wait 2 seconds

602

603

# Return to fit view

604

view.zoom_fit()

605

print("Tour completed")

606

607

# Example: Analyze what's visible in current view

608

def analyze_visible_content(view: lay.LayoutView):

609

"""Analyze the content visible in the current view."""

610

611

# Get current view bounds (this would require view state access)

612

# This is a simplified example

613

614

cellview = view.cellview(view.active_cellview_index())

615

if not cellview.is_valid():

616

return

617

618

layout = cellview.layout

619

top_cell = layout.cell(cellview.cell_index)

620

621

print(f"Analyzing cell: {top_cell.name}")

622

print(f"Cell has {top_cell.child_cells()} child cells")

623

624

# Count shapes per layer

625

layer_counts = {}

626

for layer_index in range(layout.layers()):

627

if layout.is_valid_layer(layer_index):

628

layer_info = layout.get_info(layer_index)

629

shape_count = top_cell.shapes(layer_index).size()

630

if shape_count > 0:

631

layer_counts[f"{layer_info.layer}/{layer_info.datatype}"] = shape_count

632

633

print("Shapes per layer:")

634

for layer, count in sorted(layer_counts.items()):

635

print(f" {layer}: {count} shapes")

636

637

if __name__ == "__main__":

638

tour_layout("complex_design.gds")

639

```