Source code for jdxi_editor.ui.image.instrument

"""
Module: JD-Xi Instrument Display Renderer
=========================================

This module provides functions to generate a visual representation of the Roland JD-Xi synthesizer
interface using PySide6. It renders key UI elements, including the display, sequencer section,
and keyboard.

Functions
---------
- :func:`draw_instrument_pixmap`
- :func:`draw_display`
- :func:`draw_sequencer`

Dependencies
------------
- PySide6.QtCore (Qt)
- PySide6.QtGui (QFont, QPixmap, QImage, QPainter, QPen, QColor)
- jdxi_editor.ui.windows.jdxi.dimensions (JDXI_WIDTH, JDXI_HEIGHT, etc.)

Usage
-----
These functions generate and display a graphical representation of the JD-Xi’s controls,
which can be integrated into a larger PySide6-based UI.
"""

import platform

from PySide6.QtCore import Qt
from PySide6.QtGui import (
    QColor,
    QImage,
    QLinearGradient,
    QPainter,
    QPen,
    QPixmap,
)

from jdxi_editor.ui.windows.jdxi.dimensions import JDXiDimensions


[docs] def draw_instrument_pixmap() -> QPixmap: """ Create a visual representation of the JD-Xi instrument panel. :return: QPixmap representation of the JD-Xi interface. :rtype: QPixmap """ # Create address black background image with correct aspect ratio jdxi_width = JDXiDimensions.WIDTH jdxi_height = JDXiDimensions.HEIGHT jdxi_image = QImage(jdxi_width, jdxi_height, QImage.Format_RGB32) # type: ignore[attr-defined] jdxi_image.fill(Qt.black) # type: ignore[attr-defined] pixmap = QPixmap.fromImage(jdxi_image) painter = QPainter(pixmap) painter.setRenderHint(QPainter.Antialiasing) # type: ignore[attr-defined] # draw the background gradient = QLinearGradient(0, 0, 0, jdxi_height) gradient.setColorAt(0, QColor(30, 30, 30)) gradient.setColorAt(1, QColor(0, 0, 0)) painter.setBrush(gradient) painter.fillRect(0, 0, jdxi_width, jdxi_height, gradient) # Draw a black rectangle 1 px wide at the margin for style, with no fill pen = QPen(Qt.black, 1) # type: ignore[attr-defined] painter.setPen(pen) painter.setBrush(Qt.NoBrush) # type: ignore[attr-defined] painter.drawRect(10, 50, jdxi_width - 20, jdxi_height - 100) draw_sequencer(painter) painter.end() return pixmap
[docs] def draw_sequencer(painter: QPainter) -> None: """ Draw the sequencer section of the JD-Xi interface. :param painter: QPainter instance used for drawing. :type painter: QPainter :return: None :rtype: None """ if platform.system() == "Windows": # windows has a menu across the top sequencer_y = ( JDXiDimensions.SEQUENCER_Y_WINDOWS ) # Keep same distance above keyboard else: sequencer_y = ( JDXiDimensions.SEQUENCER_Y_NON_WINDOWS ) # Keep same distance above keyboard sequencer_width = JDXiDimensions.SEQUENCER_WIDTH # Use roughly half keyboard width sequencer_x = JDXiDimensions.SEQUENCER_X # Align with right edge of keyboard # Calculate step dimensions step_count = JDXiDimensions.SEQUENCER_STEPS step_size = JDXiDimensions.SEQUENCER_STEP_SIZE # Smaller square size total_spacing = sequencer_width - (step_count * step_size) step_spacing = total_spacing / (step_count - 1) # Draw horizontal measure lines (white) painter.setPen(QPen(Qt.white, 1)) # type: ignore[attr-defined] line_y = sequencer_y - 10 # Move lines above buttons measure_width = (step_size + step_spacing) * 4 # Width of 4 steps line_spacing = step_size / 3 # Space between lines time_signatures = [4, 2, 4] # Time signatures for each beat grid for time_signature_number, beats in enumerate(time_signatures): for beat_number in range(beats): if time_signature_number == 0: scaled_measure_width = measure_width * 0.75 elif beats == 2: scaled_measure_width = measure_width * 2.0 else: scaled_measure_width = measure_width x1 = int(sequencer_x + (beat_number * scaled_measure_width)) x2 = int( (x1 + scaled_measure_width) - step_spacing ) # Stop before next measure y = line_y - 25 + time_signature_number * line_spacing painter.drawLine( int(x1), int(y), int(x2), int(y), )