33from redliner .core .ui import DocPreview
44from redliner .extensions .fetcher import FETCHER_TYPES
55from redliner .extensions .source_doc import SrcDoc
6- from .diff import diff
7- import numpy as np
86from PyQt6 import QtCore as qtc , QtGui as qtg
97
8+ from .render import Renderer , RenderPage
9+
10+
11+
12+ def rgb_to_hex (red : int , green : int , blue : int , alpha : int | None = None ) -> str :
13+ return f"#{ hex (red )[2 :].zfill (2 )} { hex (green )[2 :].zfill (2 )} { hex (blue )[2 :].zfill (2 )} { alpha if alpha is not None else '' } "
14+
15+ def hex_to_rgb (val :str ) -> tuple :
16+ val = val .strip ().lower ()
17+ if val [0 ] == "#" :
18+ val = val [1 :]
19+ r1 , r2 , g1 , g2 , b1 , b2 = val
20+ return (int (r1 + r2 ,16 ), int (g1 + g2 ,16 ), int (b1 + b2 ,16 ))
21+
22+ class ColorButton (qtw .QPushButton ):
23+ signalColorChanged = qtc .pyqtSignal (str )
24+
25+ def __init__ (self , hex ):
26+ super ().__init__ ()
27+ self .hx = hex
28+ self .setStyleSheet (f"background-color:{ self .hx } " )
29+ self .setText (self .hx )
30+ self .clicked .connect (self .color_pick )
31+
32+ def color_pick (self ):
33+ color_pick = qtw .QColorDialog .getColor (qtg .QColor (self .hx ))
34+ r , g , b , a = color_pick .getRgb ()
35+ self .hx = rgb_to_hex (r , g , b )
36+ self .setStyleSheet (f"background-color:{ self .hx } " )
37+ self .setText (self .hx )
38+ self .signalColorChanged .emit (self .hx )
39+
40+
41+ class SettingsWidget (qtw .QWidget ):
42+ signalSettingsChanged = qtc .pyqtSignal ()
43+ def __init__ (self , items :list , width :int ):
44+ super ().__init__ ()
45+ self .pd = PersistentDict ()
46+ self ._l = qtw .QVBoxLayout (self )
47+ self ._l .setContentsMargins (0 ,0 ,0 ,0 )
48+ self ._l .setSpacing (2 )
49+ self .setFixedWidth (width )
50+ tgt_l = self ._l
51+ for row in items :
52+ if len (row ) == 1 :
53+ gb = qtw .QGroupBox (row [0 ])
54+ gb_l = qtw .QVBoxLayout (gb )
55+ self ._l .addWidget (gb )
56+ tgt_l = gb_l
57+ else :
58+ _type , key , name , * args = row
59+ val = self .pd [key ]
60+ _r = qtw .QWidget ()
61+ _l = qtw .QHBoxLayout (_r )
62+ _l .setContentsMargins (0 ,0 ,0 ,0 )
63+ _l .setSpacing (2 )
64+ lb = qtw .QLabel (name )
65+ _l .addWidget (lb )
66+ lb .setSizePolicy (qtw .QSizePolicy .Policy .Fixed , qtw .QSizePolicy .Policy .Fixed )
67+ if _type == "bool" :
68+ w = qtw .QCheckBox ()
69+ w .setChecked (val )
70+ w .stateChanged .connect (lambda * _ , _k = key , _w = w : self .set (_k , _w .isChecked ()))
71+ if _type == "spin" :
72+ w = qtw .QSpinBox ()
73+ w .setRange (* args )
74+ w .setValue (val )
75+ w .valueChanged .connect (lambda * _ , _k = key , _w = w : self .set (_k , _w .value ()))
76+ if _type == "color" :
77+ w = ColorButton (val )
78+ w .signalColorChanged .connect (lambda * _ , _k = key , _w = w : self .set (_k , _w .hx ))
79+ _l .addWidget (w )
80+ tgt_l .addWidget (_r )
81+ self ._l .addStretch ()
82+
83+ def set (self , key , value ):
84+ self .pd [key ] = value
85+ self .signalSettingsChanged .emit ()
86+
87+ def __getitem__ (self , key ):
88+ return self .pd [key ]
89+
1090class DocMan (qtw .QWidget ):
1191 def __init__ (self ):
1292 super ().__init__ ()
1393 self .pd = PersistentDict ()
14- self .pd .default ("scale_lo" , 0 )
15- self .pd .default ("scale_hi" , 255 )
94+ self .pd .default ("highlighter_en" , True )
95+ self .pd .default ("highlighter_size" , 4 )
96+ self .pd .default ("highlighter_sensitivity" , 100 )
1697 self .pd .default ("dpi" , 72 )
98+ self .pd .default ("removed_color" , "#D0A000" )
99+ self .pd .default ("added_color" , "#00A0D0" )
100+ self .pd .default ("highlighter_color" , "#F0F000" )
17101 self .lhs = None
18102 self .rhs = None
19103 self .click_side = "L"
@@ -40,30 +124,20 @@ def __init__(self):
40124 lhl .addWidget (self .lhp )
41125 rhl .addWidget (self .rhp )
42126
43- w_settings = qtw .QWidget ()
44- _l .addWidget (w_settings )
45- l_s = qtw .QGridLayout (w_settings )
46- self .sb_dpi = qtw .QSpinBox ()
47- self .sb_dpi .setRange (0 , 10000 )
48- self .sb_dpi .setValue (self .pd ["dpi" ])
49- self .sb_dpi .valueChanged .connect (self .regen )
50- l_s .addWidget (qtw .QLabel ("DPI" ), 0 , 0 )
51- l_s .addWidget (self .sb_dpi , 0 , 1 )
52- self .sb_lo = qtw .QSpinBox ()
53- self .sb_lo .setRange (0 , 254 )
54- self .sb_lo .setValue (self .pd ["scale_lo" ])
55- self .sb_lo .valueChanged .connect (self .regen )
56- l_s .addWidget (qtw .QLabel ("Lower Thresh" ), 1 , 0 )
57- l_s .addWidget (self .sb_lo , 1 , 1 )
58-
59- self .sb_hi = qtw .QSpinBox ()
60- self .sb_hi .setRange (1 , 255 )
61- self .sb_hi .setValue (self .pd ["scale_hi" ])
62- self .sb_hi .valueChanged .connect (self .regen )
63- l_s .addWidget (qtw .QLabel ("Upper Thresh" ), 2 , 0 )
64- l_s .addWidget (self .sb_hi , 2 , 1 )
65- l_s .setRowStretch (3 , 1 )
66- w_settings .setFixedWidth (196 )
127+ self .settings = SettingsWidget ([
128+ ["Render" ],
129+ ["spin" , "dpi" , "DPI" , 0 , 10000 ],
130+ ["color" , "removed_color" , "Removed Color" ],
131+ ["color" , "added_color" , "Added Color" ],
132+ ["Highlighter" ],
133+ ["bool" , "highlighter_en" , "Enabled" ],
134+ ["spin" , "highlighter_size" , "Size (px)" , 0 , 128 ],
135+ ["spin" , "highlighter_sensitivity" , "Sensitivity" , 0 , 100 ],
136+ ["color" , "highlighter_color" , "Highlight Color" ]
137+ ], 196 )
138+ self .settings .signalSettingsChanged .connect (self .regen )
139+ _l .addWidget (self .settings )
140+ self .renderer = Renderer ()
67141 self .preview = qtw .QLabel ()
68142 self .preview .setScaledContents (True )
69143 _l .addWidget (self .preview )
@@ -104,41 +178,50 @@ def doc_ready(self, doc: SrcDoc):
104178 self .rhp .set_doc (doc )
105179
106180 def regen (self ):
107- scale_lo = self .sb_lo .value ()
108- scale_hi = self .sb_hi .value ()
109- dpi = self .sb_dpi .value ()
110- if scale_hi <= scale_lo :
111- if scale_lo != self .pd ["scale_lo" ]:
112- # low scale was changed
113- scale_hi = scale_lo + 1
114- self .sb_hi .setValue (scale_hi )
115- else :
116- scale_lo = scale_hi - 1
117- self .sb_lo .setValue (scale_lo )
118- self .pd .update ({
119- "dpi" : dpi ,
120- "scale_lo" : scale_lo ,
121- "scale_hi" : scale_hi
122- })
181+
123182 lh_page = self .lhp .selectedIndexes ()
124- lh_data = None
125- rh_data = None
183+ rh_page = self . rhp . selectedIndexes ()
184+ render_page = RenderPage ()
126185 if lh_page :
127186 lh_page = lh_page [0 ].row ()
128- lh_data = self .lhs .raster (lh_page , dpi )
129- rh_page = self .rhp .selectedIndexes ()
187+ render_page .lhs = self .lhs .page (lh_page , self .settings ["dpi" ])
130188 if rh_page :
131189 rh_page = rh_page [0 ].row ()
132- rh_data = self .rhs .raster (rh_page , dpi )
133- if lh_data is not None :
134- if rh_data is not None :
135- im = diff (lh_data , rh_data , scale_lo , scale_hi )
136- else :
137- im = lh_data
138- elif rh_data is not None :
139- im = rh_data
140- else :
141- im = np .full ((256 , 256 , 3 ), (0 , 0 , 255 ), dtype = np .uint8 )
142- image = qtg .QImage (im , im .shape [1 ], im .shape [0 ], im .strides [0 ], qtg .QImage .Format .Format_RGB888 )
143- self .preview .setPixmap (qtg .QPixmap .fromImage (image ))
190+ render_page .rhs = self .rhs .page (rh_page , self .settings ["dpi" ])
191+ self .renderer .set_page (render_page )
192+ self .redraw ()
193+
194+ def resizeEvent (self , a0 ):
195+ super ().resizeEvent (a0 )
196+ self .redraw ()
197+
198+ def redraw (self , lh = True , rh = True ):
199+
200+ px = self .renderer .render (hex_to_rgb (self .settings ["added_color" ]),
201+ hex_to_rgb (self .settings ["removed_color" ]),
202+ hex_to_rgb (self .settings ["highlighter_color" ]),
203+ self .settings ["highlighter_en" ],
204+ 1 - self .settings ["highlighter_sensitivity" ]/ 100 ,
205+ self .settings ["highlighter_size" ],
206+ 0 ,
207+ 0 ,
208+ 1 ,
209+ 0 ,
210+ lh ,
211+ rh ,
212+ self .preview .width (),
213+ self .preview .height ())
214+ self .preview .setPixmap (qtg .QPixmap .fromImage (px ))
144215 self .preview .setMinimumSize (qtc .QSize (64 , 64 ))
216+
217+ def keyPressEvent (self , a0 ):
218+ if a0 .key () == qtc .Qt .Key .Key_Left :
219+ self .redraw (rh = False )
220+ if a0 .key () == qtc .Qt .Key .Key_Right :
221+ self .redraw (lh = False )
222+ super ().keyPressEvent (a0 )
223+
224+ def keyReleaseEvent (self , a0 ):
225+ self .redraw ()
226+
227+
0 commit comments