Skip to content

Commit 6aa17c3

Browse files
fix hatching
1 parent e8405c8 commit 6aa17c3

File tree

5 files changed

+107
-79
lines changed

5 files changed

+107
-79
lines changed

src/cellpose_omni/gui/MainWindowModules/buttons.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,10 @@ def make_buttons(self):
893893
# ---- drawing area ---- #
894894
self.win = pg.GraphicsLayoutWidget()
895895
self.win.viewport().setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, False)
896+
# self.win.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
897+
# self.win.setAutoFillBackground(False)
898+
899+
896900
self.l0.addWidget(self.win, 0, TOOLBAR_WIDTH+1, b, 3*b)
897901
self.win.scene().sigMouseClicked.connect(lambda event: self.plot_clicked(event))
898902
self.win.scene().sigMouseMoved.connect(lambda pos: self.mouse_moved(pos))

src/cellpose_omni/gui/MainWindowModules/image.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def make_viewbox(self):
6868
self.img.autoDownsample = False
6969

7070
self.hist = guiparts.HistLUT(image=self.img,orientation='horizontal',gradientPosition='bottom')
71+
self.gradient = self.hist.gradient
7172
self.opacity_effect = QtWidgets.QGraphicsOpacityEffect()
7273
self.hist.setGraphicsEffect(self.opacity_effect)
7374
self.win.addItem(self.hist,col=0,row=1)

src/cellpose_omni/gui/MainWindowModules/theme.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99

1010
import pyqtgraph as pg
11+
import numpy as np
1112

1213

1314

@@ -92,7 +93,8 @@ def set_hist_colors(self):
9293
self.hist.axis.style['showValues'] = 0
9394
self.hist.axis.style['tickAlpha'] = 0
9495
self.hist.axis.logMode = 1
95-
# self.hist.plot.opts['antialias'] = 1
96+
self.hist.plot.opts['antialias'] = 1
97+
# self.hist.plot.opts['stepMode'] = True
9698
# self.hist.setLevels(min=0, max=255)
9799

98100
# policy = QtWidgets.QSizePolicy()
@@ -109,7 +111,3 @@ def set_tick_hover_color(self):
109111
def set_button_color(self):
110112
color = '#eeeeee' if self.darkmode else '#888888'
111113
self.ModelButton.setStyleSheet('border: 2px solid {};'.format(color))
112-
113-
114-
115-

src/cellpose_omni/gui/gui.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616

1717
import pyqtgraph as pg
1818
pg.setConfigOptions(useOpenGL=True)
19+
# pg.setConfigOptions(enableExperimental=True)
1920

2021
# handle the "Painter path exceeds +/-32767 pixels." warning
2122
from PyQt6.QtGui import QSurfaceFormat
2223
fmt = QSurfaceFormat()
2324
fmt.setStencilBufferSize(8) # 8-bit stencil
24-
fmt.setSamples(0) # Disable multisampling to avoid stipple artifacts - doesn't help
2525
QSurfaceFormat.setDefaultFormat(fmt)
2626

2727
os.environ['QT_AUTO_SCREEN_SCALE_FACTOR'] = '1'
@@ -116,9 +116,12 @@ def __init__(self, size, dpi, pxr, clipboard, image=None):
116116
self.class_sources = {} # maps (module_name, class_name) to the class's source code
117117
# Discover & load all submodules
118118
self.modules = self.load_all_submodules()
119+
print('modules',self.modules)
119120
self.patch_all_submodules()
120121

121122

123+
124+
122125
# --- New: Register external modules ---
123126
self.register_external_modules()
124127

@@ -222,9 +225,7 @@ def __init__(self, size, dpi, pxr, clipboard, image=None):
222225
self.linksEditorAction.setChecked(False)
223226
self.linksEditorAction.triggered.connect(self.toggleLinksDock)
224227

225-
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
226-
self.setAutoFillBackground(False)
227-
228+
228229
self.setAcceptDrops(True)
229230
self.win.show()
230231
self.show()

src/cellpose_omni/gui/guiparts.py

Lines changed: 94 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from PyQt6.QtGui import QPainter
66
from PyQt6.QtWidgets import QApplication, QRadioButton, QWidget, QDialog, QButtonGroup, QSlider, QStyle, QStyleOptionSlider, QGridLayout, QPushButton, QLabel, QLineEdit, QDialogButtonBox, QComboBox
77
import pyqtgraph as pg
8-
from pyqtgraph import Point
8+
from pyqtgraph.Point import Point
99
import numpy as np
1010
import os
1111
from omnipose.core import affinity_to_boundary
@@ -1214,7 +1214,6 @@ def __pixelPosToRangeValue(self, pos):
12141214
opt.upsideDown)
12151215

12161216

1217-
12181217
class HistLUT(pg.HistogramLUTItem):
12191218
# sigLookupTableChanged = QtCore.pyqtSignal(object)
12201219
# sigLevelsChanged = QtCore.pyqtSignal(object)
@@ -1232,12 +1231,15 @@ def __init__(self, image=None, fillHistogram=True, levelMode='mono',
12321231
self._orig_mousePressEvent = super().mousePressEvent
12331232
self._orig_mouseMoveEvent = super().mouseMoveEvent
12341233
self._orig_mouseReleaseEvent = super().mouseReleaseEvent
1234+
self._orig_paint = super().paint
1235+
12351236

12361237
self.imageitem = image
12371238
self._view = 0
12381239
# Make sure there's a place to store full item states for each view.
12391240
if not hasattr(self, 'view_states'):
12401241
self.view_states = {}
1242+
12411243

12421244
# Connect signals for color stops...
12431245
if hasattr(self.gradient, 'sigGradientChanged'):
@@ -1248,12 +1250,22 @@ def __init__(self, image=None, fillHistogram=True, levelMode='mono',
12481250
# ...and region/levels so we capture user changes to min/max handles.
12491251
self.region.sigRegionChanged.connect(self._on_region_changed)
12501252
self.region.sigRegionChangeFinished.connect(self._on_region_changed)
1251-
1253+
1254+
# def paint(self, painter, option, widget=None):
1255+
# old_brush = self.gradient.gradRect.brush()
1256+
# if getattr(self, 'discrete_mode', False):
1257+
# # In discrete mode, skip the default overlay drawing.
1258+
# # return
1259+
# self.gradient.gradRect.setBrush(QtGui.QBrush(QtCore.Qt.BrushStyle.NoBrush))
1260+
# # Otherwise, call the original painting.
1261+
# self._orig_paint(painter, option, widget)
1262+
# self.gradient.gradRect.setBrush(old_brush)
1263+
# self.gradient.backgroundRect.hide() # the cause of the hatching pattern
1264+
1265+
12521266
def set_view(self, v, preset=None, default_cmaps=None):
12531267
self._view = v
12541268
state = self.view_states.get(v) # This is the *full item* state, not just gradient.
1255-
1256-
12571269

12581270
if state is not None:
12591271
self.restoreState(state) # calls HistogramLUTItem.restoreState(state)
@@ -1293,7 +1305,7 @@ def setDiscreteMode(self, discrete: bool, n_bands: int = 5):
12931305
if st.get('mode', '').lower() == 'hsv':
12941306
st['mode'] = 'rgb'
12951307
self.gradient.restoreState(st)
1296-
# Save original paint method if not already saved.
1308+
# Save original paint method if not already saved.
12971309
if not hasattr(self.gradient, '_original_paint'):
12981310
self.gradient._original_paint = self.gradient.paint
12991311
# Store the number of discrete bands.
@@ -1304,18 +1316,13 @@ def setDiscreteMode(self, discrete: bool, n_bands: int = 5):
13041316
self.gradient.paint = self._discrete_gradient_paint.__get__(self.gradient, type(self.gradient))
13051317
# Hide the continuous gradient: disable gradRect painting and caching.
13061318
self.gradient.gradRect.hide()
1307-
self.gradient.setCacheMode(QGraphicsItem.CacheMode.NoCache)
1308-
self.gradient.gradRect.setCacheMode(QGraphicsItem.CacheMode.NoCache)
1309-
self.gradient.gradRect.setFlag(QGraphicsItem.GraphicsItemFlag.ItemHasNoContents, True)
13101319

1311-
self.gradient.update()
13121320
else:
13131321
if hasattr(self.gradient, '_original_paint'):
13141322
self.gradient.paint = self.gradient._original_paint
13151323
self.gradient.gradRect.show()
1316-
self.gradient.gradRect.setFlag(QGraphicsItem.GraphicsItemFlag.ItemHasNoContents, False)
13171324

1318-
self.gradient.update()
1325+
self.gradient.update()
13191326

13201327

13211328
def _discrete_gradient_paint(self, painter, opt, widget=None):
@@ -1326,10 +1333,9 @@ def _discrete_gradient_paint(self, painter, opt, widget=None):
13261333
between adjacent bands to cover any rounding gaps.
13271334
"""
13281335
painter.save()
1329-
painter.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing, False)
1330-
painter.setRenderHint(QtGui.QPainter.RenderHint.SmoothPixmapTransform, False)
1331-
painter.setCompositionMode(QtGui.QPainter.CompositionMode_Source)
1332-
# painter.setPen(Qt.NoPen)
1336+
painter.setPen(Qt.NoPen)
1337+
# painter.setPen(self.tickPen)
1338+
13331339

13341340
# Get the drawing rectangle from gradRect as an integer QRect.
13351341
rect = self.gradRect.rect().toRect()
@@ -1349,7 +1355,9 @@ def _discrete_gradient_paint(self, painter, opt, widget=None):
13491355
bandRect = QtCore.QRect(x, rect.top(), w + 1, rect.height())
13501356
else:
13511357
bandRect = QtCore.QRect(x, rect.top(), w, rect.height())
1352-
frac = (i + 0.5) / nBands
1358+
# frac = (i + 0.5) / nBands
1359+
frac = (i ) / (nBands-1)
1360+
13531361
qcol = self._parent_histlut._sample_colormap(frac)
13541362
painter.setBrush(QtGui.QBrush(qcol, Qt.BrushStyle.SolidPattern))
13551363
painter.drawRect(bandRect)
@@ -1373,8 +1381,15 @@ def _discrete_gradient_paint(self, painter, opt, widget=None):
13731381
painter.drawRect(bandRect)
13741382
y += h
13751383

1384+
# drow the border
1385+
pen = self.tickPen
1386+
painter.setPen(pen)
1387+
painter.setBrush(QtCore.Qt.BrushStyle.NoBrush)
1388+
painter.drawRect(rect)
1389+
13761390
painter.restore()
1377-
1391+
1392+
13781393
def _sample_colormap(self, fraction: float) -> QtGui.QColor:
13791394
"""
13801395
Sample the current colormap at the given fraction (0 to 1) and return a fully opaque QColor.
@@ -1395,7 +1410,7 @@ def _sample_colormap(self, fraction: float) -> QtGui.QColor:
13951410
a = 255
13961411
else:
13971412
r, g, b, a = entry
1398-
return QtGui.QColor(r, g, b, 255)
1413+
return QtGui.QColor(r, g, b, a)
13991414

14001415
def _on_gradient_changed(self):
14011416
# Called when the user moves color stops in the gradient
@@ -1459,54 +1474,65 @@ def autoRange(self):
14591474
self.region.setRegion((min_val, max_val)) # sets the slider region
14601475

14611476

1462-
# def paint(self, p, *args):
1463-
# # paint the bounding edges of the region item and gradient item with lines
1464-
# # connecting them
1465-
# if self.levelMode != 'mono' or not self.region.isVisible():
1466-
# return
1467-
# print('ddd')
1468-
# pen = self.region.lines[0].pen
1469-
1470-
# mn, mx = self.getLevels()
1471-
# vbc = self.vb.viewRect().center()
1472-
# gradRect = self.gradient.mapRectToParent(self.gradient.gradRect.rect())
1473-
# if self.orientation == 'vertical':
1474-
# p1mn = self.vb.mapFromViewToItem(self, Point(vbc.x(), mn)) + Point(0, 5)
1475-
# p1mx = self.vb.mapFromViewToItem(self, Point(vbc.x(), mx)) - Point(0, 5)
1476-
# if self.gradientPosition == 'right':
1477-
# p2mn = gradRect.bottomLeft()
1478-
# p2mx = gradRect.topLeft()
1479-
# else:
1480-
# p2mn = gradRect.bottomRight()
1481-
# p2mx = gradRect.topRight()
1482-
# else:
1483-
# p1mn = self.vb.mapFromViewToItem(self, Point(mn, vbc.y())) - Point(5, 0)
1484-
# p1mx = self.vb.mapFromViewToItem(self, Point(mx, vbc.y())) + Point(5, 0)
1485-
# if self.gradientPosition == 'bottom':
1486-
# p2mn = gradRect.topLeft()
1487-
# p2mx = gradRect.topRight()
1488-
# else:
1489-
# p2mn = gradRect.bottomLeft()
1490-
# p2mx = gradRect.bottomRight()
1491-
1492-
# p.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing)
1493-
1494-
# for pen in [pen]: #get rid of first entry, shadow of some sort
1495-
# p.setPen(pen)
1496-
1497-
# # lines from the linear region item bounds to the gradient item bounds
1498-
# p.drawLine(p1mn, p2mn)
1499-
# p.drawLine(p1mx, p2mx)
1500-
1501-
# # lines bounding the edges of the gradient item
1502-
# if self.orientation == 'vertical':
1503-
# p.drawLine(gradRect.topLeft(), gradRect.topRight())
1504-
# p.drawLine(gradRect.bottomLeft(), gradRect.bottomRight())
1505-
# else:
1506-
# p.drawLine(gradRect.topLeft(), gradRect.bottomLeft())
1507-
# p.drawLine(gradRect.topRight(), gradRect.bottomRight())
1508-
1477+
def paint(self, p, *args):
1478+
# paint the bounding edges of the region item and gradient item with lines
1479+
# connecting them
1480+
if self.levelMode != 'mono' or not self.region.isVisible():
1481+
return
15091482

1483+
pen = self.region.lines[0].pen
1484+
1485+
mn, mx = self.getLevels()
1486+
vbc = self.vb.viewRect().center()
1487+
gradRect = self.gradient.mapRectToParent(self.gradient.gradRect.rect())
1488+
if self.orientation == 'vertical':
1489+
p1mn = self.vb.mapFromViewToItem(self, Point(vbc.x(), mn)) + Point(0, 5)
1490+
p1mx = self.vb.mapFromViewToItem(self, Point(vbc.x(), mx)) - Point(0, 5)
1491+
if self.gradientPosition == 'right':
1492+
p2mn = gradRect.bottomLeft()
1493+
p2mx = gradRect.topLeft()
1494+
else:
1495+
p2mn = gradRect.bottomRight()
1496+
p2mx = gradRect.topRight()
1497+
else:
1498+
p1mn = self.vb.mapFromViewToItem(self, Point(mn, vbc.y())) - Point(5, 0)
1499+
p1mx = self.vb.mapFromViewToItem(self, Point(mx, vbc.y())) + Point(5, 0)
1500+
if self.gradientPosition == 'bottom':
1501+
p2mn = gradRect.topLeft()
1502+
p2mx = gradRect.topRight()
1503+
else:
1504+
p2mn = gradRect.bottomLeft()
1505+
p2mx = gradRect.bottomRight()
1506+
1507+
p.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing, True)
1508+
p.setRenderHint(QtGui.QPainter.RenderHint.SmoothPixmapTransform, True)
1509+
1510+
for pen in [pen]: #get rid of first entry, shadow of some sort
1511+
p.setPen(pen)
1512+
1513+
# lines from the linear region item bounds to the gradient item bounds
1514+
p.drawLine(p1mn, p2mn)
1515+
p.drawLine(p1mx, p2mx)
1516+
1517+
# lines bounding the edges of the gradient item
1518+
if self.orientation == 'vertical':
1519+
p.drawLine(gradRect.topLeft(), gradRect.topRight())
1520+
p.drawLine(gradRect.bottomLeft(), gradRect.bottomRight())
1521+
else:
1522+
p.drawLine(gradRect.topLeft(), gradRect.bottomLeft())
1523+
p.drawLine(gradRect.topRight(), gradRect.bottomRight())
1524+
1525+
# def paint(self, painter, option, widget=None):
1526+
old_brush = self.gradient.gradRect.brush()
1527+
if getattr(self, 'discrete_mode', False):
1528+
# In discrete mode, skip the default overlay drawing.
1529+
# return
1530+
self.gradient.gradRect.setBrush(QtGui.QBrush(QtCore.Qt.BrushStyle.NoBrush))
1531+
# Otherwise, call the original painting.
1532+
self._orig_paint(p, *args) # painter, option, widget)
1533+
self.gradient.gradRect.setBrush(old_brush)
1534+
self.gradient.backgroundRect.hide() # the cause of the hatching pattern
1535+
15101536

15111537

15121538

@@ -1557,17 +1583,15 @@ def update_icons(self):
15571583
def _emit_toggled(self):
15581584
"""Emit the toggled signal when the button is clicked."""
15591585
self.toggled.emit(self.isChecked())
1560-
1561-
import numpy as np
1562-
import pyqtgraph as pg
1586+
1587+
15631588
from pyqtgraph import GraphicsObject
15641589
from PyQt6.QtWidgets import QGraphicsItem
15651590
from PyQt6.QtGui import QPainter
15661591
from PyQt6.QtCore import QRectF, Qt
15671592

15681593
import OpenGL.GL as gl
15691594

1570-
15711595
class GLPixelGridOverlay(GraphicsObject):
15721596
"""
15731597
A QGraphicsItem that draws lines between centers of adjacent pixels

0 commit comments

Comments
 (0)