Sample Files

Introducing sample Python plugin files.

Download all sample files here.

Sample 1: Walk figures

This plugin walks figures in the item right-clicked in the file list.

Download here. (plugin_walk_figures.py)

import os
import math
import tkinter
from decimal import Decimal

class WalkFigures(pynebv.Plugin):
    location = ['file_panel/item_menu']
    contact = 'ncs'
    label = 'Walk Figures'
    def centering_tkinter_root(self, event):
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        window_width = self.root.winfo_width()
        window_height = self.root.winfo_height()
        x = screen_width / 2 - window_width /2
        y = screen_height / 2 - window_height / 2
        self.root.geometry("+%d+%d" % (x, y))
    def quit_dialog(self):
        self.quit_now = True
        self.root.destroy()
    def show_next_dialog(self):
        self.quit_now = False
        self.root = tkinter.Tk()
        self.root.title(u"Figure Walk")
        self.root.geometry("200x50")
        self.root.attributes("-topmost", True or False)
        self.root.bind("<Visibility>", self.centering_tkinter_root)
        button = tkinter.Button(self.root, text="Next", command=lambda: self.root.destroy())
        button.pack()
        button = tkinter.Button(self.root, text="Quit", command=self.quit_dialog)
        button.pack()
        self.root.mainloop()
    def show_target_ascendants(self, item):
        print(f"aa {item.display_name[:15]}")
        if item.display_name[:15] == "Walk:Target*-- ":
            item.display = True
            descendants = item.descendants()
            if descendants:
                descendants.display = True
            return True
        has_visible = False
        children = item.descendants('', True)
        for child in children:
            if self.show_target_ascendants(child):
                item.display = True
                has_visible = True
        return has_visible
    def show_targets(self, targets):
        for target in targets:
            target.display_name = f"Walk:Target*-- {target.display_name}"
        list = pynebv.file.list()
        for top in list:
            if self.show_target_ascendants(top):
                top.display = True
        for target in targets:
            target.display_name = target.display_name[15:]
    def exec(self, context):
        if hasattr(pynebv, 'error_mode'):
            raise RuntimeError('Error mode is already set')
        all_items = pynebv.file.items()
        visibles = pynebv.EbvItemList([item for item in all_items if item.display])
        not_visibles = pynebv.EbvItemList([item for item in all_items if not item.display])
        targets = context['items']
        if visibles:
            visibles.display = False
        self.show_targets(targets)
        polygons = pynebv.figure.polygons()
        if visibles:
            visibles.display = True
        if not_visibles:
            not_visibles.display = False
        origin_area = pynebv.screen.get_area()
        for polygon in polygons:
            area = None
            for point in polygon.points:
                if area is None:
                    area = [point.x, point.y, point.x, point.y]
                if point.x < area[0]:
                    area[0] = point.x
                elif point.x > area[2]:
                    area[2] = point.x
                if point.y < area[1]:
                    area[1] = point.y
                elif point.y > area[3]:
                    area[3] = point.y
            margin = 10
            width = area[2] - area[0]
            height = area[3] - area[1]
            max_size = width if width > height else height
            if max_size > 0:
                margin = max_size
            area[0] -= margin
            area[1] -= margin
            area[2] += margin
            area[3] += margin
            # crafted to avoid exponential notation
            str_array = [f"{value:.10f}" for value in area]
            print(area)
            print(str_array)
            pynebv.screen.set_area(str_array)
            self.show_next_dialog()
            if self.quit_now:
                break
        pynebv.screen.set_area(origin_area)

Sample 2: Create figures and marks on the screen

This plugin allows drawing rectangles or arrows by right-dragging on the screen, and creating an X mark by right-clicking.

Download here. (plugin_create_figures.py)

import os
import math
def get_plugin_ebv():
    file_name = 'plugin.ebv'
    file_path = f"{pynebv.plugin.temp_dir}/{file_name}"
    # Create file if file_path does not exists
    if not os.path.exists(file_path):
        f = open(file_path, 'w')
        f.write("#EBV\nunit 1\n")
        f.close()
    return file_path

class BoxCreate(pynebv.Plugin):
    location = 'screen/context_menu'
    contact = 'ncs'
    label = 'Create Box'
    def __init__(self):
        if not hasattr(pynebv, 'fig_index'):
            pynebv.fig_index = 0
    def exec(self, context):
        if hasattr(pynebv, 'error_mode'):
            raise RuntimeError('Error mode is already set')
        print(context)
        if not 'area' in context:
            return
        x1 = context["area"][0]
        y1 = context["area"][1]
        x2 = context["area"][2]
        y2 = context["area"][3]
        # Add a box to file
        file_path = get_plugin_ebv()
        f = open(file_path, 'a')
        f.write("layno %d\n" % (pynebv.fig_index))
        pynebv.fig_index += 1
        f.write("rect %f,%f,%f,%f\n" % (x1, y1, x2 - x1, y2 - y1))
        f.close()
        # Read and display the file
        if len(pynebv.file.items(os.path.basename(file_path))) == 0:
            pynebv.file.open(file_path)
        pynebv.file.reload(True)

class ArrowCreate(pynebv.Plugin):
    location = 'screen/context_menu'
    contact = 'ncs'
    label = 'Create Arrow'
    def __init__(self):
        if not hasattr(pynebv, 'fig_index'):
            pynebv.fig_index = 0
    def exec(self, context):
        if hasattr(pynebv, 'error_mode'):
            raise RuntimeError('Error mode is already set')
        print(context)
        if not 'start_end' in context:
            return
        sx = context["start_end"][0]
        sy = context["start_end"][1]
        ex = context["start_end"][2]
        ey = context["start_end"][3]
        points = self.calculate_arrow_points(sx, sy, ex, ey)
        # Add an arrow to file
        file_path = get_plugin_ebv()
        f = open(file_path, 'a')
        f.write("layno %d\n" % (pynebv.fig_index))
        pynebv.fig_index += 1
        f.write("polygon\n")
        for x, y in points:
            f.write("xy %f,%f\n" % (x, y))
        f.write("end\n")
        f.close()
        # Read and display the file
        if len(pynebv.file.items(os.path.basename(file_path))) == 0:
            pynebv.file.open(file_path)
        pynebv.file.reload(True)
    def calculate_arrow_points(self, sx, sy, ex, ey):
        length = math.hypot(ex - sx, ey - sy)
        arrow_points = [
            (0, 0),
            (-0.2, 0.2),
            (-0.1, 0.2),
            (-0.1, 1),
            (0.1, 1),
            (0.1, 0.2),
            (0.2, 0.2),
        ]
        
        # Calculate arrow angle
        angle = math.atan2(ey - sy, ex - sx)
        cos = math.cos(angle)
        sin = math.sin(angle)

        # Calculation with arrow reference position set to (sx, sy)
        points = []
        for x, y in arrow_points:
            # Adjust size
            x *= length
            y *= length
            # Rotate and move
            points.append((
                ex + x * sin - y * cos,
                ey - x * cos - y * sin
            ))

        return points

class CreatePoint(pynebv.Plugin):
    location = 'screen/context_menu'
    contact = 'ncs'
    label = 'Create Point'
    def __init__(self):
        if not hasattr(pynebv, 'fig_index'):
            pynebv.fig_index = 0
    def exec(self, context):
        if hasattr(pynebv, 'error_mode'):
            raise RuntimeError('Error mode is already set')
        x = context['point'][0]
        y = context['point'][1] 
        # Add X to file
        file_path = get_plugin_ebv()
        f = open(file_path, 'a')
        f.write("layno %d\n" % (pynebv.fig_index))
        pynebv.fig_index += 1
        f.write("polygon\n")
        area = pynebv.screen.get_area()
        width = area[2] - area[0]
        height = area[3] - area[1]
        min_size = width if width < height else height
        unit = min_size / 100
        f.write("xy %f,%f\n" % (x, y + 1 * unit))
        f.write("xy %f,%f\n" % (x + 9 * unit, y + 11 * unit))
        f.write("xy %f,%f\n" % (x + 11 * unit, y + 9 * unit))
        f.write("xy %f,%f\n" % (x + 1 * unit, y ))
        f.write("xy %f,%f\n" % (x + 11 * unit, y - 9 * unit))
        f.write("xy %f,%f\n" % (x + 9 * unit, y - 11 * unit))
        f.write("xy %f,%f\n" % (x, y - 1 * unit))
        f.write("xy %f,%f\n" % (x - 9 * unit, y - 11 * unit))
        f.write("xy %f,%f\n" % (x - 11 * unit, y - 9 * unit))
        f.write("xy %f,%f\n" % (x - 1 * unit, y))
        f.write("xy %f,%f\n" % (x - 11 * unit, y + 9 * unit))
        f.write("xy %f,%f\n" % (x - 9 * unit, y + 11 * unit))
        f.write("end\n")
        f.close()
        pynebv.file.reload(True)
Last modified April 16, 2025