286
286
# Precisely matches lxdialog's set_bluetitle_theme() and set_classic_theme()
287
287
"linux" : """
288
288
path=fg:white,bg:blue,bold
289
- separator=fg:black ,bg:white
289
+ separator=fg:white ,bg:blue
290
290
list=fg:black,bg:white
291
291
selection=fg:white,bg:blue,bold
292
292
inv-list=fg:red,bg:white
293
293
inv-selection=fg:red,bg:blue,bold
294
- help=fg:black ,bg:white
294
+ help=fg:white ,bg:blue
295
295
show-help=fg:black,bg:white
296
296
frame=fg:white,bg:blue,bold
297
297
body=fg:black,bg:white
@@ -999,6 +999,10 @@ def _init():
999
999
1000
1000
_init_styles ()
1001
1001
1002
+ # Set stdscr background to match main list style
1003
+ # This ensures areas not covered by subwindows have correct background
1004
+ _stdscr .bkgd (' ' , _style .get ("list" , 0 ))
1005
+
1002
1006
# Hide the cursor
1003
1007
_safe_curs_set (0 )
1004
1008
@@ -1044,17 +1048,24 @@ def _resize_main():
1044
1048
1045
1049
screen_height , screen_width = _stdscr .getmaxyx ()
1046
1050
1047
- _path_win .resize (1 , screen_width )
1048
- _top_sep_win .resize (1 , screen_width )
1049
- _bot_sep_win .resize (1 , screen_width )
1050
-
1051
1051
help_win_height = _SHOW_HELP_HEIGHT if _show_help else \
1052
1052
len (_MAIN_HELP_LINES )
1053
1053
1054
+ # Screen layout:
1055
+ # Row 0: _path_win, Row 1: _top_sep_win, Row 2+: _menu_win
1056
+ # Row (2+menu_win_height): _bot_sep_win
1057
+ # Row (2+menu_win_height+1): _help_win
1058
+ # Total: 1 + 1 + menu_win_height + 1 + help_win_height = screen_height
1054
1059
menu_win_height = screen_height - help_win_height - 3
1060
+ menu_win_width = screen_width
1061
+
1062
+ _path_win .resize (1 , screen_width )
1063
+ _top_sep_win .resize (1 , menu_win_width )
1055
1064
1056
1065
if menu_win_height >= 1 :
1057
- _menu_win .resize (menu_win_height , screen_width )
1066
+ _menu_win .resize (menu_win_height , menu_win_width )
1067
+ _bot_sep_win .resize (1 , menu_win_width )
1068
+ # _help_win uses full screen width for blue background to extend to right edge
1058
1069
_help_win .resize (help_win_height , screen_width )
1059
1070
1060
1071
_top_sep_win .mvwin (1 , 0 )
@@ -1363,8 +1374,10 @@ def _draw_main():
1363
1374
_safe_hline (_top_sep_win , 0 , 4 , curses .ACS_UARROW , _N_SCROLL_ARROWS )
1364
1375
1365
1376
# Add the 'mainmenu' text as the title, centered at the top
1377
+ # Use _top_sep_win width instead of term_width for correct centering
1378
+ top_sep_width = _width (_top_sep_win )
1366
1379
_safe_addstr (_top_sep_win ,
1367
- 0 , max ((term_width - len (_kconf .mainmenu_text ))// 2 , 0 ),
1380
+ 0 , max ((top_sep_width - len (_kconf .mainmenu_text ))// 2 , 0 ),
1368
1381
_kconf .mainmenu_text )
1369
1382
1370
1383
_top_sep_win .noutrefresh ()
@@ -1752,12 +1765,22 @@ def edit_width():
1752
1765
# Horizontal scroll offset
1753
1766
hscroll = max (i - edit_width () + 1 , 0 )
1754
1767
1768
+ # Create shadow windows once
1769
+ win_y , win_x = win .getbegyx ()
1770
+ win_height , win_width = win .getmaxyx ()
1771
+ bottom_shadow , right_shadow = _create_shadow_windows (win_y , win_x , win_height , win_width )
1772
+
1755
1773
while True :
1756
1774
# Draw the "main" display with the menu, etc., so that resizing still
1757
1775
# works properly. This is like a stack of windows, only hardcoded for
1758
1776
# now.
1759
1777
_draw_main ()
1778
+
1760
1779
_draw_input_dialog (win , title , info_lines , s , i , hscroll )
1780
+
1781
+ # Refresh shadow windows after dialog window to ensure they're on top
1782
+ _refresh_shadow_windows (bottom_shadow , right_shadow )
1783
+
1761
1784
curses .doupdate ()
1762
1785
1763
1786
@@ -1767,6 +1790,10 @@ def edit_width():
1767
1790
# Resize the main display too. The dialog floats above it.
1768
1791
_resize_main ()
1769
1792
_resize_input_dialog (win , title , info_lines )
1793
+ # Recreate shadow windows with new dialog size
1794
+ win_y , win_x = win .getbegyx ()
1795
+ win_height , win_width = win .getmaxyx ()
1796
+ bottom_shadow , right_shadow = _create_shadow_windows (win_y , win_x , win_height , win_width )
1770
1797
1771
1798
elif c == "\n " :
1772
1799
_safe_curs_set (0 )
@@ -1806,13 +1833,6 @@ def _resize_input_dialog(win, title, info_lines):
1806
1833
def _draw_input_dialog (win , title , info_lines , s , i , hscroll ):
1807
1834
edit_width = _width (win ) - 4
1808
1835
1809
- # Get window position and size for shadow
1810
- win_y , win_x = win .getbegyx ()
1811
- win_height , win_width = win .getmaxyx ()
1812
-
1813
- # Draw shadow on stdscr first
1814
- _draw_shadow (_stdscr , win_y , win_x , win_height , win_width )
1815
-
1816
1836
win .erase ()
1817
1837
1818
1838
# Note: Perhaps having a separate window for the input field would be nicer
@@ -1968,10 +1988,20 @@ def _key_dialog(title, text, keys):
1968
1988
1969
1989
_resize_key_dialog (win , text )
1970
1990
1991
+ # Create shadow windows once
1992
+ win_y , win_x = win .getbegyx ()
1993
+ win_height , win_width = win .getmaxyx ()
1994
+ bottom_shadow , right_shadow = _create_shadow_windows (win_y , win_x , win_height , win_width )
1995
+
1971
1996
while True :
1972
1997
# See _input_dialog()
1973
1998
_draw_main ()
1999
+
1974
2000
_draw_key_dialog (win , title , text )
2001
+
2002
+ # Refresh shadow windows after dialog window to ensure they're on top
2003
+ _refresh_shadow_windows (bottom_shadow , right_shadow )
2004
+
1975
2005
curses .doupdate ()
1976
2006
1977
2007
@@ -1981,6 +2011,10 @@ def _key_dialog(title, text, keys):
1981
2011
# Resize the main display too. The dialog floats above it.
1982
2012
_resize_main ()
1983
2013
_resize_key_dialog (win , text )
2014
+ # Recreate shadow windows with new dialog size
2015
+ win_y , win_x = win .getbegyx ()
2016
+ win_height , win_width = win .getmaxyx ()
2017
+ bottom_shadow , right_shadow = _create_shadow_windows (win_y , win_x , win_height , win_width )
1984
2018
1985
2019
elif c == "\x1B " : # \x1B = ESC
1986
2020
return None
@@ -2007,13 +2041,6 @@ def _resize_key_dialog(win, text):
2007
2041
2008
2042
2009
2043
def _draw_key_dialog (win , title , text ):
2010
- # Get window position and size for shadow
2011
- win_y , win_x = win .getbegyx ()
2012
- win_height , win_width = win .getmaxyx ()
2013
-
2014
- # Draw shadow on stdscr first
2015
- _draw_shadow (_stdscr , win_y , win_x , win_height , win_width )
2016
-
2017
2044
win .erase ()
2018
2045
2019
2046
# Draw the frame first
@@ -2060,16 +2087,15 @@ def _button_dialog(title, text, buttons, default_button=0):
2060
2087
win .mvwin ((_height (_stdscr ) - win_height )// 2 ,
2061
2088
(_width (_stdscr ) - win_width )// 2 )
2062
2089
2090
+ # Create shadow windows once
2091
+ win_y , win_x = win .getbegyx ()
2092
+ win_height , win_width = win .getmaxyx ()
2093
+ bottom_shadow , right_shadow = _create_shadow_windows (win_y , win_x , win_height , win_width )
2094
+
2063
2095
while True :
2064
- # Draw main display behind dialog
2096
+ # Draw main display behind dialog (calls noutrefresh on all subwindows)
2065
2097
_draw_main ()
2066
2098
2067
- # Get window position and size
2068
- win_y , win_x = win .getbegyx ()
2069
- win_height , win_width = win .getmaxyx ()
2070
-
2071
- # Don't draw shadow for now - TODO: Add shadow support later
2072
-
2073
2099
win .erase ()
2074
2100
2075
2101
# Draw box border with proper colors
@@ -2147,6 +2173,10 @@ def _button_dialog(title, text, buttons, default_button=0):
2147
2173
_print_button (win , button_label , button_y , button_positions [i ], i == selected_button )
2148
2174
2149
2175
win .noutrefresh ()
2176
+
2177
+ # Refresh shadow windows after dialog window to ensure they're on top
2178
+ _refresh_shadow_windows (bottom_shadow , right_shadow )
2179
+
2150
2180
curses .doupdate ()
2151
2181
2152
2182
# Handle input
@@ -2158,6 +2188,10 @@ def _button_dialog(title, text, buttons, default_button=0):
2158
2188
win .resize (win_height , win_width )
2159
2189
win .mvwin ((_height (_stdscr ) - win_height )// 2 ,
2160
2190
(_width (_stdscr ) - win_width )// 2 )
2191
+ # Recreate shadow windows with new dialog size
2192
+ win_y , win_x = win .getbegyx ()
2193
+ win_height , win_width = win .getmaxyx ()
2194
+ bottom_shadow , right_shadow = _create_shadow_windows (win_y , win_x , win_height , win_width )
2161
2195
2162
2196
elif c == "\x1B " : # ESC
2163
2197
return None
@@ -2260,37 +2294,64 @@ def _draw_box(win, y, x, height, width, box_attr, border_attr):
2260
2294
pass # Interior is handled by caller
2261
2295
2262
2296
2263
- def _draw_shadow (win , y , x , height , width ):
2264
- # Draw shadows along the right and bottom edge to give a more 3D look,
2265
- # matching lxdialog's draw_shadow()
2297
+ def _create_shadow_windows (y , x , height , width , right_y_offset = 1 ):
2298
+ # Create shadow windows for bottom and right edges
2299
+ # Returns tuple of (bottom_shadow_win, right_shadow_win)
2300
+ #
2301
+ # Based on lxdialog's draw_shadow():
2302
+ # - Bottom: at y + height, from x + 2, width chars
2303
+ # - Right: from y + right_y_offset to y + height (inclusive), at x + width, 2 chars wide
2266
2304
2267
- if curses .has_colors ():
2268
- # Note: We need to define shadow color if not already defined
2269
- # For now, use a simple approach: draw with shadow style
2270
- try :
2271
- win .attrset (_style .get ("shadow" , 0 ))
2272
- except :
2273
- # Fallback: use dimmed/dark color
2274
- win .attrset (curses .A_DIM )
2305
+ if not curses .has_colors ():
2306
+ return None , None
2307
+
2308
+ try :
2309
+ shadow_attr = _style .get ("shadow" , 0 )
2275
2310
2276
- # Bottom shadow (offset by 2 on x-axis)
2277
- for i in range (width ):
2311
+ # Bottom shadow window (1 line high, width wide, offset by 2 on x)
2312
+ bottom_shadow = None
2313
+ if y + height < _height (_stdscr ) and x + 2 + width <= _width (_stdscr ):
2278
2314
try :
2279
- ch = win . inch ( y + height , x + 2 + i )
2280
- _safe_addch ( win , y + height , x + 2 + i , ch & curses . A_CHARTEXT )
2315
+ bottom_shadow = curses . newwin ( 1 , width , y + height , x + 2 )
2316
+ bottom_shadow . bkgd ( ' ' , shadow_attr )
2281
2317
except :
2282
2318
pass
2283
2319
2284
- # Right shadow (2 characters wide)
2285
- for i in range (1 , height + 1 ):
2320
+ # Right shadow window
2321
+ # lxdialog: for (i = y + 1; i < y + height + 1; i++)
2322
+ # Draw from y+right_y_offset to y+height (inclusive)
2323
+ right_shadow = None
2324
+ if x + width + 2 <= _width (_stdscr ) and y + height <= _height (_stdscr ):
2286
2325
try :
2287
- ch1 = win .inch (y + i , x + width )
2288
- _safe_addch (win , y + i , x + width , ch1 & curses .A_CHARTEXT )
2289
- ch2 = win .inch (y + i , x + width + 1 )
2290
- _safe_addch (win , y + i , x + width + 1 , ch2 & curses .A_CHARTEXT )
2326
+ # From (y + right_y_offset) to (y + height) inclusive
2327
+ # Total rows = (y + height) - (y + right_y_offset) + 1 = height - right_y_offset + 1
2328
+ shadow_height = height - right_y_offset + 1
2329
+ if shadow_height > 0 :
2330
+ right_shadow = curses .newwin (shadow_height , 2 , y + right_y_offset , x + width )
2331
+ right_shadow .bkgd (' ' , shadow_attr )
2291
2332
except :
2292
2333
pass
2293
2334
2335
+ return bottom_shadow , right_shadow
2336
+ except :
2337
+ return None , None
2338
+
2339
+
2340
+ def _refresh_shadow_windows (bottom_shadow , right_shadow ):
2341
+ # Refresh shadow windows, refilling them each time to ensure visibility
2342
+ if bottom_shadow :
2343
+ try :
2344
+ bottom_shadow .erase () # Clear and refill with background
2345
+ bottom_shadow .noutrefresh ()
2346
+ except :
2347
+ pass
2348
+ if right_shadow :
2349
+ try :
2350
+ right_shadow .erase () # Clear and refill with background
2351
+ right_shadow .noutrefresh ()
2352
+ except :
2353
+ pass
2354
+
2294
2355
2295
2356
def _draw_frame (win , title ):
2296
2357
# Draw a frame around the inner edges of 'win', with 'title' at the top
@@ -3147,8 +3208,9 @@ def _styled_win(style):
3147
3208
3148
3209
def _set_style (win , style ):
3149
3210
# Changes the style of an existing window
3211
+ # Use bkgd() to immediately fill window with background
3150
3212
3151
- win .bkgdset (" " , _style [style ])
3213
+ win .bkgd (" " , _style [style ])
3152
3214
3153
3215
3154
3216
def _max_scroll (lst , win ):
0 commit comments