Repository: Qiskit/qiskit

Issue:
Classical conditions misalign in both ASCII and MPL output
### Environment

- **Qiskit Terra version**: 0.19.1
- **Python version**:  3.7.12
- **Operating system**: Ubuntu 18.04.5 LTS (Google Colab)


### What is happening?

I was testing my automatic code generation for Qiskit, and apparently the ~cphase~ controlled U1 gate with a classical condition will make the circuit misaligns in both of ASCII output and MPL output.


Screenshots:
```
q2_0: ─■───────■───────■───────■───────■───────■───────■───────■───────■──────»
       │U1(0)  │U1(0)  │U1(0)  │U1(0)  │U1(0)  │U1(0)  │U1(0)  │U1(0)  │U1(0) »
q2_1: ─■───────■───────■───────■───────■───────■───────■───────■───────■──────»
       ║       ║       ║       ║       ║       ║       ║       ║       ║      »
q2_2: ─╫───────╫───────╫───────╫───────╫───────╫───────╫───────╫───────╫──────»
      ┌╫─╨──┐ ┌╫─╨──┐ ┌╫─╨──┐ ┌╫─╨──┐ ┌╫─╨──┐ ┌╫─╨──┐ ┌╫─╨──┐ ┌╫─╨──┐ ┌╫─╨───┐»
c2: 5/╡║0x1 ╞═╡║0x3 ╞═╡║0x5 ╞═╡║0x7 ╞═╡║0x9 ╞═╡║0xb ╞═╡║0xd ╞═╡║0xf ╞═╡║0x11 ╞»
      └╫────┘ └╫────┘ └╫────┘ └╫────┘ └╫────┘ └╫────┘ └╫────┘ └╫────┘ └╫─────┘»
«                                                                         »
«q2_0: ─■───────■───────■───────■───────■───────■───────■───────────■─────»
«       │U1(0)  │U1(0)  │U1(0)  │U1(0)  │U1(0)  │U1(0)  │U1(0) ┌────┴────┐»
«q2_1: ─■───────■───────■───────■───────■───────■───────■──────┤ U2(0,0) ├»
«       ║       ║       ║       ║       ║       ║       ║      └────╥────┘»
«q2_2: ─╫───────╫───────╫───────╫───────╫───────╫───────╫───────────╫─────»
«      ┌╫─╨───┐┌╫─╨───┐┌╫─╨───┐┌╫─╨───┐┌╫─╨───┐┌╫─╨───┐┌╫─╨───┐  ┌──╨──┐  »
«c2: 5/╡║0x13 ╞╡║0x15 ╞╡║0x17 ╞╡║0x19 ╞╡║0x1b ╞╡║0x1d ╞╡║0x1f ╞══╡ 0x2 ╞══»
«      └╫─────┘└╫─────┘└╫─────┘└╫─────┘└╫─────┘└╫─────┘└╫─────┘  └─────┘  »
«                                                                        »
«q2_0: ─────■──────────■──────────■──────────■──────────■──────────■─────»
«      ┌────┴────┐┌────┴────┐┌────┴────┐┌────┴────┐┌────┴────┐┌────┴────┐»
«q2_1: ┤ U2(0,0) ├┤ U2(0,0) ├┤ U2(0,0) ├┤ U2(0,0) ├┤ U2(0,0) ├┤ U2(0,0) ├»
«      └────╥────┘└────╥────┘└────╥────┘└────╥────┘└────╥────┘└────╥────┘»
«q2_2: ─────╫──────────╫──────────╫──────────╫──────────╫──────────╫─────»
«        ┌──╨──┐    ┌──╨──┐    ┌──╨──┐    ┌──╨──┐    ┌──╨──┐    ┌──╨──┐  »
«c2: 5/══╡ 0x3 ╞════╡ 0x6 ╞════╡ 0x7 ╞════╡ 0xa ╞════╡ 0xb ╞════╡ 0xe ╞══»
«        └─────┘    └─────┘    └─────┘    └─────┘    └─────┘    └─────┘  »
«                                                                        »
«q2_0: ─────■──────────■──────────■──────────■──────────■──────────■─────»
«      ┌────┴────┐┌────┴────┐┌────┴────┐┌────┴────┐┌────┴────┐┌────┴────┐»
«q2_1: ┤ U2(0,0) ├┤ U2(0,0) ├┤ U2(0,0) ├┤ U2(0,0) ├┤ U2(0,0) ├┤ U2(0,0) ├»
«      └────╥────┘└────╥────┘└────╥────┘└────╥────┘└────╥────┘└────╥────┘»
«q2_2: ─────╫──────────╫──────────╫──────────╫──────────╫──────────╫─────»
«        ┌──╨──┐    ┌──╨───┐   ┌──╨───┐   ┌──╨───┐   ┌──╨───┐   ┌──╨───┐ »
«c2: 5/══╡ 0xf ╞════╡ 0x12 ╞═══╡ 0x13 ╞═══╡ 0x16 ╞═══╡ 0x17 ╞═══╡ 0x1a ╞═»
«        └─────┘    └──────┘   └──────┘   └──────┘   └──────┘   └──────┘ »
«                                       ┌───────────┐┌───────────┐       »
«q2_0: ─────■──────────■──────────■─────┤ U3(0,0,0) ├┤ U3(0,0,0) ├───X───»
«      ┌────┴────┐┌────┴────┐┌────┴────┐└─────┬─────┘└─────┬─────┘   │   »
«q2_1: ┤ U2(0,0) ├┤ U2(0,0) ├┤ U2(0,0) ├──────■────────────■─────────■───»
«      └────╥────┘└────╥────┘└────╥────┘      ║            ║         │   »
«q2_2: ─────╫──────────╫──────────╫───────────╫────────────╫─────────X───»
«        ┌──╨───┐   ┌──╨───┐   ┌──╨───┐    ┌──╨───┐     ┌──╨───┐  ┌──╨──┐»
«c2: 5/══╡ 0x1b ╞═══╡ 0x1e ╞═══╡ 0x1f ╞════╡ 0x15 ╞═════╡ 0x17 ╞══╡ 0x2 ╞»
«        └──────┘   └──────┘   └──────┘    └──────┘     └──────┘  └─────┘»
«                                                           
«q2_0: ───X──────X──────X──────X───────X───────X───────X────
«         │      │      │      │       │       │       │    
«q2_1: ───■──────■──────■──────■───────■───────■───────■────
«         │      │      │      │       │       │       │    
«q2_2: ───X──────X──────X──────X───────X───────X───────X────
«      ┌──╨──┐┌──╨──┐┌──╨──┐┌──╨───┐┌──╨───┐┌──╨───┐┌──╨───┐
«c2: 5/╡ 0x3 ╞╡ 0xa ╞╡ 0xb ╞╡ 0x12 ╞╡ 0x13 ╞╡ 0x1a ╞╡ 0x1b ╞
«      └─────┘└─────┘└─────┘└──────┘└──────┘└──────┘└──────┘
```

![image](https://user-images.githubusercontent.com/7108662/149796254-a6c64c72-0664-467a-8154-5b69959289ed.png)


### How can we reproduce the issue?

Using the source code below:

```python3
from numpy import pi, e as euler
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit.library.standard_gates import SdgGate, TdgGate, SXGate, RXGate, RYGate, RZGate, U1Gate, U2Gate, U3Gate, SwapGate, XGate, YGate, ZGate, HGate, PhaseGate, SGate, TGate

qr = QuantumRegister(3)
cr = ClassicalRegister(5)
qc = QuantumCircuit(qr, cr)

qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 1)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 3)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 5)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 7)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 9)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 11)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 13)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 15)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 17)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 19)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 21)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 23)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 25)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 27)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 29)
qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 31)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 2)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 3)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 6)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 7)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 10)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 11)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 14)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 15)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 18)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 19)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 22)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 23)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 26)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 27)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 30)
qc.append(U2Gate(0, 0).control(1), [0, 1]).c_if(cr, 31)
qc.append(U3Gate(0, 0, 0).control(1), [1, 0]).c_if(cr, 21)
qc.append(U3Gate(0, 0, 0).control(1), [1, 0]).c_if(cr, 23)
qc.append(SwapGate().control(1), [1, 0, 2]).c_if(cr, 2)
qc.append(SwapGate().control(1), [1, 0, 2]).c_if(cr, 3)
qc.append(SwapGate().control(1), [1, 0, 2]).c_if(cr, 10)
qc.append(SwapGate().control(1), [1, 0, 2]).c_if(cr, 11)
qc.append(SwapGate().control(1), [1, 0, 2]).c_if(cr, 18)
qc.append(SwapGate().control(1), [1, 0, 2]).c_if(cr, 19)
qc.append(SwapGate().control(1), [1, 0, 2]).c_if(cr, 26)
qc.append(SwapGate().control(1), [1, 0, 2]).c_if(cr, 27)

qc.draw() # For ASCII output
# qc.draw('mpl') # For MPL output
```

### What should happen?

They should align in a vertical manner.

### Any suggestions?

_No response_


Discussion:
There is special handling in each of the drawers for certain names in `ControlledGate`, so it's likely that the bug comes in there somewhere.  Notably, `u1` and `p` are handled specially, but `u2` is not; this seems to match with the output images up top.

For ease, a more minimal reproducer:
```python
In [15]: from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
    ...: from qiskit.circuit.library import U1Gate
    ...:
    ...: qr = QuantumRegister(3)
    ...: cr = ClassicalRegister(5)
    ...: qc = QuantumCircuit(qr, cr)
    ...:
    ...: qc.append(U1Gate(0).control(1), [1, 0]).c_if(cr, 1)
    ...: qc.draw()
```
```text
Out[15]:

q1_0: ─■──────
       │U1(0)
q1_1: ─■──────
       ║
q1_2: ─╫──────
      ┌╫─╨──┐
c1: 5/╡║0x1 ╞═
      └╫────┘
```
Oddly enough, I think these two problems are unrelated. The 'mpl' problem seems to be related to a miscalculation in the code that deals with folding. Since the 'text' problem appears with only 1 gate, it can't relate to that. I think it might have to do with the U1/P code as suggested, since it looks like the gate is aligned differently than the condition.

Resolving patch:
diff --git a/qiskit/visualization/text.py b/qiskit/visualization/text.py
--- a/qiskit/visualization/text.py
+++ b/qiskit/visualization/text.py
@@ -430,6 +430,7 @@ class Bullet(DirectOnQuWire):
 
     def __init__(self, top_connect="", bot_connect="", conditional=False, label=None, bottom=False):
         super().__init__("■")
+        self.conditional = conditional
         self.top_connect = top_connect
         self.bot_connect = "║" if conditional else bot_connect
         if label and bottom:
@@ -451,6 +452,7 @@ class OpenBullet(DirectOnQuWire):
 
     def __init__(self, top_connect="", bot_connect="", conditional=False, label=None, bottom=False):
         super().__init__("o")
+        self.conditional = conditional
         self.top_connect = top_connect
         self.bot_connect = "║" if conditional else bot_connect
         if label and bottom:
@@ -1033,6 +1035,10 @@ def _set_ctrl_state(self, node, conditional, ctrl_text, bottom):
         ctrl_qubits = node.qargs[:num_ctrl_qubits]
         cstate = f"{op.ctrl_state:b}".rjust(num_ctrl_qubits, "0")[::-1]
         for i in range(len(ctrl_qubits)):
+            # For sidetext gate alignment, need to set every Bullet with
+            # conditional on if there's a condition.
+            if op.condition is not None:
+                conditional = True
             if cstate[i] == "1":
                 gates.append(Bullet(conditional=conditional, label=ctrl_text, bottom=bottom))
             else:
@@ -1502,3 +1508,5 @@ def connect_with(self, wire_char):
             if label:
                 for affected_bit in affected_bits:
                     affected_bit.right_fill = len(label) + len(affected_bit.mid)
+                    if isinstance(affected_bit, (Bullet, OpenBullet)) and affected_bit.conditional:
+                        affected_bit.left_fill = len(label) + len(affected_bit.mid)


Test patch:
diff --git a/test/ipynb/mpl/circuit/references/sidetext_condition.png b/test/ipynb/mpl/circuit/references/sidetext_condition.png
new file mode 100644
Binary files /dev/null and b/test/ipynb/mpl/circuit/references/sidetext_condition.png differ
diff --git a/test/ipynb/mpl/circuit/test_circuit_matplotlib_drawer.py b/test/ipynb/mpl/circuit/test_circuit_matplotlib_drawer.py
--- a/test/ipynb/mpl/circuit/test_circuit_matplotlib_drawer.py
+++ b/test/ipynb/mpl/circuit/test_circuit_matplotlib_drawer.py
@@ -35,6 +35,7 @@
     ZGate,
     SGate,
     U1Gate,
+    CPhaseGate,
 )
 from qiskit.circuit.library import MCXVChain
 from qiskit.extensions import HamiltonianGate
@@ -863,6 +864,14 @@ def test_conditions_with_bits_reverse(self):
             circuit, cregbundle=False, reverse_bits=True, filename="cond_bits_reverse.png"
         )
 
+    def test_sidetext_with_condition(self):
+        """Test that sidetext gates align properly with conditions"""
+        qr = QuantumRegister(2, "q")
+        cr = ClassicalRegister(2, "c")
+        circuit = QuantumCircuit(qr, cr)
+        circuit.append(CPhaseGate(pi / 2), [qr[0], qr[1]]).c_if(cr[1], 1)
+        self.circuit_drawer(circuit, cregbundle=False, filename="sidetext_condition.png")
+
     def test_fold_with_conditions(self):
         """Test that gates with conditions draw correctly when folding"""
         qr = QuantumRegister(3)
diff --git a/test/python/visualization/references/test_latex_sidetext_condition.tex b/test/python/visualization/references/test_latex_sidetext_condition.tex
new file mode 100644
--- /dev/null
+++ b/test/python/visualization/references/test_latex_sidetext_condition.tex
@@ -0,0 +1,14 @@
+\documentclass[border=2px]{standalone}
+
+\usepackage[braket, qm]{qcircuit}
+\usepackage{graphicx}
+
+\begin{document}
+\scalebox{1.0}{
+\Qcircuit @C=1.0em @R=0.8em @!R { \\
+	 	\nghost{{q}_{0} :  } & \lstick{{q}_{0} :  } & \ctrl{1} & \dstick{\hspace{2.0em}\mathrm{P}\,(\mathrm{\frac{\pi}{2}})} \qw & \qw & \qw & \qw & \qw\\
+	 	\nghost{{q}_{1} :  } & \lstick{{q}_{1} :  } & \control \qw & \qw & \qw & \qw & \qw & \qw\\
+	 	\nghost{{c}_{0} :  } & \lstick{{c}_{0} :  } & \cw & \cw & \cw & \cw & \cw & \cw\\
+	 	\nghost{{c}_{1} :  } & \lstick{{c}_{1} :  } & \control \cw^(0.0){^{\mathtt{}}} \cwx[-2] & \cw & \cw & \cw & \cw & \cw\\
+\\ }}
+\end{document}
\ No newline at end of file
diff --git a/test/python/visualization/test_circuit_latex.py b/test/python/visualization/test_circuit_latex.py
--- a/test/python/visualization/test_circuit_latex.py
+++ b/test/python/visualization/test_circuit_latex.py
@@ -22,7 +22,7 @@
 from qiskit.visualization import circuit_drawer
 from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, transpile
 from qiskit.test.mock import FakeTenerife
-from qiskit.circuit.library import XGate, MCXGate, RZZGate, SwapGate, DCXGate
+from qiskit.circuit.library import XGate, MCXGate, RZZGate, SwapGate, DCXGate, CPhaseGate
 from qiskit.extensions import HamiltonianGate
 from qiskit.circuit import Parameter, Qubit, Clbit
 from qiskit.circuit.library import IQP
@@ -645,6 +645,16 @@ def test_conditions_with_bits_reverse(self):
         )
         self.assertEqualToReference(filename)
 
+    def test_sidetext_with_condition(self):
+        """Test that sidetext gates align properly with a condition"""
+        filename = self._get_resource_path("test_latex_sidetext_condition.tex")
+        qr = QuantumRegister(2, "q")
+        cr = ClassicalRegister(2, "c")
+        circuit = QuantumCircuit(qr, cr)
+        circuit.append(CPhaseGate(pi / 2), [qr[0], qr[1]]).c_if(cr[1], 1)
+        circuit_drawer(circuit, cregbundle=False, filename=filename, output="latex_source")
+        self.assertEqualToReference(filename)
+
 
 if __name__ == "__main__":
     unittest.main(verbosity=2)
diff --git a/test/python/visualization/test_circuit_text_drawer.py b/test/python/visualization/test_circuit_text_drawer.py
--- a/test/python/visualization/test_circuit_text_drawer.py
+++ b/test/python/visualization/test_circuit_text_drawer.py
@@ -635,6 +635,81 @@ def test_text_cp(self):
         circuit.append(CPhaseGate(pi / 2), [qr[2], qr[0]])
         self.assertEqual(str(_text_circuit_drawer(circuit)), expected)
 
+    def test_text_cu1_condition(self):
+        """Test cu1 with condition"""
+        expected = "\n".join(
+            [
+                "                      ",
+                "q_0: ────────■────────",
+                "             │U1(π/2) ",
+                "q_1: ────────■────────",
+                "             ║        ",
+                "q_2: ────────╫────────",
+                "             ║        ",
+                "c_0: ════════╬════════",
+                "             ║        ",
+                "c_1: ════════■════════",
+                "                      ",
+                "c_2: ═════════════════",
+                "                      ",
+            ]
+        )
+        qr = QuantumRegister(3, "q")
+        cr = ClassicalRegister(3, "c")
+        circuit = QuantumCircuit(qr, cr)
+        circuit.append(CU1Gate(pi / 2), [qr[0], qr[1]]).c_if(cr[1], 1)
+        self.assertEqual(str(_text_circuit_drawer(circuit, initial_state=False)), expected)
+
+    def test_text_rzz_condition(self):
+        """Test rzz with condition"""
+        expected = "\n".join(
+            [
+                "                      ",
+                "q_0: ────────■────────",
+                "             │ZZ(π/2) ",
+                "q_1: ────────■────────",
+                "             ║        ",
+                "q_2: ────────╫────────",
+                "             ║        ",
+                "c_0: ════════╬════════",
+                "             ║        ",
+                "c_1: ════════■════════",
+                "                      ",
+                "c_2: ═════════════════",
+                "                      ",
+            ]
+        )
+        qr = QuantumRegister(3, "q")
+        cr = ClassicalRegister(3, "c")
+        circuit = QuantumCircuit(qr, cr)
+        circuit.append(RZZGate(pi / 2), [qr[0], qr[1]]).c_if(cr[1], 1)
+        self.assertEqual(str(_text_circuit_drawer(circuit, initial_state=False)), expected)
+
+    def test_text_cp_condition(self):
+        """Test cp with condition"""
+        expected = "\n".join(
+            [
+                "                    ",
+                "q_0: ───────■───────",
+                "            │P(π/2) ",
+                "q_1: ───────■───────",
+                "            ║       ",
+                "q_2: ───────╫───────",
+                "            ║       ",
+                "c_0: ═══════╬═══════",
+                "            ║       ",
+                "c_1: ═══════■═══════",
+                "                    ",
+                "c_2: ═══════════════",
+                "                    ",
+            ]
+        )
+        qr = QuantumRegister(3, "q")
+        cr = ClassicalRegister(3, "c")
+        circuit = QuantumCircuit(qr, cr)
+        circuit.append(CPhaseGate(pi / 2), [qr[0], qr[1]]).c_if(cr[1], 1)
+        self.assertEqual(str(_text_circuit_drawer(circuit, initial_state=False)), expected)
+
     def test_text_cu1_reverse_bits(self):
         """cu1 drawing with reverse_bits"""
         expected = "\n".join(