From 43147cacdb9f582455af1adbadbae062cc210267 Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Fri, 24 Jan 2025 14:27:54 -0800 Subject: [PATCH 01/22] ENH: Add a SmarAct detailed screen to customize to SmarAct signals --- pcdsdevices/ui/SmarAct.detailed.ui | 4705 ++++++++++++++++++++++++++++ 1 file changed, 4705 insertions(+) create mode 100644 pcdsdevices/ui/SmarAct.detailed.ui diff --git a/pcdsdevices/ui/SmarAct.detailed.ui b/pcdsdevices/ui/SmarAct.detailed.ui new file mode 100644 index 00000000000..b1611f707b3 --- /dev/null +++ b/pcdsdevices/ui/SmarAct.detailed.ui @@ -0,0 +1,4705 @@ + + + Form + + + + 0 + 0 + 543 + 577 + + + + + 0 + 0 + + + + + 543 + 577 + + + + Form + + + + 0 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + + 0 + 0 + + + + + + + + + + + QLayout::SetMinimumSize + + + + + + 0 + 0 + + + + + + + false + + + true + + + + + + ca://${prefix}:STATE_RBV.B5 + + + true + + + false + + + false + + + 1 + + + 0 + + + + Has Encoder + + + + + + + + + 0 + 0 + + + + + + + false + + + true + + + + + + ca://${prefix}:STATE_RBV.B6 + + + true + + + false + + + false + + + 1 + + + 0 + + + + Calibrated + + + + + + + + + 0 + 0 + + + + + + + false + + + true + + + + + + ca://${prefix}:STATE_RBV.B7 + + + true + + + false + + + false + + + 1 + + + 0 + + + + Homed + + + + + + + + + + + 0 + 0 + + + + + 0 + 200 + + + + + 16777215 + 150 + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 15 + + + + + + + + + 0 + 0 + + + + + 0 + 200 + + + + 0 + + + + + 0 + 0 + + + + Open-loop + + + + 2 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + Qt::LeftToRight + + + QFrame::StyledPanel + + + QFrame::Sunken + + + 1 + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustIgnored + + + true + + + Qt::AlignCenter + + + + + 0 + 0 + 509 + 300 + + + + + 0 + 0 + + + + + 0 + 300 + + + + + + + + + + 0 + 0 + + + + Jog + + + Qt::AlignCenter + + + + + + + QLayout::SetDefaultConstraint + + + + + Forward + + + + + + + + 0 + 0 + + + + + 100 + 25 + + + + + + + + + + + 25 + 25 + + + + false + + + false + + + + + + false + + + ca://${prefix}:STEP_FORWARD + + + caret-square-right + + + + 90 + 90 + 90 + + + + false + + + + + + + + + false + + + Are you sure you want to proceed? + + + 1 + + + None + + + false + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 5 + 25 + + + + + + + + + 0 + 0 + + + + + 100 + 25 + + + + + + + + + + + 25 + 25 + + + + false + + + false + + + + + + false + + + ca://${prefix}:STEP_REVERSE.PROC + + + caret-square-left + + + + 90 + 90 + 90 + + + + false + + + + + + + + + false + + + Are you sure you want to proceed? + + + 1 + + + None + + + false + + + false + + + + + + + Reverse + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + + + QLayout::SetDefaultConstraint + + + 6 + + + + + Scan Voltage + + + Qt::AlignCenter + + + + + + + + + + 0 + 0 + + + + + 55 + 31 + + + + + + + + 25 + 25 + + + + false + + + false + + + + + + false + + + ca://${prefix}:CLEAR_COUNT.PROC + + + eraser + + + + 255 + 85 + 255 + + + + false + + + + + + + + + true + + + Are you sure you want to clear the total step count? + + + 1 + + + None + + + false + + + false + + + + + + + Clear Count + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}:STEP_VOLTAGE + + + + + + + Step Frequency + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + ca://${prefix}:STEP_FREQ + + + false + + + + + + + + 0 + 0 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + ca://${prefix}:STEP_COUNT + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 5 + 20 + + + + + + + + Step Size + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}:SCAN_MOVE + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + 16777215 + 1677215 + + + + Total Step Count + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}:STEP_COUNT + + + + + + + Step Voltage + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}:STEP_FREQ + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + ca://${prefix}:STEP_VOLTAGE + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + ca://${prefix}:TOTAL_STEP_COUNT + + + false + + + + + + + + 0 + 0 + + + + + 50 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + Scan Voltage as a % expressed as Uint16 (i.e. 0-65535) + + + ca://${prefix}:SCAN_POS + + + false + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 5 + + + + + + + + + + + + + + 0 + 0 + + + + Closed-loop + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + true + + + Qt::AlignCenter + + + + + 0 + 0 + 527 + 400 + + + + + 0 + 0 + + + + + 0 + 400 + + + + + + + + + + 0 + 25 + + + + Home + + + Qt::AlignCenter + + + + + + + QLayout::SetNoConstraint + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 5 + 25 + + + + + + + + + 0 + 0 + + + + + 75 + 25 + + + + + + + + 25 + 25 + + + + false + + + false + + + + + + false + + + ca://${prefix}.HOMR + + + fast-backward + + + false + + + + + + + + + true + + + Are you sure you want to proceed? This will move your stage until it reaches the next reference position + + + 1 + + + None + + + false + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Reverse + + + + + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Forward + + + + + + + + 0 + 0 + + + + + 75 + 25 + + + + + + + + 25 + 25 + + + + false + + + false + + + + + + false + + + ca://${prefix}.HOMR + + + fast-forward + + + false + + + + + + + + + true + + + Are you sure you want to proceed? This will move your stage until it reaches the next reference position + + + 1 + + + None + + + false + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + + + + + + 0 + 25 + + + + Acceleration + + + Qt::AlignCenter + + + + + + + + 0 + 25 + + + + Velocity + + + Qt::AlignCenter + + + + + + + + 0 + 25 + + + + Max Velocity + + + Qt::AlignCenter + + + + + + + + 0 + 25 + + + + Current Position + + + Qt::AlignCenter + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}.VELO + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}.HVEL + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + true + + + true + + + false + + + true + + + Velocity for closed loop moves + + + ca://${prefix}.VELO + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Closed Loop Frequency Max + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + Maximum closed loop frequency in Hz. Sets an upper threshold on the velocity of a stage. Setting > 5 kHz can affect piezo health + + + ca://${prefix}:MAX_CLF_RBV + + + false + + + + + + + + 0 + 25 + + + + Home Velocity + + + Qt::AlignCenter + + + + + + + + 0 + 25 + + + + Base Velocity + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + true + + + true + + + false + + + true + + + Base (minimum) velocity + + + ca://${prefix}.VBAS + + + false + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}.VMAX + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + true + + + true + + + false + + + true + + + + + + ca://${prefix}.RBV + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + true + + + true + + + false + + + true + + + Velocity of Homing sequence + + + ca://${prefix}.HVEL + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + Acceleration of the closed loop move + + + ca://${prefix}.ACCL + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 5 + 20 + + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}.VBAS + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}.VAL + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}:MAX_CLF + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}.ACCL + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + true + + + true + + + false + + + true + + + Maximum velocity + + + ca://${prefix}.VMAX + + + false + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + 0 + 0 + + + + Diagnostics + + + + 2 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + true + + + + + 0 + 0 + 655 + 250 + + + + + 0 + 0 + + + + + 0 + 250 + + + + + + + + 0 + 0 + + + + + 150 + 200 + + + + true + + + + + 0 + 0 + 150 + 600 + + + + + 0 + 0 + + + + + 150 + 600 + + + + + + + + 0 + 0 + + + + + 125 + 0 + + + + + + + false + + + true + + + + + + ca://${prefix}:STATE_RBV + + + true + + + false + + + true + + + 21 + + + 0 + + + + Actively Moving + Closed Loop Active + Calibrating + Referencing + Move Delayed + Sensor Present + Is Calibrated + Is Referenced + End Stop Reached + Range Limit Reached + Following Limit Reached + Movement Failed + Is Streaming + Positioner OVLD + Over temperature + Reference Mark + Is Phased + Positioner Fault + Amplifier Enabled + In Position + Brake Enabled + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 2 + + + + + + 0 + 0 + + + + Motor Load + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + Avg CLF measured in 2 s interval + + + ca://${prefix}:DIAG_CLF_AVG + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Timebase for measuring CLF diagnostics + + + DCLF Timebase + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + thermal load as a % + + + ca://${prefix}:MOTOR_LOAD + + + false + + + + + + + + 0 + 0 + + + + Channel Temp. + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + Max CLF measured in 2 s interval + + + DCLF Max + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + Max CLF measured in 2 s interval + + + ca://${prefix}:DIAG_CLF_MAX + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + Most recent channel error + + + ca://${prefix}:CHAN_ERR + + + false + + + PyDMLabel::Hex + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + Timebase for measuring CLF diagnostics + + + ca://${prefix}:DIAG_CLF_TIMEBASE_RBV + + + false + + + + + + + + 0 + 0 + + + + Module Temp. + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + true + + + true + + + false + + + true + + + + + + ca://${prefix}:CHANTEMP + + + false + + + + + + + + 0 + 0 + + + + Channel Error + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Avg CLF measured in 2 s interval + + + DCLF Avg + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + true + + + true + + + false + + + true + + + + + + ca://${prefix}:MODTEMP + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + Timebase for measuring CLF diagnostics + + + false + + + ca://${prefix}:DIAG_CLF_TIMEBASE + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Celsius + + + + + + + Celsius + + + + + + + % + + + + + + + + + + + + + + + 0 + 0 + + + + Configuration + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + true + + + + + 0 + 0 + 509 + 478 + + + + + 0 + 0 + + + + + 0 + 350 + + + + + 9 + + + 9 + + + 9 + + + 9 + + + + + 6 + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}:PTYPE + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + ca://${prefix}.EGU + + + false + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}:SET_DRMIN + + + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 80 + 20 + + + + + + + + + 0 + 0 + + + + + 55 + 25 + + + + + 9 + + + + + + + false + + + true + + + + + + ca://${prefix}:NEED_CALIB + + + + 255 + 255 + 0 + + + + Qt::Horizontal + + + true + + + false + + + true + + + 1 + + + 0 + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 90 + 20 + + + + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + sig://${name}_motor_egu + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 13 + 20 + + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + Invert the logical scale. Must home after changing to take effect. Non-volatile. + + + ca://${prefix}:LSCI_RBV + + + false + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}:SET_LSCO + + + + + + + + 0 + 25 + + + + High Limit + + + Qt::AlignCenter + + + + + + + + 0 + 25 + + + + PTYPE + + + Qt::AlignCenter + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + TTZV position threshold in encoder ticks (pm or ndeg). Range: 0 - 1E7 + + + false + + + ca://${prefix}:TTZ_THRESHOLD_RBV + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + Closed-loop ONLY: Whether TTZV is enabled or not + + + ca://${prefix}:TTZV_MODE_RBV + + + false + + + + + + + + 0 + 25 + + + + Needs Calibration + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + Current TTZV position threshold in encoder ticks (pm or ndeg) + + + ca://${prefix}:TTZ_THRESHOLD_RBV + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Default Range Max + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + Sets the distance code inversion flag. Non-volatile. + + + ca://${prefix}:DCIN_RBV + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Sets the distance code inversion flag. Non-volatile. + + + Distance Code Inversion + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}.LLM + + + + + + + + 0 + 25 + + + + Invert the logical scale. Must home after changing to take effect. Non-volatile. + + + Logical Scale Inversion + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + true + + + true + + + false + + + true + + + Shift the logical scale in mm. Non-volatile. + + + ca://${prefix}:LSCO + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + true + + + true + + + false + + + true + + + Default minimum range for logical scale. Non-volatile. + + + ca://${prefix}:DRMIN + + + false + + + + + + + + 0 + 25 + + + + + 10 + 75 + true + + + + + + + Calibrate + + + + 25 + 25 + + + + false + + + false + + + + + + false + + + ca://${prefix}:DO_CALIB.PROC + + + sync + + + + 0 + 85 + 255 + + + + false + + + + + + + + + false + + + Are you sure you want to proceed? + + + 1 + + + None + + + false + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + ca://${prefix}:PTYPE_RBV + + + false + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}.HLM + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + sig://${name}_description + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Default maximum range for logical scale. Non-volatile. + + + Qt::AlignCenter + + + 0 + + + true + + + true + + + false + + + true + + + Default maximum range for logical scale. Non-volatile. + + + ca://${prefix}:DRMAX + + + false + + + + + + + + 0 + 25 + + + + Low Limit + + + Qt::AlignCenter + + + + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + false + + + ca://${prefix}:SET_DRMAX + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + ca://${prefix}.DESC + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + ca://${prefix}.HLM + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Shift the logical scale in mm. Non-volatile. + + + false + + + Logical Scale Offset + + + false + + + Qt::AlignCenter + + + true + + + 0 + + + + + + + + 0 + 25 + + + + Description + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Default minimum range for logical scale. Non-volatile. + + + Default Range Min + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + + + + ca://${prefix}.LLM + + + false + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Target to Zero Voltage + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + TTZV Threshold + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 25 + + + + EGU + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 100 + 25 + + + + + + + false + + + true + + + Closed-loop ONLY: toggle TTZV state + + + false + + + ca://${prefix}:TTZV_MODE + + + + + + + + 0 + 0 + + + + + 100 + 25 + + + + + + + false + + + true + + + + + + false + + + ca://${prefix}:SET_LSCI + + + + + + + + 0 + 0 + + + + + 100 + 25 + + + + + + + false + + + true + + + + + + false + + + ca://${prefix}:SET_DCIN + + + + + + + + + Qt::Vertical + + + + 453 + 37 + + + + + + + + + + + + + + + + + PyDMLabel + QLabel +
pydm.widgets.label
+
+ + PyDMByteIndicator + QWidget +
pydm.widgets.byte
+
+ + PyDMEnumComboBox + QComboBox +
pydm.widgets.enum_combo_box
+
+ + PyDMLineEdit + QLineEdit +
pydm.widgets.line_edit
+
+ + PyDMPushButton + QPushButton +
pydm.widgets.pushbutton
+
+ + TyphosDisplayTitle + QFrame +
typhos.display
+
+ + TyphosPositionerWidget + QWidget +
typhos.positioner
+
+
+ + +
From 6fbb85421bac25cbfd1bbec7293c721f6112615c Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Fri, 24 Jan 2025 14:28:27 -0800 Subject: [PATCH 02/22] ENH: Add a SmarActTipTilt embedded screen for simple open loop control --- pcdsdevices/ui/SmarActTipTilt.embedded.ui | 580 ++++++++++++++++++++++ 1 file changed, 580 insertions(+) create mode 100644 pcdsdevices/ui/SmarActTipTilt.embedded.ui diff --git a/pcdsdevices/ui/SmarActTipTilt.embedded.ui b/pcdsdevices/ui/SmarActTipTilt.embedded.ui new file mode 100644 index 00000000000..72b73a712ca --- /dev/null +++ b/pcdsdevices/ui/SmarActTipTilt.embedded.ui @@ -0,0 +1,580 @@ + + + Form + + + + 0 + 0 + 320 + 323 + + + + + 0 + 0 + + + + Form + + + + QLayout::SetMinimumSize + + + + + + 0 + 0 + + + + + + + + + + + + + Step Count + + + + + + + + 0 + 0 + + + + Tilt + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Tip + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + + + + + + + + 0 + 0 + + + + + + + + + + 0 + 0 + + + + + 35 + 35 + + + + + + + + 30 + 30 + + + + false + + + false + + + + + + false + + + + + + caret-right + + + + 0 + 0 + 0 + + + + false + + + + + + + + + false + + + Are you sure you want to proceed? + + + 1 + + + None + + + false + + + false + + + + + + + + 0 + 0 + + + + + 30 + 30 + + + + + 12 + 75 + true + + + + Step + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 35 + 35 + + + + + + + + 30 + 30 + + + + false + + + false + + + + + + false + + + + + + caret-left + + + + 0 + 0 + 0 + + + + false + + + + + + + + + false + + + Are you sure you want to proceed? + + + 1 + + + None + + + false + + + false + + + + + + + + 0 + 0 + + + + + 35 + 35 + + + + + + + + 30 + 30 + + + + false + + + false + + + + + + false + + + + + + caret-down + + + + 0 + 0 + 0 + + + + false + + + + + + + + + false + + + Are you sure you want to proceed? + + + 1 + + + None + + + false + + + false + + + + + + + + 0 + 0 + + + + + 35 + 35 + + + + + + + + 30 + 30 + + + + false + + + false + + + + + + false + + + + + + caret-up + + + + 0 + 0 + 0 + + + + false + + + + + + + + + false + + + Are you sure you want to proceed? + + + 1 + + + None + + + false + + + false + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + + + + false + + + false + + + + + + false + + + + + + SP_ToolBarHorizontalExtensionButton + + + false + + + + + + + + + false + + + Are you sure you want to proceed? + + + None + + + None + + + false + + + false + + + + + + + + PyDMLabel + QLabel +
pydm.widgets.label
+
+ + PyDMPushButton + QPushButton +
pydm.widgets.pushbutton
+
+ + TyphosDisplayTitle + QFrame +
typhos.display
+
+
+ + +
From a27dff43d2c5a96e2be11dfe5f92aebaa1de62de Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Fri, 24 Jan 2025 15:06:07 -0800 Subject: [PATCH 03/22] ENH: add hybrid pyqt script for SmarActTipTilt embedded screen to mimick behavior from TyphosPositionerRow --- pcdsdevices/ui/SmarActTipTilt.embedded.py | 298 ++++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 pcdsdevices/ui/SmarActTipTilt.embedded.py diff --git a/pcdsdevices/ui/SmarActTipTilt.embedded.py b/pcdsdevices/ui/SmarActTipTilt.embedded.py new file mode 100644 index 00000000000..efded139de4 --- /dev/null +++ b/pcdsdevices/ui/SmarActTipTilt.embedded.py @@ -0,0 +1,298 @@ +from __future__ import annotations + +import logging +import typing +from os import path +from typing import Optional + +import ophyd +import pydm +from pydm import Display +from qtpy import QtCore, QtGui, QtWidgets, uic +from typhos import utils +from typhos.panel import SignalOrder, TyphosSignalPanel + +logger = logging.getLogger(__name__) + + +class _SmarActTipTiltEmbeddedUI(QtWidgets.QWidget): + """Annotations helper for SmarAct.embedded.ui. Do not instantiate.""" + dpad_label: QtWidgets.QLabel + tip_forward: pydm.widgets.pushbutton.PyDMPushButton + tip_reverse: pydm.widgets.pushbutton.PyDMPushButton + tip_step_count: pydm.widgets.label.PyDMLabel + tilt_forward: pydm.widgets.pushbutton.PyDMPushButton + tilt_reverse: pydm.widgets.pushbutton.PyDMPushButton + tilt_step_count: pydm.widgets.label.PyDMLabel + settings_button: pydm.widgets.pushbutton.PyDMPushButton + + +class SmarActTipTiltWidget(Display, utils.TyphosBase): + """Custom widget for controlling a tip-tilt with d-pad buttons""" + ui: _SmarActTipTiltEmbeddedUI + ui_template = path.join(path.dirname(path.realpath(__file__)), 'SmarActTipTilt.embedded.ui') + + def __init__(self, parent=None, **kwargs): + super().__init__(parent=parent) + + self.ui = typing.cast(_SmarActTipTiltEmbeddedUI, uic.loadUi(self.ui_template, self)) + self._omit_names = ['jog_fwd', 'jog_rev'] + self.ui.extended_signal_panel = None + + self.ui.settings_button.clicked.connect(self._expand_layout) + + @property + def device(self): + """The associated device.""" + try: + return self.devices[0] + except Exception: + ... + + def add_device(self, device): + """Typhos hook for adding a new device.""" + super().add_device(device) + # Gotta make sure to destroy this screen if you were handed an empty device + if device is None: + self.ui.device_name_label.setText("(no device)") + if self.ui.extended_signal_panel is not None: + self.layout().removeWidget(self.ui.extended_signal_panel) + self.ui.extended_signal_panel.destroyLater() + self.ui.extended_signal_panel = None + return + + # Can't do this during init because the device doesn't exist yet! + self.update_pvs() + + @QtCore.Property("QStringList") + def omitNames(self) -> list[str]: + """Get or set the list of names to omit in the expanded signal panel.""" + return self._omit_names + + @omitNames.setter + def omitNames(self, omit_names: list[str]) -> None: + if omit_names == self._omit_names: + return + + self._omit_names = list(omit_names or []) + if self.ui.extended_signal_panel is not None: + self.ui.extended_signal_panel.omitNames = self._omit_names + + def _create_signal_panel(self) -> Optional[TyphosSignalPanel]: + """Create the 'extended' TyphosSignalPanel for the device.""" + if self.device is None: + return None + + return SettingsPanel(mirror=self, parent=self, flags=QtCore.Qt.Window) + + def _expand_layout(self) -> None: + """Toggle the expansion of the signal panel.""" + if self.ui.extended_signal_panel is None: + self.ui.extended_signal_panel = self._create_signal_panel() + if self.ui.extended_signal_panel is None: + return + to_show = True + else: + to_show = not self.ui.extended_signal_panel.isVisible() + + self.ui.extended_signal_panel.setVisible(to_show) + + def update_pvs(self): + """ + Once we have the tip-tilt device, set the TIP and TILT channels to + the buttons and labels. + """ + + if self.device is None: + print('No device set!') + return + + self.ui.tip_forward.set_channel(f'ca://{self.device.tip.prefix}:STEP_FORWARD.PROC') + self.ui.tip_reverse.set_channel(f'ca://{self.device.tip.prefix}:STEP_REVERSE.PROC') + self.ui.tip_step_count.set_channel(f'ca://{self.device.tip.prefix}:TOTAL_STEP_COUNT') + self.ui.tilt_forward.set_channel(f'ca://{self.device.tilt.prefix}:STEP_FORWARD.PROC') + self.ui.tilt_reverse.set_channel(f'ca://{self.device.tilt.prefix}:STEP_REVERSE.PROC') + self.ui.tilt_step_count.set_channel(f'ca://{self.device.tilt.prefix}:TOTAL_STEP_COUNT') + + def get_names_to_omit(self) -> list[str]: + """ + Get a list of signal names to omit in the extended panel. + + Returns + ------- + list[str] + """ + device: Optional[ophyd.Device] = self.device + if device is None: + return [] + + to_omit = set(['jog_fwd', 'jog_rev']) + + # TODO: move these to a Qt designable property + for name in self.omitNames: + to_omit.add(name) + + if device.name in to_omit: + # Don't let the renamed position signal stop us from showing any + # signals: + to_omit.remove(device.name) + return sorted(to_omit) + + +class _StageSettingsUI(): + """helper for the stages basic settings. Do not instantiate.""" + tip_label: QtWidgets.QLabel + tilt_label: QtWidgets.QLabel + step_size_label: QtWidgets.QLabel + tip_step_size_rbv: pydm.widgets.label.PyDMLabel + tip_step_size_set: pydm.widgets.line_edit.PyDMLineEdit + tilt_step_size_rbv: pydm.widgets.label.PyDMLabel + tilt_step_size_set: pydm.widgets.line_edit.PyDMLineEdit + step_count_label: QtWidgets.QLabel + step_count_rbv: pydm.widgets.label.PyDMLabel + step_volt_label: QtWidgets.QLabel + tip_step_volt_rbv: pydm.widgets.label.PyDMLabel + tip_step_volt_set: pydm.widgets.line_edit.PyDMLineEdit + tilt_step_volt_rbv: pydm.widgets.label.PyDMLabel + tilt_step_volt_set: pydm.widgets.label.PyDMLineEdit + + +class SettingsPanel(QtWidgets.QWidget): + """ + Container class for basic settings that accompany open-loop movement for SmarAct tip-tilts. Largely lifted from TyphosPositionerRow + """ + mirror: SmarActTipTiltWidget + resize_timer: QtCore.QTimer + + def __init__(self, mirror: SmarActTipTiltWidget, parent: QtWidgets.QWidget | None = None, **kwargs): + super().__init__(parent=parent, **kwargs) + + self.mirror = mirror + # Make the subdevice labels + self.tip_label = QtWidgets.QLabel() + self.format_label(self.tip_label, 'Tip') + + self.tilt_label = QtWidgets.QLabel() + self.format_label(self.tilt_label, 'Tilt') + + # Then add panels, widgets, devices, and scroll areas + self.tip_panel = TyphosSignalPanel() + self.tip_panel.sortBy = SignalOrder.byName + self.tip_panel.omitNames = mirror.get_names_to_omit() + self.tip_panel.add_device(mirror.device.tip) + self.tip_scroll_area = QtWidgets.QScrollArea() + self.format_scroll_area(self.tip_panel, self.tip_scroll_area) + + self.tilt_panel = TyphosSignalPanel() + self.tilt_panel.sortBy = SignalOrder.byName + self.tilt_panel.omitNames = mirror.get_names_to_omit() + self.tilt_panel.add_device(mirror.device.tilt) + self.tilt_scroll_area = QtWidgets.QScrollArea() + self.format_scroll_area(self.tilt_panel, self.tilt_scroll_area) + + # Then add them to the layout! + layout = QtWidgets.QVBoxLayout() + layout.addWidget(self.tip_label) + layout.addWidget(self.tip_scroll_area) + layout.addWidget(self.tilt_label) + layout.addWidget(self.tilt_scroll_area) + + # Set the layout and then do some resize timer set-up + self.setLayout(layout) + self.resize_timer = QtCore.QTimer(parent=self) + self.resize_timer.timeout.connect(self.fix_scroll_size) + self.resize_timer.setInterval(1) + self.resize_timer.setSingleShot(True) + + # Capture the initial min widths + for panel in [self.tip_panel, self.tilt_panel]: + panel.original_panel_min_width = panel.minimumWidth() + panel.last_resize_width = 0 + + self.resize_done = False + + def format_label(self, label, label_text): + """Create and format the text for each subdevice""" + _label = label + _label.setText(label_text) + _font = _label.font() + _font.setPointSize(_font.pointSize() + 4) + _label.setFont(_font) + _label.setMaximumHeight( + QtGui.QFontMetrics(_font).boundingRect(_label.text()).height() + ) + + def format_scroll_area(self, panel, panel_scroll_area): + """Format the scroll area for each subdevice""" + panel_scroll_area.setFrameStyle(QtWidgets.QFrame.NoFrame) + panel_scroll_area.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) + panel_scroll_area.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + panel_scroll_area.setWidgetResizable(True) + panel_scroll_area.setWidget(panel) + + def hideEvent(self, event: QtGui.QHideEvent): + """ + After hide, update button text, even if we were hidden via clicking the "x". + Shamelessly stolen from TyphosPositionerRow. + """ + button = self.mirror.ui.settings_button + button.PyDMIcon = 'SP_ToolBarHorizontalExtensionButton' + return super().hideEvent(event) + + def showEvent(self, event: QtGui.QShowEvent): + """ + Before show, update button text and move window to just under button. + Shamelessly stolen from TyphosPositionerRow. + """ + button = self.mirror.ui.settings_button + button.PyDMIcon = 'SP_ToolBarVerticalExtensionButton' + self.move( + button.mapToGlobal( + QtCore.QPoint( + button.pos().x(), + button.pos().y() + button.height() + + self.style().pixelMetric(QtWidgets.QStyle.PM_TitleBarHeight), + ) + ) + ) + if not self.resize_done: + self.resize_timer.start() + return super().showEvent(event) + + def fix_scroll_size(self): + """ + Slot that ensures the panel gets enough space in the scroll area. + + The panel, when created, has smaller sizing information than it does + a few moments after being shown for the first time. This might + update several times before settling down. + + We want to watch for this resize and set the scroll area width such + that there's enough room to see the widget at its minimum size. + -------------------------------------------------------------------- + Also shamelessly stolen from TyphosPositionerRow + """ + for panel in [self.tip_panel, self.tilt_panel]: + if panel.minimumWidth() <= panel.original_panel_min_width: + # No change + self.resize_timer.start() + return + elif panel.last_resize_width != panel.minimumWidth(): + # We are not stable yet + panel.last_resize_width = panel.minimumWidth() + self.resize_timer.start() + return + + def make_space(self, scroll_area, panel): + """Generalize fixing the dimensions of the scroll areas for multiple panels""" + scroll_area.setMinimumWidth( + panel.minimumWidth() + + self.style().pixelMetric(QtWidgets.QStyle.PM_ScrollBarExtent) + + 2 * self.style().pixelMetric(QtWidgets.QStyle.PM_ScrollView_ScrollBarOverlap) + + 2 * self.style().pixelMetric(QtWidgets.QStyle.PM_ScrollView_ScrollBarSpacing) + ) + + make_space(self, self.tip_scroll_area, self.tip_panel) + make_space(self, self.tilt_scroll_area, self.tilt_panel) + + self.resize_done = True From d93860ab8de3f584ff750905ff2298ba0230fe3f Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Wed, 29 Jan 2025 10:00:51 -0800 Subject: [PATCH 04/22] MNT: Try to fix expanded panel placement and refactor the resize function --- pcdsdevices/ui/SmarActTipTilt.embedded.py | 33 ++++++++++++++--------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/pcdsdevices/ui/SmarActTipTilt.embedded.py b/pcdsdevices/ui/SmarActTipTilt.embedded.py index efded139de4..b61cf2e32d0 100644 --- a/pcdsdevices/ui/SmarActTipTilt.embedded.py +++ b/pcdsdevices/ui/SmarActTipTilt.embedded.py @@ -16,7 +16,7 @@ class _SmarActTipTiltEmbeddedUI(QtWidgets.QWidget): - """Annotations helper for SmarAct.embedded.ui. Do not instantiate.""" + """Annotations helper for SmarActTipTilt.embedded.ui. Do not instantiate.""" dpad_label: QtWidgets.QLabel tip_forward: pydm.widgets.pushbutton.PyDMPushButton tip_reverse: pydm.widgets.pushbutton.PyDMPushButton @@ -246,12 +246,14 @@ def showEvent(self, event: QtGui.QShowEvent): """ button = self.mirror.ui.settings_button button.PyDMIcon = 'SP_ToolBarVerticalExtensionButton' + offset = button.mapToGlobal(QtCore.QPoint(0, 0)) self.move( button.mapToGlobal( QtCore.QPoint( - button.pos().x(), + button.pos().x() + button.width(), button.pos().y() + button.height() - + self.style().pixelMetric(QtWidgets.QStyle.PM_TitleBarHeight), + + self.style().pixelMetric(QtWidgets.QStyle.PM_TitleBarHeight) + - offset.y(), ) ) ) @@ -272,16 +274,21 @@ def fix_scroll_size(self): -------------------------------------------------------------------- Also shamelessly stolen from TyphosPositionerRow """ - for panel in [self.tip_panel, self.tilt_panel]: - if panel.minimumWidth() <= panel.original_panel_min_width: - # No change - self.resize_timer.start() - return - elif panel.last_resize_width != panel.minimumWidth(): - # We are not stable yet - panel.last_resize_width = panel.minimumWidth() - self.resize_timer.start() - return + if (self.tip_panel.minimumWidth() <= self.tip_panel.original_panel_min_width or + self.tilt_panel.minimumWidth() <= self.tilt_panel.original_panel_min_width): + # No change + self.resize_timer.start() + return + _check_tip = self.tip_panel.last_resize_width != self.tip_panel.minimumWidth() + _check_tilt = self.tilt_panel.last_resize_width != self.tilt_panel.minimumWidth() + if _check_tip: + # We are not stable yet! + self.tip_panel.last_resize_width = self.tip_panel.minimumWidth() + if _check_tilt: + self.tip_panel.last_resize_width = self.tip_panel.minimumWidth() + if _check_tip or _check_tilt: + self.resize_timer.start() + return def make_space(self, scroll_area, panel): """Generalize fixing the dimensions of the scroll areas for multiple panels""" From 86f5aacf072ad69b3cf9c7593b126fbe16fc6d6d Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Wed, 29 Jan 2025 10:02:57 -0800 Subject: [PATCH 05/22] ENH: Fix object names and formatting for controls tabs --- pcdsdevices/ui/SmarAct.detailed.ui | 907 +++++++++++++++-------------- 1 file changed, 455 insertions(+), 452 deletions(-) diff --git a/pcdsdevices/ui/SmarAct.detailed.ui b/pcdsdevices/ui/SmarAct.detailed.ui index b1611f707b3..ad05a418576 100644 --- a/pcdsdevices/ui/SmarAct.detailed.ui +++ b/pcdsdevices/ui/SmarAct.detailed.ui @@ -239,6 +239,9 @@ + + true + 0 @@ -1490,7 +1493,7 @@ false - ca://${prefix}.HOMR + ca://${prefix}.HOMF fast-forward @@ -3141,12 +3144,58 @@ 9 - + 6 - - + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + Qt::AlignCenter + + + 0 + + + false + + + true + + + false + + + true + + + Closed-loop ONLY: Whether TTZV is enabled or not + + + ca://${prefix}:TTZV_MODE_RBV + + + false + + + + + 0 @@ -3181,18 +3230,72 @@ false - ca://${prefix}:PTYPE + sig://${name}_motor_egu - - + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 13 + 20 + + + + + + + + + 0 + 25 + + + + Description + + + Qt::AlignCenter + + + + + - + 0 0 + + + 0 + 25 + + + + Default minimum range for logical scale. Non-volatile. + + + Default Range Min + + + Qt::AlignCenter + + + true + + + + + 0 @@ -3223,16 +3326,16 @@ - - ca://${prefix}.EGU - - + false + + sig://${name}_description + - - + + 0 @@ -3267,12 +3370,78 @@ false - ca://${prefix}:SET_DRMIN + ca://${prefix}:SET_LSCO + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + TTZV Threshold + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Target to Zero Voltage + + + Qt::AlignCenter + + + true + + + + + + + + 0 + 25 + + + + PTYPE + + + Qt::AlignCenter - + @@ -3373,8 +3542,8 @@ - - + + 0 @@ -3409,28 +3578,12 @@ false - sig://${name}_motor_egu + ca://${prefix}.LLM - - - - Qt::Horizontal - - - QSizePolicy::MinimumExpanding - - - - 13 - 20 - - - - - - + + 0 @@ -3465,18 +3618,24 @@ true - Invert the logical scale. Must home after changing to take effect. Non-volatile. + - ca://${prefix}:LSCI_RBV + ca://${prefix}.LLM false - - + + + + + 0 + 0 + + 0 @@ -3507,56 +3666,24 @@ - - false - - ca://${prefix}:SET_LSCO + ca://${prefix}.EGU + + + false - - + + 0 25 - - High Limit - - - Qt::AlignCenter - - - - - - - - 0 - 25 - - - - PTYPE - - - Qt::AlignCenter - - - - - - - - 0 - 25 - - - - + + Qt::AlignCenter @@ -3577,18 +3704,18 @@ true - TTZV position threshold in encoder ticks (pm or ndeg). Range: 0 - 1E7 + false - ca://${prefix}:TTZ_THRESHOLD_RBV + ca://${prefix}.HLM - - + + 0 @@ -3623,18 +3750,52 @@ true - Closed-loop ONLY: Whether TTZV is enabled or not + Sets the distance code inversion flag. Non-volatile. - ca://${prefix}:TTZV_MODE_RBV + ca://${prefix}:DCIN_RBV false - - + + + + + 0 + 0 + + + + + 100 + 25 + + + + + + + false + + + true + + + Closed-loop ONLY: toggle TTZV state + + + false + + + ca://${prefix}:TTZV_MODE + + + + + 0 @@ -3642,21 +3803,27 @@ - Needs Calibration + High Limit Qt::AlignCenter - - + + 0 0 + + + 0 + 25 + + @@ -3679,18 +3846,34 @@ true - Current TTZV position threshold in encoder ticks (pm or ndeg) + Invert the logical scale. Must home after changing to take effect. Non-volatile. - ca://${prefix}:TTZ_THRESHOLD_RBV + ca://${prefix}:LSCI_RBV false - - + + + + + 0 + 25 + + + + Low Limit + + + Qt::AlignCenter + + + + + 0 @@ -3703,8 +3886,11 @@ 25 + + Sets the distance code inversion flag. Non-volatile. + - Default Range Max + Distance Code Inversion Qt::AlignCenter @@ -3714,8 +3900,8 @@ - - + + 0 @@ -3738,7 +3924,7 @@ 0 - false + true true @@ -3750,46 +3936,58 @@ true - Sets the distance code inversion flag. Non-volatile. + Shift the logical scale in mm. Non-volatile. - ca://${prefix}:DCIN_RBV + ca://${prefix}:LSCO false - - + + - + 0 0 - - - 0 - 25 - - - Sets the distance code inversion flag. Non-volatile. - - - Distance Code Inversion + Qt::AlignCenter - + + 0 + + + false + + + true + + + false + + true + + Current TTZV position threshold in encoder ticks (pm or ndeg) + + + ca://${prefix}:TTZ_THRESHOLD_RBV + + + false + - - + + 0 @@ -3824,23 +4022,26 @@ false - ca://${prefix}.LLM + ca://${prefix}:SET_DRMIN - - + + + + + 0 + 0 + + 0 25 - - Invert the logical scale. Must home after changing to take effect. Non-volatile. - - Logical Scale Inversion + Default Range Max Qt::AlignCenter @@ -3850,35 +4051,23 @@ - - + + - + 0 0 - 0 + 100 25 - - Qt::AlignCenter - - - 0 - - - true - - - true - false @@ -3886,18 +4075,34 @@ true - Shift the logical scale in mm. Non-volatile. + + + + false - ca://${prefix}:LSCO + ca://${prefix}:SET_DCIN - - false + + + + + + + 0 + 25 + + + + EGU + + + Qt::AlignCenter - - + + 0 @@ -3911,7 +4116,7 @@ - + Default maximum range for logical scale. Non-volatile. Qt::AlignCenter @@ -3932,10 +4137,10 @@ true - Default minimum range for logical scale. Non-volatile. + Default maximum range for logical scale. Non-volatile. - ca://${prefix}:DRMIN + ca://${prefix}:DRMAX false @@ -4023,36 +4228,24 @@ - - + + - + 0 0 - 0 + 100 25 - - Qt::AlignCenter - - - 0 - - - false - - - true - - + false @@ -4061,16 +4254,22 @@ - - ca://${prefix}:PTYPE_RBV - - + false + + ca://${prefix}:SET_LSCI + - - + + + + + 0 + 0 + + 0 @@ -4101,16 +4300,16 @@ - - false - - ca://${prefix}.HLM + ca://${prefix}:PTYPE_RBV + + + false - - + + 0 @@ -4118,41 +4317,23 @@ - + Invert the logical scale. Must home after changing to take effect. Non-volatile. + + + Logical Scale Inversion Qt::AlignCenter - - 0 - - - false - - - true - - - false - - + true - - - - - false - - - sig://${name}_description - - - + + - + 0 0 @@ -4164,55 +4345,30 @@ - Default maximum range for logical scale. Non-volatile. - - - Qt::AlignCenter - - - 0 - - - true - - - true + Shift the logical scale in mm. Non-volatile. - + false - - true - - - Default maximum range for logical scale. Non-volatile. - - - ca://${prefix}:DRMAX + + Logical Scale Offset - + false - - - - - - - 0 - 25 - - - - Low Limit - Qt::AlignCenter + + true + + + 0 + - - + + 0 @@ -4247,18 +4403,12 @@ false - ca://${prefix}:SET_DRMAX + ca://${prefix}:PTYPE - - - - - 0 - 0 - - + + 0 @@ -4287,18 +4437,34 @@ true - + TTZV position threshold in encoder ticks (pm or ndeg). Range: 0 - 1E7 + + + false - ca://${prefix}.DESC + ca://${prefix}:TTZ_THRESHOLD_RBV - - false + + + + + + + 0 + 25 + + + + Needs Calibration + + + Qt::AlignCenter - - + + 0 @@ -4336,96 +4502,15 @@ - ca://${prefix}.HLM + ca://${prefix}.DESC false - - - - - 0 - 0 - - - - - 0 - 25 - - - - Shift the logical scale in mm. Non-volatile. - - - false - - - Logical Scale Offset - - - false - - - Qt::AlignCenter - - - true - - - 0 - - - - - - - - 0 - 25 - - - - Description - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - - 0 - 25 - - - - Default minimum range for logical scale. Non-volatile. - - - Default Range Min - - - Qt::AlignCenter - - - true - - - - - + + 0 @@ -4448,7 +4533,7 @@ 0 - false + true true @@ -4460,18 +4545,18 @@ true - + Default minimum range for logical scale. Non-volatile. - ca://${prefix}.LLM + ca://${prefix}:DRMIN false - - + + 0 @@ -4484,75 +4569,21 @@ 25 - - Target to Zero Voltage + + Qt::AlignCenter - - true - - - - - - - - 0 - 0 - - - - - 0 - 25 - - - - TTZV Threshold + + 0 - - Qt::AlignCenter + + false - + true - - - - - - - 0 - 25 - - - - EGU - - - Qt::AlignCenter - - - - - - - - 0 - 0 - - - - - 100 - 25 - - - - - false @@ -4560,66 +4591,38 @@ true - Closed-loop ONLY: toggle TTZV state - - - false + - ca://${prefix}:TTZV_MODE + ca://${prefix}.HLM + + + false - - - - - 0 - 0 - - + + - 100 + 0 25 - - false - - - true + + Qt::AlignCenter - - + + 0 - + false - - ca://${prefix}:SET_LSCI - - - - - - - - 0 - 0 - - - - - 100 - 25 - - - - + + true false @@ -4634,7 +4637,7 @@ false - ca://${prefix}:SET_DCIN + ca://${prefix}:SET_DRMAX From 315cd1f7809e8ef6028b107ee8c03f0bf074bf82 Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Wed, 29 Jan 2025 10:57:14 -0800 Subject: [PATCH 06/22] ENH: Add hybrid pyqt script to handle SmarAct closed loop UI and include optional picoscale --- pcdsdevices/ui/SmarAct.detailed.py | 370 +++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 pcdsdevices/ui/SmarAct.detailed.py diff --git a/pcdsdevices/ui/SmarAct.detailed.py b/pcdsdevices/ui/SmarAct.detailed.py new file mode 100644 index 00000000000..d942c104679 --- /dev/null +++ b/pcdsdevices/ui/SmarAct.detailed.py @@ -0,0 +1,370 @@ +from __future__ import annotations + +import logging +import re +import typing +from os import path + +import pydm +from pydm import Display +from qtpy import QtCore, QtWidgets, uic +from typhos import utils + +logger = logging.getLogger(__name__) + + +class _SmarActDetailedUI(QtWidgets.QWidget): + """Annotations helper for SmarAct.detailed.ui. Do not instantiate.""" + # Status bar + calibrated_bool: pydm.widgets.byte.PyDMByteIndicator + has_encoder_bool: pydm.widgets.byte.PyDMByteIndicator + referenced_bool: pydm.widgets.byte.PyDMByteIndicator + # Open-loop tab + jog_forward_button: pydm.widgets.pushbutton.PyDMPushButton + jog_reverse_button: pydm.widgets.pushbutton.PyDMPushButton + clear_count_button: pydm.widgets.pushbutton.PyDMPushButton + total_step_count_rbv: pydm.widgets.label.PyDMLabel + step_size_rbv: pydm.widgets.label.PyDMLabel + step_size_set: pydm.widgets.line_edit.PyDMLineEdit + step_volt_rbv: pydm.widgets.label.PyDMLabel + step_volt_set: pydm.widgets.line_edit.PyDMLineEdit + step_freq_rbv: pydm.widgets.label.PyDMLabel + step_freq_set: pydm.widgets.line_edit.PyDMLineEdit + scan_volt_rbv: pydm.widgets.label.PyDMLabel + scan_volt_set: pydm.widgets.line_edit.PyDMLineEdit + # Closed-loop tab + home_forward_button: pydm.widgets.pushbutton.PyDMPushButton + home_reverse_button: pydm.widgets.pushbutton.PyDMPushButton + curr_pos_rbv: pydm.widgets.label.PyDMLabel + curr_pos_set: pydm.widgets.line_edit.PyDMLineEdit + home_velocity_rbv: pydm.widgets.label.PyDMLabel + home_velocity_set: pydm.widgets.line_edit.PyDMLineEdit + velocity_rbv: pydm.widgets.label.PyDMLabel + velocity_set: pydm.widgets.line_edit.PyDMLineEdit + velocity_base_rbv: pydm.widgets.label.PyDMLabel + velocity_base_set: pydm.widgets.line_edit.PyDMLineEdit + velocity_max_rbv: pydm.widgets.label.PyDMLabel + velocity_max_set: pydm.widgets.line_edit.PyDMLineEdit + acceleration_rbv: pydm.widgets.label.PyDMLabel + acceleration_set: pydm.widgets.line_edit.PyDMLineEdit + closed_loop_freq_max_rbv: pydm.widgets.label.PyDMLabel + closed_loop_freq_max_set: pydm.widgets.line_edit.PyDMLineEdit + # Diagnostics tab + chan_temp_rbv: pydm.widgets.label.PyDMLabel + mod_temp_rbv: pydm.widgets.label.PyDMLabel + motor_load_rbv: pydm.widgets.label.PyDMLabel + chan_error_rbv: pydm.widgets.label.PyDMLabel + diag_closed_loop_freq_max_rbv: pydm.widgets.label.PyDMLabel + diag_closed_loop_freq_avg_rbv: pydm.widgets.label.PyDMLabel + diag_closed_loop_freq_timebase_rbv: pydm.widgets.label.PyDMLabel + channel_states: pydm.widgets.byte.PyDMByteIndicator + # Config tab + desc_rbv: pydm.widgets.label.PyDMLabel + desc_set: pydm.widgets.line_edit.PyDMLineEdit + egu_rbv: pydm.widgets.label.PyDMLabel + egu_set: pydm.widgets.line_edit.PyDMLineEdit + ptype_rbv: pydm.widgets.label.PyDMLabel + ptype_set: pydm.widgets.line_edit.PyDMLineEdit + need_calib_led: pydm.widgets.byte.PyDMByteIndicator + calibrate_button: pydm.widgets.pushbutton.PyDMPushButton + low_limit_rbv: pydm.widgets.label.PyDMLabel + low_limit_set: pydm.widgets.line_edit.PyDMLineEdit + high_limit_rbv: pydm.widgets.label.PyDMLabel + high_limit_set: pydm.widgets.line_edit.PyDMLineEdit + ttzv_rbv: pydm.widgets.label.PyDMLabel + ttzv_set: pydm.widgets.enum_combo_box.PyDMEnumComboBox + ttzv_threshold_rbv: pydm.widgets.label.PyDMLabel + ttzv_treshold_set: pydm.widgets.line_edit.PyDMLineEdit + logical_scale_offset_rbv: pydm.widgets.label.PyDMLabel + logical_scale_offset_set: pydm.widgets.line_edit.PyDMLineEdit + logical_scale_inversion_rbv: pydm.widgets.label.PyDMLabel + logical_scale_inversion_set: pydm.widgets.enum_combo_box.PyDMEnumComboBox + def_range_min_rbv: pydm.widgets.label.PyDMLabel + def_range_min_set: pydm.widgets.line_edit.PyDMLineEdit + def_range_max_rbv: pydm.widgets.label.PyDMLabel + def_range_max_set: pydm.widgets.line_edit.PyDMLineEdit + dist_code_inversion_rbv: pydm.widgets.label.PyDMLabel + dist_code_inversion_set: pydm.widgets.enum_combo_box.PyDMEnumComboBox + # Misc + controls_tabs: QtWidgets.QTabWidget + pico_adjustment_prog_bar: QtWidgets.QProgressBar + + +class SmarActDetailedWidget(Display, utils.TyphosBase): + """ + Custom widget for managing the SmarAct detailed screen + """ + ui: _SmarActDetailedUI + ui_template = path.join(path.dirname(path.realpath(__file__)), 'SmarAct.detailed.ui') + + def __init__(self, parent=None, **kwargs): + super().__init__(parent=parent) + + self.ui = typing.cast(_SmarActDetailedUI, uic.loadUi(self.ui_template, self)) + + @property + def device(self): + """The associated device.""" + try: + return self.devices[0] + except Exception: + ... + + def add_device(self, device): + """Typhos hook for adding a new device.""" + super().add_device(device) + # Gotta make sure to destroy this screen if you were handed an empty device + if device is None: + self.ui.device_name_label.setText("(no device)") + return + + self.post_typhos_init() + + def post_typhos_init(self): + """ + Once typhos has relinked the device and parent widget, we need to clean + Up some of the signals and maybe add new widgets to the display. + Add any other init-esque shenanigans you need here. + """ + self.fix_pvs() + self.maybe_add_pico() + # Only start this timer if PicoScale exists + if hasattr(self.device, 'pico_exists'): + self.adj_prog_timer = QtCore.QTimer(parent=self) + self.adj_prog_timer.timeout.connect(self.update_adj_prog) + self.adj_prog_timer.setInterval(1000) + self.adj_prog_timer.start() + self._last_adj_prog = 0 + + def fix_pvs(self): + """ + Fix all the channel access and signal linking to various pydm objects in the screen, + since the macros aren't expanded when the UI is initialized. + """ + object_names = self.find_pydm_names() + for obj in object_names: + _widget = getattr(self, obj) + _channel = getattr(_widget, 'channel') + if re.search(r'\{prefix\}', _channel): + _widget.set_channel(_channel.replace('${prefix}', self.device.prefix)) + if re.search(r'\{name\}', _channel): + _widget.set_channel(_channel.replace('${name}', self.device.name)) + + def find_pydm_names(self) -> list[str]: + """ + Find the object names for all PyDM objects using findChildren + + Returns + ------------ + result : list[str] + 1D list of object names + """ + _button = pydm.widgets.pushbutton.PyDMPushButton + _byte = pydm.widgets.byte.PyDMByteIndicator + _label = pydm.widgets.label.PyDMLabel + _line_edit = pydm.widgets.line_edit.PyDMLineEdit + _combo_box = pydm.widgets.enum_combo_box.PyDMEnumComboBox + + result = [] + + for obj_type in [_button, _byte, _label, _line_edit, _combo_box]: + result += [obj.objectName() for obj in self.findChildren(obj_type)] + + # get rid of the objects from the embedded TyphosPositioner widget + _omit = ['low_limit_switch', 'moving_indicator', 'high_limit_switch', + 'low_limit', 'user_readback', 'error_label', + 'high_limit', 'user_setpoint'] + + return [obj for obj in result if obj not in _omit] + + def maybe_add_pico(self): + """ + Maybe add the picoscale tab and signals _if_ they exist. + Sadly involves a lot of manual signal management that would normally be + handled in TyphosSignalPanel. + """ + if hasattr(self.device, 'pico_exists'): + if hasattr(self, 'picoscale'): + # Don't add infite tabs please :] + return + # Grab all the pico related signals + _pico_signals = [sig for sig in self.device.component_names if 'pico' in sig] + self.pico_signal_dict = {} + # Grab any usable info from the HAPPI device and rebuild the JSON + for sig in _pico_signals: + _d = {} + _sig = getattr(self.device, sig) + _d['name'] = sig + if hasattr(_sig, 'pvname'): + _d['read_pv'] = _sig.pvname + if hasattr(_sig, 'setpoint_pvname'): + _d['write_pv'] = _sig.setpoint_pvname + self.pico_signal_dict[sig] = _d + + # Now we have to do some manual nonsense because I'm picky. If I was smart I'd figure out + # how to tweak Typhos and make this a lot easier for other use cases [: + # Manual label naming + _label_map = [('pico_present', 'PicoScale Present?'), + ('pico_exists', 'PicoScale Exists?'), + ('pico_valid', 'PicoScale Valid?'), + ('pico_sig_qual', 'Signal Quality'), + ('pico_adj_state', 'Adjustment State'), + ('pico_curr_adj_prog', 'Current Adjustment Progress'), + ('pico_adj_done', 'Adjustment Complete'), + ('pico_enable', 'PicoScale Enabled'), + ('pico_stable', 'Signal Stable?'), + ('pico_name', 'PicoScale Name'), + ('pico_wmin', 'Working Distance (min)'), + ('pico_wmax', 'Working Distance (max)')] + for item in _label_map: + self.pico_signal_dict[item[0]]['label'] = item[-1] + + # Now let's add some metadata for customizing the display + _byte_sigs = ['pico_present', 'pico_exists', 'pico_valid', 'pico_enable', 'pico_stable'] + _enum_sigs = ['pico_adj_state'] + for sig in _byte_sigs: + self.pico_signal_dict[sig]['meta'] = 'byte' + for sig in _enum_sigs: + self.pico_signal_dict[sig]['meta'] = 'enum' + # Some exceptions that prove the rule + self.pico_signal_dict['pico_curr_adj_prog']['meta'] = 'progressbar' + + # Last but not least, let me manually dictate the signal order + _row_map = [('pico_name', 0), + ('pico_present', 1), + ('pico_exists', 2), + ('pico_valid', 3), + ('pico_enable', 4), + ('pico_stable', 5), + ('pico_adj_done', 6), + ('pico_wmin', 7), + ('pico_wmax', 8), + ('pico_sig_qual', 9), + ('pico_adj_state', 10), + ('pico_curr_adj_prog', 11), + ] + for item in _row_map: + self.pico_signal_dict[item[0]]['row'] = item[-1] + + # Generate the tab + self.generate_pico_tab() + + def generate_pico_tab(self): + """ + Gather all the pico related signals from the device and format the signal panel. + A lot of this is recycled from TyphosSignalPanel with some alterations. + """ + + def add_signal_row(grid: QtWidgets.QGridLayout, signal_dict: dict): + """ + Similar to the typhos method but allows for some manual overhauling. + Bundles an EpicsSignal into a row of (Label, RBV widget, Setpoint widget) + and adds it to a grid layout. + + Parameters + ------------ + grid: QtWidgets.QGridLayout + The layout to add the signals to + signal_dict: dict + A JSON-like dictionary of device signals, names, and metadata + + Returns + ------------ + None + """ + # Make the row label first + row_label = QtWidgets.QLabel() + row_label.setText(signal_dict['label']) + # Set the object name as an attr for later shenanigans + setattr(self, signal_dict['name'] + '_label', row_label) + + # Then set the RBV widget + rbv_widget = pydm.widgets.label.PyDMLabel() + rbv_widget.setAlignment(QtCore.Qt.AlignCenter) + # Unless they're special + if 'meta' in signal_dict: + if signal_dict['meta'] == 'byte': + rbv_widget = pydm.widgets.byte.PyDMByteIndicator() + rbv_widget.circles = 1 + rbv_widget.showLabels = 0 + if signal_dict['meta'] == 'progressbar': + rbv_widget = QtWidgets.QProgressBar() + rbv_widget.setRange(0, 100) + rbv_widget.hide() + row_label.hide() + + # Add the widget as an attr for later shenanigans + setattr(self, signal_dict['name'] + '_rbv', rbv_widget) + + if hasattr(rbv_widget, 'set_channel'): + rbv_widget.set_channel(signal_dict['read_pv']) + + # Create setpoint widgets if they exist + if 'write_pv' in signal_dict: + # handle tricky enums + if 'meta' in signal_dict and signal_dict['meta'] == 'enum': + setpoint_widget = pydm.widgets.enum_combo_box.PyDMEnumComboBox() + setpoint_widget.set_channel(signal_dict['write_pv']) + # lean on HAPPI if possible + _signal_metadata = getattr(self.device, signal_dict['name']).metadata + if 'enum_strs' in _signal_metadata: + for item in _signal_metadata['enum_strs']: + setpoint_widget.addItem(item) + # Otherwise just give it some defaults + else: + for item in ['Disable', 'Enable']: + setpoint_widget.addItem(item) + # Default line edits + else: + setpoint_widget = pydm.widgets.line_edit.PyDMLineEdit() + setpoint_widget.set_channel(signal_dict['write_pv']) + + # Add the widget as an attr for later shenanigans + setattr(self, signal_dict['name'] + '_set', setpoint_widget) + + # Now finally add these signals + grid.addWidget(row_label, signal_dict['row'], 0) + grid.addWidget( + getattr(self, signal_dict['name'] + '_rbv'), signal_dict['row'], 1) + if 'write_pv' in signal_dict: + grid.addWidget(setpoint_widget, signal_dict['row'], 2) + + # Make the tab + self.picoscale = QtWidgets.QWidget() + # Format the scroll area + pico_scroll_area = QtWidgets.QScrollArea() + pico_scroll_area.setFrameStyle(QtWidgets.QFrame.NoFrame) + pico_scroll_area.setWidget(self.picoscale) + # Format the tab layout + self.picoscale.layout = QtWidgets.QVBoxLayout() + # Add signals + self.picoscale.panel = QtWidgets.QGridLayout() + for _d in self.pico_signal_dict: + add_signal_row(self.picoscale.panel, self.pico_signal_dict[_d]) + # Set the layout and add to the tab widget + self.picoscale.setLayout(self.picoscale.panel) + self.controls_tabs.addTab(self.picoscale, 'Picoscale') + + def update_adj_prog(self): + """ + Function for displaying and updating the QProgressBar when the PicoScale + Auto-adjustment is taking place. + """ + # Check to see if the system can even enter adjustment and display the bar + if self.device.pico_adj_state.get(): + self.adj_prog_timer.start() + if not self._last_adj_prog: + self.pico_curr_adj_prog_rbv.show() + self.pico_curr_adj_prog_label.show() + # Then check to see if the progress has updated + if self._last_adj_prog < self.device.pico_curr_adj_prog.get(): + self.pico_curr_adj_prog_rbv.setValue(self.device.pico_curr_adj_prog.get()) + # Now finally check to see if it is complete. Since the threaded behavior in the IOC + # toggles the adjustment PV for ALL stages on a PicoScale when adjustment completes, + # check for that state change too. + if self.device.pico_adj_done.get() or not self.device.pico_adj_state.get(): + self.pico_curr_adj_prog_rbv.hide() + self.pico_curr_adj_prog_rbv.reset() + self.pico_curr_adj_prog_label.hide() + # reset the timer too in case you need re-adjust later on + self.adj_prog_timer.start() From f327052182fdab55f69af0e3134a6d317927758d Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Wed, 29 Jan 2025 13:29:56 -0800 Subject: [PATCH 07/22] DOC: add release notes --- .../1275-SmarAct_UI_Overhaul.rst | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst diff --git a/docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst b/docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst new file mode 100644 index 00000000000..e1c4ce55f1d --- /dev/null +++ b/docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst @@ -0,0 +1,32 @@ +1275 SmarAct UI Overhaul +################# + +API Breaks +---------- +- N/A + +Library Features +---------------- +- Added SmarAct.detailed.ui screen +- Accompanying SmarAct.detailed.py screen to handle closed loop and picoscale +- Added SmarActTipTilt.embedded ui and py screens for operational support + +Device Features +--------------- +- N/A + +New Devices +----------- +- N/A + +Bugfixes +-------- +- N/A + +Maintenance +----------- +- N/A + +Contributors +------------ +- aberges-SLAC From 38ed48d5e711714264bdf64b6c1acf40200f8e08 Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Thu, 30 Jan 2025 16:26:50 -0800 Subject: [PATCH 08/22] MNT: fix some ui loading calls for both screens and resizing condition checks for TipTilt --- pcdsdevices/ui/SmarAct.detailed.py | 10 ++++------ pcdsdevices/ui/SmarActTipTilt.embedded.py | 18 +++++++----------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/pcdsdevices/ui/SmarAct.detailed.py b/pcdsdevices/ui/SmarAct.detailed.py index d942c104679..16f769f5762 100644 --- a/pcdsdevices/ui/SmarAct.detailed.py +++ b/pcdsdevices/ui/SmarAct.detailed.py @@ -2,12 +2,11 @@ import logging import re -import typing from os import path import pydm from pydm import Display -from qtpy import QtCore, QtWidgets, uic +from qtpy import QtCore, QtWidgets from typhos import utils logger = logging.getLogger(__name__) @@ -95,12 +94,11 @@ class SmarActDetailedWidget(Display, utils.TyphosBase): Custom widget for managing the SmarAct detailed screen """ ui: _SmarActDetailedUI + # Seems confusing, but really just cleans up the call to pydm for setting self.ui ui_template = path.join(path.dirname(path.realpath(__file__)), 'SmarAct.detailed.ui') - def __init__(self, parent=None, **kwargs): - super().__init__(parent=parent) - - self.ui = typing.cast(_SmarActDetailedUI, uic.loadUi(self.ui_template, self)) + def __init__(self, parent=None, ui_filename=ui_template, **kwargs): + super().__init__(parent=parent, ui_filename=ui_filename) @property def device(self): diff --git a/pcdsdevices/ui/SmarActTipTilt.embedded.py b/pcdsdevices/ui/SmarActTipTilt.embedded.py index b61cf2e32d0..fd9a8614faa 100644 --- a/pcdsdevices/ui/SmarActTipTilt.embedded.py +++ b/pcdsdevices/ui/SmarActTipTilt.embedded.py @@ -1,14 +1,13 @@ from __future__ import annotations import logging -import typing from os import path from typing import Optional import ophyd import pydm from pydm import Display -from qtpy import QtCore, QtGui, QtWidgets, uic +from qtpy import QtCore, QtGui, QtWidgets from typhos import utils from typhos.panel import SignalOrder, TyphosSignalPanel @@ -30,12 +29,12 @@ class _SmarActTipTiltEmbeddedUI(QtWidgets.QWidget): class SmarActTipTiltWidget(Display, utils.TyphosBase): """Custom widget for controlling a tip-tilt with d-pad buttons""" ui: _SmarActTipTiltEmbeddedUI + # Seems confusing, but really just cleans up the call to pydm for setting self.ui ui_template = path.join(path.dirname(path.realpath(__file__)), 'SmarActTipTilt.embedded.ui') - def __init__(self, parent=None, **kwargs): - super().__init__(parent=parent) + def __init__(self, parent=None, ui_filename=ui_template, **kwargs,): + super().__init__(parent=parent, ui_filename=ui_filename) - self.ui = typing.cast(_SmarActTipTiltEmbeddedUI, uic.loadUi(self.ui_template, self)) self._omit_names = ['jog_fwd', 'jog_rev'] self.ui.extended_signal_panel = None @@ -279,14 +278,11 @@ def fix_scroll_size(self): # No change self.resize_timer.start() return - _check_tip = self.tip_panel.last_resize_width != self.tip_panel.minimumWidth() - _check_tilt = self.tilt_panel.last_resize_width != self.tilt_panel.minimumWidth() - if _check_tip: + elif (self.tip_panel.last_resize_width != self.tip_panel.minimumWidth() or + self.tilt_panel.last_resize_width != self.tilt_panel.minimumWidth()): # We are not stable yet! self.tip_panel.last_resize_width = self.tip_panel.minimumWidth() - if _check_tilt: - self.tip_panel.last_resize_width = self.tip_panel.minimumWidth() - if _check_tip or _check_tilt: + self.tilt_panel.last_resize_width = self.tilt_panel.minimumWidth() self.resize_timer.start() return From a358576b301d0437c261358eccade2b60438aade Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Tue, 11 Feb 2025 16:16:29 -0800 Subject: [PATCH 09/22] ENH: Add long_names for SmarAct --- pcdsdevices/epics_motor.py | 61 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/pcdsdevices/epics_motor.py b/pcdsdevices/epics_motor.py index 1257c526019..ffbac373b85 100644 --- a/pcdsdevices/epics_motor.py +++ b/pcdsdevices/epics_motor.py @@ -1562,6 +1562,20 @@ class SmarActOpenLoop(Device): module_temp = Cpt(EpicsSignalRO, ':MODTEMP', kind='normal', doc='Temperature of the MCS2 Module in the rack') + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Long name shenanigans + self.step_voltage.long_name = 'Step Voltage' + self.step_freq.long_name = 'Step Frequency' + self.jog_step_size.long_name = 'Jog Step Size' + self.jog_fwd.long_name = 'Jog Forward' + self.jog_rev.long_name = 'Jog Backward' + self.total_step_count.long_name = 'Total Step Count' + self.step_clear_cmd.long_name = 'Clear Step Count' + self.scan_move.long_name = 'Scan Voltage' + self.channel_temp.long_name = 'Channel Temp. (°C)' + self.module_temp.long_name = 'Module Temp. (°C)' + class SmarActTipTilt(Device): """ @@ -1652,6 +1666,41 @@ class SmarAct(EpicsMotorInterface): # useful open_loop = Cpt(SmarActOpenLoop, '', kind='omitted') + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # Long name shenanigans + # Motor Record long name overrides + self.velocity.long_name = 'Velocity' + self.velocity_base.long_name = 'Velocity Min' + self.velocity_max.long_name = 'Velocity Max' + self.acceleration.long_name = 'Acceleration' + self.motor_stop.long_name = 'Stop Motor' + self.motor_is_moving.long_name = 'Actively Moving' + self.dial_position.long_name = 'Dial Position' + self.direction_of_travel.long_name = 'Direction of Travel' + self.home_forward.long_name = 'Home Forward' + self.home_reverse.long_name = 'Home Backward' + self.low_limit_switch.long_name = 'Low Limit Switch' + self.high_limit_switch.long_name = 'High Limit Switch' + self.high_limit_travel.long_name = 'High Limit Travel' + self.low_limit_travel.long_name = 'Low Limit Travel' + self.user_setpoint.long_name = 'Setpoint' + self.user_offset.long_name = 'User Offset' + self.user_offset_dir.long_name = 'User Offset Direction' + self.motor_egu.long_name = 'EGU' + self.description.long_name = 'Description' + # SmarAct specific long names + self.pos_type.long_name = 'Positioner Type' + self.needs_calib.long_name = 'Needs Calibration?' + self.do_calib.long_name = 'Calibrate' + self.log_scale_offset.long_name = 'Logical Scale Offset' + self.def_range_min.long_name = 'Default Range Min.' + self.def_range_max.long_name = 'Default Range Max' + self.log_scale_inv.long_name = 'Logical Scale Inversion' + self.dist_code_inv.long_name = 'Distance Code Inversion' + self.channel_temp.long_name = 'Channel Temp. (°C)' + self.module_temp.long_name = 'Module Temp. (°C)' + class SmarActEncodedTipTilt(Device): """ @@ -1718,6 +1767,18 @@ class SmarActPicoscale(SmarAct): def __init__(self, prefix, *, ioc_base, **kwargs): self._ioc_base = ioc_base super().__init__(prefix, **kwargs) + self.pico_adj_done.long_name = 'Auto Adjustment Done?' + self.pico_adj_state.long_name = 'Auto Adjustment State' + self.pico_curr_adj_prog.long_name = 'Auto Adjustment Progress' + self.pico_enable.long_name = 'PicoScale Enabled?' + self.pico_exists.long_name = 'PicoScale Exists?' + self.pico_name.long_name = 'PicoScale Name' + self.pico_present.long_name = 'PicoScale Present?' + self.pico_sig_qual.long_name = 'Signal Quality' + self.pico_valid.long_name = 'PicoScale Valid?' + self.pico_stable.long_name = 'PicoScale Stable?' + self.pico_wmax.long_name = 'Working distance (max)' + self.pico_wmin.long_name = 'Working distance (min)' class PI_M824(PVPositionerIsClose): From 0df115af1f5e3e355b0f943778c79991acaa1f2f Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Tue, 11 Feb 2025 16:17:09 -0800 Subject: [PATCH 10/22] ENH: Remove ${name} macros from channels, will be handled in .py script --- pcdsdevices/ui/SmarAct.detailed.ui | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pcdsdevices/ui/SmarAct.detailed.ui b/pcdsdevices/ui/SmarAct.detailed.ui index ad05a418576..4e229f106b2 100644 --- a/pcdsdevices/ui/SmarAct.detailed.ui +++ b/pcdsdevices/ui/SmarAct.detailed.ui @@ -1288,7 +1288,7 @@ 0 - 0 + -96 527 400 @@ -1784,7 +1784,7 @@ - + @@ -3230,7 +3230,7 @@ false - sig://${name}_motor_egu + @@ -3330,7 +3330,7 @@ false - sig://${name}_description + From 23510057b00c2f7cad11cf3c4cda271db4b8e887 Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Tue, 11 Feb 2025 16:17:54 -0800 Subject: [PATCH 11/22] ENH: Use long_names to simplify and refactor. Add another pico signal as a byte indicator --- pcdsdevices/ui/SmarAct.detailed.py | 50 +++++++++--------------------- 1 file changed, 14 insertions(+), 36 deletions(-) diff --git a/pcdsdevices/ui/SmarAct.detailed.py b/pcdsdevices/ui/SmarAct.detailed.py index 16f769f5762..47901ff83fe 100644 --- a/pcdsdevices/ui/SmarAct.detailed.py +++ b/pcdsdevices/ui/SmarAct.detailed.py @@ -143,10 +143,14 @@ def fix_pvs(self): for obj in object_names: _widget = getattr(self, obj) _channel = getattr(_widget, 'channel') + if not _channel: + _channel = '' if re.search(r'\{prefix\}', _channel): _widget.set_channel(_channel.replace('${prefix}', self.device.prefix)) - if re.search(r'\{name\}', _channel): - _widget.set_channel(_channel.replace('${name}', self.device.name)) + + # Now let's manually add the funky egu and description signals here to avoid terminal spam + self.desc_set.set_channel(f'sig://{self.device.name}_description') + self.egu_set.set_channel(f'sig://{self.device.name}_motor_egu') def find_pydm_names(self) -> list[str]: """ @@ -197,28 +201,12 @@ def maybe_add_pico(self): _d['read_pv'] = _sig.pvname if hasattr(_sig, 'setpoint_pvname'): _d['write_pv'] = _sig.setpoint_pvname + if hasattr(_sig, 'long_name'): + _d['label'] = _sig.long_name self.pico_signal_dict[sig] = _d - # Now we have to do some manual nonsense because I'm picky. If I was smart I'd figure out - # how to tweak Typhos and make this a lot easier for other use cases [: - # Manual label naming - _label_map = [('pico_present', 'PicoScale Present?'), - ('pico_exists', 'PicoScale Exists?'), - ('pico_valid', 'PicoScale Valid?'), - ('pico_sig_qual', 'Signal Quality'), - ('pico_adj_state', 'Adjustment State'), - ('pico_curr_adj_prog', 'Current Adjustment Progress'), - ('pico_adj_done', 'Adjustment Complete'), - ('pico_enable', 'PicoScale Enabled'), - ('pico_stable', 'Signal Stable?'), - ('pico_name', 'PicoScale Name'), - ('pico_wmin', 'Working Distance (min)'), - ('pico_wmax', 'Working Distance (max)')] - for item in _label_map: - self.pico_signal_dict[item[0]]['label'] = item[-1] - # Now let's add some metadata for customizing the display - _byte_sigs = ['pico_present', 'pico_exists', 'pico_valid', 'pico_enable', 'pico_stable'] + _byte_sigs = ['pico_present', 'pico_exists', 'pico_valid', 'pico_enable', 'pico_stable', 'pico_adj_done'] _enum_sigs = ['pico_adj_state'] for sig in _byte_sigs: self.pico_signal_dict[sig]['meta'] = 'byte' @@ -228,21 +216,11 @@ def maybe_add_pico(self): self.pico_signal_dict['pico_curr_adj_prog']['meta'] = 'progressbar' # Last but not least, let me manually dictate the signal order - _row_map = [('pico_name', 0), - ('pico_present', 1), - ('pico_exists', 2), - ('pico_valid', 3), - ('pico_enable', 4), - ('pico_stable', 5), - ('pico_adj_done', 6), - ('pico_wmin', 7), - ('pico_wmax', 8), - ('pico_sig_qual', 9), - ('pico_adj_state', 10), - ('pico_curr_adj_prog', 11), - ] - for item in _row_map: - self.pico_signal_dict[item[0]]['row'] = item[-1] + _rows = ['pico_name', 'pico_present', 'pico_exists', 'pico_valid', 'pico_enable', + 'pico_stable', 'pico_adj_done', 'pico_wmin', 'pico_wmax', 'pico_sig_qual', + 'pico_adj_state', 'pico_curr_adj_prog'] + for pos, item in enumerate(_rows): + self.pico_signal_dict[item]['row'] = pos # Generate the tab self.generate_pico_tab() From f8d0b190a45afb45a41e04f5f42ff99d0d1efa2d Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Tue, 11 Feb 2025 17:22:18 -0800 Subject: [PATCH 12/22] MNT: Rename LSCO and LSCI widgets to be consistent with epics_motor.device --- pcdsdevices/ui/SmarAct.detailed.ui | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pcdsdevices/ui/SmarAct.detailed.ui b/pcdsdevices/ui/SmarAct.detailed.ui index 4e229f106b2..32ba3fed68f 100644 --- a/pcdsdevices/ui/SmarAct.detailed.ui +++ b/pcdsdevices/ui/SmarAct.detailed.ui @@ -255,7 +255,7 @@ - 0 + 3 @@ -1288,7 +1288,7 @@ 0 - -96 + 0 527 400 @@ -2390,7 +2390,7 @@ 0 0 - 655 + 475 250 @@ -3230,7 +3230,7 @@ false - + @@ -3330,12 +3330,12 @@ false - + - + 0 @@ -3811,7 +3811,7 @@ - + 0 @@ -3901,7 +3901,7 @@ - + 0 @@ -4229,7 +4229,7 @@ - + 0 @@ -4309,7 +4309,7 @@ - + 0 @@ -4331,7 +4331,7 @@ - + 0 From d94b4cf2dd68fa925649b7706b8ee4e74d611900 Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Tue, 11 Feb 2025 17:23:10 -0800 Subject: [PATCH 13/22] MNT: Fix tab priority --- pcdsdevices/ui/SmarAct.detailed.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pcdsdevices/ui/SmarAct.detailed.ui b/pcdsdevices/ui/SmarAct.detailed.ui index 32ba3fed68f..b676f0e2b65 100644 --- a/pcdsdevices/ui/SmarAct.detailed.ui +++ b/pcdsdevices/ui/SmarAct.detailed.ui @@ -255,7 +255,7 @@ - 3 + 0 @@ -2390,7 +2390,7 @@ 0 0 - 475 + 655 250 From fc706f984ce351fa14d8bcb04b473dcde3aae2cd Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Tue, 11 Feb 2025 17:27:06 -0800 Subject: [PATCH 14/22] MNT: make channel and module temp widget object names consistent with epics_motor device --- pcdsdevices/ui/SmarAct.detailed.ui | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pcdsdevices/ui/SmarAct.detailed.ui b/pcdsdevices/ui/SmarAct.detailed.ui index b676f0e2b65..aab0aefcf73 100644 --- a/pcdsdevices/ui/SmarAct.detailed.ui +++ b/pcdsdevices/ui/SmarAct.detailed.ui @@ -2669,7 +2669,7 @@ - + 0 @@ -2842,7 +2842,7 @@ - + 0 @@ -2858,7 +2858,7 @@ - + 0 @@ -2942,7 +2942,7 @@ - + 0 @@ -3047,14 +3047,14 @@ - + Celsius - + Celsius From fcd710dd4ffcd60c9fe8719c8893aefe43db5c96 Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Tue, 11 Feb 2025 18:17:12 -0800 Subject: [PATCH 15/22] MNT: More naming convention fixes --- pcdsdevices/ui/SmarAct.detailed.ui | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/pcdsdevices/ui/SmarAct.detailed.ui b/pcdsdevices/ui/SmarAct.detailed.ui index aab0aefcf73..5da2af70576 100644 --- a/pcdsdevices/ui/SmarAct.detailed.ui +++ b/pcdsdevices/ui/SmarAct.detailed.ui @@ -356,19 +356,19 @@ - + QLayout::SetDefaultConstraint - + Forward - + 0 @@ -448,7 +448,7 @@ - + Qt::Horizontal @@ -463,9 +463,9 @@ - + - + Qt::Horizontal @@ -481,7 +481,7 @@ - + 0 @@ -561,7 +561,7 @@ - + Reverse @@ -625,7 +625,7 @@ 6 - + Scan Voltage @@ -838,7 +838,7 @@ - + 0 @@ -894,7 +894,7 @@ - + Step Size @@ -904,7 +904,7 @@ - + 0 @@ -978,7 +978,7 @@ - + 0 @@ -1172,7 +1172,7 @@ - + 0 From 8e032e7f1cf04ba1c53589fbf336a430d68b4ba6 Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Tue, 11 Feb 2025 18:28:24 -0800 Subject: [PATCH 16/22] MNT: EVEN MORE naming convention compliance --- pcdsdevices/ui/SmarAct.detailed.ui | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pcdsdevices/ui/SmarAct.detailed.ui b/pcdsdevices/ui/SmarAct.detailed.ui index 5da2af70576..6beafab58bf 100644 --- a/pcdsdevices/ui/SmarAct.detailed.ui +++ b/pcdsdevices/ui/SmarAct.detailed.ui @@ -635,9 +635,9 @@ - + - + 0 @@ -714,14 +714,14 @@ - + Clear Count - + Qt::Horizontal @@ -736,7 +736,7 @@ - + 0 @@ -1024,7 +1024,7 @@ - + Step Voltage @@ -1080,7 +1080,7 @@ - + 0 From 24b1d709f34bb6f5ff616484deee6696bef0d056 Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Tue, 11 Feb 2025 18:49:32 -0800 Subject: [PATCH 17/22] MNT: Last naming convention fix I swear --- pcdsdevices/ui/SmarAct.detailed.ui | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pcdsdevices/ui/SmarAct.detailed.ui b/pcdsdevices/ui/SmarAct.detailed.ui index 6beafab58bf..a2f4af7d26f 100644 --- a/pcdsdevices/ui/SmarAct.detailed.ui +++ b/pcdsdevices/ui/SmarAct.detailed.ui @@ -3425,7 +3425,7 @@ - + 0 @@ -3459,7 +3459,7 @@ - + 0 @@ -4148,7 +4148,7 @@ - + 0 @@ -4263,7 +4263,7 @@ - + 0 @@ -4368,7 +4368,7 @@ - + 0 From 323d4e3a791a8122ad99982ae747bccc0015f430 Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Tue, 11 Feb 2025 18:52:57 -0800 Subject: [PATCH 18/22] ENH: Add tooltip helpers and fix some object names --- pcdsdevices/ui/SmarAct.detailed.py | 66 +++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/pcdsdevices/ui/SmarAct.detailed.py b/pcdsdevices/ui/SmarAct.detailed.py index 47901ff83fe..96b680cb5ea 100644 --- a/pcdsdevices/ui/SmarAct.detailed.py +++ b/pcdsdevices/ui/SmarAct.detailed.py @@ -19,9 +19,9 @@ class _SmarActDetailedUI(QtWidgets.QWidget): has_encoder_bool: pydm.widgets.byte.PyDMByteIndicator referenced_bool: pydm.widgets.byte.PyDMByteIndicator # Open-loop tab - jog_forward_button: pydm.widgets.pushbutton.PyDMPushButton - jog_reverse_button: pydm.widgets.pushbutton.PyDMPushButton - clear_count_button: pydm.widgets.pushbutton.PyDMPushButton + jog_fwd_button: pydm.widgets.pushbutton.PyDMPushButton + jog_rev_button: pydm.widgets.pushbutton.PyDMPushButton + step_clear_cmd_button: pydm.widgets.pushbutton.PyDMPushButton total_step_count_rbv: pydm.widgets.label.PyDMLabel step_size_rbv: pydm.widgets.label.PyDMLabel step_size_set: pydm.widgets.line_edit.PyDMLineEdit @@ -29,8 +29,8 @@ class _SmarActDetailedUI(QtWidgets.QWidget): step_volt_set: pydm.widgets.line_edit.PyDMLineEdit step_freq_rbv: pydm.widgets.label.PyDMLabel step_freq_set: pydm.widgets.line_edit.PyDMLineEdit - scan_volt_rbv: pydm.widgets.label.PyDMLabel - scan_volt_set: pydm.widgets.line_edit.PyDMLineEdit + scan_move_rbv: pydm.widgets.label.PyDMLabel + scan_move_set: pydm.widgets.line_edit.PyDMLineEdit # Closed-loop tab home_forward_button: pydm.widgets.pushbutton.PyDMPushButton home_reverse_button: pydm.widgets.pushbutton.PyDMPushButton @@ -49,8 +49,8 @@ class _SmarActDetailedUI(QtWidgets.QWidget): closed_loop_freq_max_rbv: pydm.widgets.label.PyDMLabel closed_loop_freq_max_set: pydm.widgets.line_edit.PyDMLineEdit # Diagnostics tab - chan_temp_rbv: pydm.widgets.label.PyDMLabel - mod_temp_rbv: pydm.widgets.label.PyDMLabel + channel_temp_rbv: pydm.widgets.label.PyDMLabel + module_temp_rbv: pydm.widgets.label.PyDMLabel motor_load_rbv: pydm.widgets.label.PyDMLabel chan_error_rbv: pydm.widgets.label.PyDMLabel diag_closed_loop_freq_max_rbv: pydm.widgets.label.PyDMLabel @@ -62,10 +62,10 @@ class _SmarActDetailedUI(QtWidgets.QWidget): desc_set: pydm.widgets.line_edit.PyDMLineEdit egu_rbv: pydm.widgets.label.PyDMLabel egu_set: pydm.widgets.line_edit.PyDMLineEdit - ptype_rbv: pydm.widgets.label.PyDMLabel - ptype_set: pydm.widgets.line_edit.PyDMLineEdit - need_calib_led: pydm.widgets.byte.PyDMByteIndicator - calibrate_button: pydm.widgets.pushbutton.PyDMPushButton + pos_type_rbv: pydm.widgets.label.PyDMLabel + pos_type_set: pydm.widgets.line_edit.PyDMLineEdit + needs_calib_led: pydm.widgets.byte.PyDMByteIndicator + do_calib_button: pydm.widgets.pushbutton.PyDMPushButton low_limit_rbv: pydm.widgets.label.PyDMLabel low_limit_set: pydm.widgets.line_edit.PyDMLineEdit high_limit_rbv: pydm.widgets.label.PyDMLabel @@ -74,10 +74,10 @@ class _SmarActDetailedUI(QtWidgets.QWidget): ttzv_set: pydm.widgets.enum_combo_box.PyDMEnumComboBox ttzv_threshold_rbv: pydm.widgets.label.PyDMLabel ttzv_treshold_set: pydm.widgets.line_edit.PyDMLineEdit - logical_scale_offset_rbv: pydm.widgets.label.PyDMLabel - logical_scale_offset_set: pydm.widgets.line_edit.PyDMLineEdit - logical_scale_inversion_rbv: pydm.widgets.label.PyDMLabel - logical_scale_inversion_set: pydm.widgets.enum_combo_box.PyDMEnumComboBox + log_scale_offset_rbv: pydm.widgets.label.PyDMLabel + log_scale_offset_set: pydm.widgets.line_edit.PyDMLineEdit + log_scale_inversion_rbv: pydm.widgets.label.PyDMLabel + log_scale_inversion_set: pydm.widgets.enum_combo_box.PyDMEnumComboBox def_range_min_rbv: pydm.widgets.label.PyDMLabel def_range_min_set: pydm.widgets.line_edit.PyDMLineEdit def_range_max_rbv: pydm.widgets.label.PyDMLabel @@ -126,6 +126,7 @@ def post_typhos_init(self): """ self.fix_pvs() self.maybe_add_pico() + self.add_tool_tips() # Only start this timer if PicoScale exists if hasattr(self.device, 'pico_exists'): self.adj_prog_timer = QtCore.QTimer(parent=self) @@ -152,6 +153,41 @@ def fix_pvs(self): self.desc_set.set_channel(f'sig://{self.device.name}_description') self.egu_set.set_channel(f'sig://{self.device.name}_motor_egu') + def add_tool_tips(self): + """ + Add hutch_python tooltips to label widgets, if they exist. + """ + _signals = list(self.device.component_names) + # Let's deal with the subdevice signals afterwards + _signals.remove('open_loop') + _open_loop_signals = list(self.device.open_loop.component_names) + + def _get_tooltip(device: any, signal: str) -> str: + """ + Get the tooltip from the Ophyd.Device signal, if it exists. + """ + _dotted_name = getattr(device, signal).dotted_name + try: + _tooltip = getattr(type(device), signal).doc + except AttributeError: + _tooltip = '' + _tooltip = (_dotted_name + '
' + + round(1.75*len(_dotted_name))*'-' + '
' + + _tooltip) + return _tooltip + + for sig in (_signals + _open_loop_signals): + # Assume the QLabel's object name is standard form + _label_name = sig + '_label' + _device = self.device + # open_loop is a component device, nests differently + if sig in _open_loop_signals: + _device = self.device.open_loop + # Now let's add the tooltip for widgets that exist + if hasattr(self, _label_name): + _tooltip = _get_tooltip(_device, sig) + getattr(self, _label_name).setToolTip(_tooltip) + def find_pydm_names(self) -> list[str]: """ Find the object names for all PyDM objects using findChildren From f30adb7e711233c772b202a287af66d3849064ac Mon Sep 17 00:00:00 2001 From: Adam Berges <149725219+aberges-SLAC@users.noreply.github.com> Date: Wed, 12 Feb 2025 13:56:10 -0800 Subject: [PATCH 19/22] DOC: update release notes doc --- docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst b/docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst index e1c4ce55f1d..cb724cf8821 100644 --- a/docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst +++ b/docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst @@ -13,7 +13,7 @@ Library Features Device Features --------------- -- N/A +- Added long_name fields to various SmarAct classes in pcsdevices.epics_motor New Devices ----------- From cdd61885d8361ee20bc36c3b461223cc133d9d2b Mon Sep 17 00:00:00 2001 From: Adam Berges <149725219+aberges-SLAC@users.noreply.github.com> Date: Fri, 14 Feb 2025 10:28:11 -0800 Subject: [PATCH 20/22] Update docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst Co-authored-by: Zachary Lentz --- docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst b/docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst index cb724cf8821..0bda41a0d97 100644 --- a/docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst +++ b/docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst @@ -10,6 +10,7 @@ Library Features - Added SmarAct.detailed.ui screen - Accompanying SmarAct.detailed.py screen to handle closed loop and picoscale - Added SmarActTipTilt.embedded ui and py screens for operational support +- Designed and implemented huge improvements for all the SmarAct typhos screens, a monumental win for laser folk. Device Features --------------- From 77e7d927960cbf98538f4154c45dcd529007ddce Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Fri, 14 Feb 2025 10:58:01 -0800 Subject: [PATCH 21/22] MNT: Clean up ui_filename call and move pico timer to rightful place --- pcdsdevices/ui/SmarAct.detailed.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/pcdsdevices/ui/SmarAct.detailed.py b/pcdsdevices/ui/SmarAct.detailed.py index 96b680cb5ea..320cfa4a05a 100644 --- a/pcdsdevices/ui/SmarAct.detailed.py +++ b/pcdsdevices/ui/SmarAct.detailed.py @@ -2,7 +2,6 @@ import logging import re -from os import path import pydm from pydm import Display @@ -94,10 +93,8 @@ class SmarActDetailedWidget(Display, utils.TyphosBase): Custom widget for managing the SmarAct detailed screen """ ui: _SmarActDetailedUI - # Seems confusing, but really just cleans up the call to pydm for setting self.ui - ui_template = path.join(path.dirname(path.realpath(__file__)), 'SmarAct.detailed.ui') - def __init__(self, parent=None, ui_filename=ui_template, **kwargs): + def __init__(self, parent=None, ui_filename='SmarAct.detailed.ui', **kwargs): super().__init__(parent=parent, ui_filename=ui_filename) @property @@ -127,13 +124,6 @@ def post_typhos_init(self): self.fix_pvs() self.maybe_add_pico() self.add_tool_tips() - # Only start this timer if PicoScale exists - if hasattr(self.device, 'pico_exists'): - self.adj_prog_timer = QtCore.QTimer(parent=self) - self.adj_prog_timer.timeout.connect(self.update_adj_prog) - self.adj_prog_timer.setInterval(1000) - self.adj_prog_timer.start() - self._last_adj_prog = 0 def fix_pvs(self): """ @@ -225,6 +215,12 @@ def maybe_add_pico(self): if hasattr(self, 'picoscale'): # Don't add infite tabs please :] return + # Only start this timer if PicoScale exists + self.adj_prog_timer = QtCore.QTimer(parent=self) + self.adj_prog_timer.timeout.connect(self.update_adj_prog) + self.adj_prog_timer.setInterval(1000) + self.adj_prog_timer.start() + self._last_adj_prog = 0 # Grab all the pico related signals _pico_signals = [sig for sig in self.device.component_names if 'pico' in sig] self.pico_signal_dict = {} From 14baba14f7550f2f6f40fdf6141c6be8103de7d0 Mon Sep 17 00:00:00 2001 From: aberges-SLAC Date: Fri, 14 Feb 2025 10:59:00 -0800 Subject: [PATCH 22/22] MNT: Clean up ui_filename call --- pcdsdevices/ui/SmarActTipTilt.embedded.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pcdsdevices/ui/SmarActTipTilt.embedded.py b/pcdsdevices/ui/SmarActTipTilt.embedded.py index fd9a8614faa..f417ca5fb65 100644 --- a/pcdsdevices/ui/SmarActTipTilt.embedded.py +++ b/pcdsdevices/ui/SmarActTipTilt.embedded.py @@ -1,7 +1,6 @@ from __future__ import annotations import logging -from os import path from typing import Optional import ophyd @@ -29,10 +28,8 @@ class _SmarActTipTiltEmbeddedUI(QtWidgets.QWidget): class SmarActTipTiltWidget(Display, utils.TyphosBase): """Custom widget for controlling a tip-tilt with d-pad buttons""" ui: _SmarActTipTiltEmbeddedUI - # Seems confusing, but really just cleans up the call to pydm for setting self.ui - ui_template = path.join(path.dirname(path.realpath(__file__)), 'SmarActTipTilt.embedded.ui') - def __init__(self, parent=None, ui_filename=ui_template, **kwargs,): + def __init__(self, parent=None, ui_filename='SmarActTipTilt.embedded.ui', **kwargs,): super().__init__(parent=parent, ui_filename=ui_filename) self._omit_names = ['jog_fwd', 'jog_rev']