19
19
import pygame
20
20
import pygame_menu
21
21
22
+ from itertools import product
22
23
from pygame_menu ._base import Base
23
24
from pygame_menu ._decorator import Decorator
24
25
from pygame_menu .locals import POSITION_SOUTHEAST , POSITION_SOUTHWEST , POSITION_WEST , \
@@ -91,6 +92,8 @@ class ScrollArea(Base):
91
92
:param area_width: Width of scrollable area in px
92
93
:param area_height: Height of scrollable area in px
93
94
:param area_color: Background color, it can be a color or an image
95
+ :param border_color: Border color
96
+ :param border_width: Border width in px
94
97
:param controls_joystick: Use joystick events
95
98
:param controls_keyboard: Use keyboard events
96
99
:param controls_mouse: Use mouse events
@@ -114,6 +117,10 @@ class ScrollArea(Base):
114
117
:param world: Surface to draw and scroll
115
118
"""
116
119
_area_color : Optional [Union [ColorInputType , 'pygame_menu.BaseImage' ]]
120
+ _border_color : Optional [Union [ColorInputType , 'pygame_menu.BaseImage' ]]
121
+ _border_tiles : List ['pygame.Surface' ]
122
+ _border_tiles_size : Tuple2IntType
123
+ _border_width : int
117
124
_bg_surface : Optional ['pygame.Surface' ]
118
125
_decorator : 'Decorator'
119
126
_extend_x : int
@@ -135,6 +142,8 @@ def __init__(
135
142
area_width : int ,
136
143
area_height : int ,
137
144
area_color : Optional [Union [ColorInputType , 'pygame_menu.BaseImage' ]] = None ,
145
+ border_color : Optional [Union [ColorInputType , 'pygame_menu.BaseImage' ]] = None ,
146
+ border_width : int = 0 ,
138
147
controls_joystick : bool = True ,
139
148
controls_keyboard : bool = True ,
140
149
controls_mouse : bool = True ,
@@ -161,6 +170,7 @@ def __init__(
161
170
162
171
assert isinstance (area_height , int )
163
172
assert isinstance (area_width , int )
173
+ assert isinstance (border_width , int )
164
174
assert isinstance (controls_joystick , bool )
165
175
assert isinstance (controls_keyboard , bool )
166
176
assert isinstance (controls_mouse , bool )
@@ -175,6 +185,18 @@ def __init__(
175
185
176
186
if area_color is not None and not isinstance (area_color , pygame_menu .BaseImage ):
177
187
area_color = assert_color (area_color )
188
+ if border_color is not None and not isinstance (border_color , pygame_menu .BaseImage ):
189
+ border_color = assert_color (border_color )
190
+
191
+ # Create tiles
192
+ if isinstance (border_color , pygame_menu .BaseImage ):
193
+ iw , ih = border_color .get_size ()
194
+ tw , th = iw // 3 , ih // 3
195
+ self ._border_tiles_size = tw , th
196
+ self ._border_tiles = [
197
+ border_color .subsurface ((x , y , tw , th ))
198
+ for x , y in product (range (0 , iw , tw ), range (0 , ih , th ))
199
+ ]
178
200
179
201
scrollbar_color = assert_color (scrollbar_color )
180
202
scrollbar_slider_color = assert_color (scrollbar_slider_color )
@@ -195,7 +217,8 @@ def __init__(
195
217
unique_scrolls .append (s )
196
218
197
219
self ._area_color = area_color
198
- self ._bg_surface = None
220
+ self ._border_color = border_color
221
+ self ._border_width = border_width
199
222
self ._bg_surface = None
200
223
self ._decorator = Decorator (self )
201
224
self ._scrollbar_positions = tuple (unique_scrolls ) # Ensure unique
@@ -300,10 +323,11 @@ def _make_background_surface(self) -> None:
300
323
# Make surface
301
324
self ._bg_surface = make_surface (width = self ._rect .width + self ._extend_x ,
302
325
height = self ._rect .height + self ._extend_y )
326
+ rect = self ._bg_surface .get_rect ()
303
327
if self ._area_color is not None :
304
328
if isinstance (self ._area_color , pygame_menu .BaseImage ):
305
329
self ._area_color .draw (surface = self ._bg_surface ,
306
- area = self . _bg_surface . get_rect () )
330
+ area = rect )
307
331
else :
308
332
self ._bg_surface .fill (assert_color (self ._area_color ))
309
333
@@ -476,6 +500,74 @@ def draw(self, surface: 'pygame.Surface') -> 'ScrollArea':
476
500
# Draw post decorator
477
501
self ._decorator .draw_post (surface )
478
502
503
+ # Create border
504
+ if isinstance (self ._border_color , pygame_menu .BaseImage ): # Image
505
+ tw , th = self ._border_tiles_size
506
+ border_rect = pygame .Rect (
507
+ int (self ._rect .x - tw ),
508
+ int (self ._rect .y - th ),
509
+ int (self ._rect .width + 2 * tw ),
510
+ int (self ._rect .height + 2 * th )
511
+ )
512
+
513
+ surface_blit = surface .blit
514
+ (
515
+ tile_nw ,
516
+ tile_w ,
517
+ tile_sw ,
518
+ tile_n ,
519
+ tile_c ,
520
+ tile_s ,
521
+ tile_ne ,
522
+ tile_e ,
523
+ tile_se ,
524
+ ) = self ._border_tiles
525
+ left , top = self ._rect .topleft
526
+ left -= tw
527
+ top -= th
528
+
529
+ # draw top and bottom tiles
530
+ area : Optional [Tuple [int , int , int , int ]]
531
+
532
+ for x in range (border_rect .left , border_rect .right , tw ):
533
+ if x + tw >= border_rect .right :
534
+ area = 0 , 0 , tw - (x + border_rect .right ), th
535
+ else :
536
+ area = None
537
+ surface_blit (tile_n , (x , top ), area )
538
+ surface_blit (tile_s , (x , border_rect .bottom - th ), area )
539
+
540
+ # draw left and right tiles
541
+ for y in range (border_rect .top , border_rect .bottom , th ):
542
+ if y + th >= border_rect .bottom :
543
+ area = 0 , 0 , tw , th - (y + border_rect .bottom )
544
+ else :
545
+ area = None
546
+ surface_blit (tile_w , (left , y ), area )
547
+ surface_blit (tile_e , (border_rect .right - tw , y ), area )
548
+
549
+ # draw corners
550
+ surface_blit (tile_nw , (left , top ))
551
+ surface_blit (tile_sw , (left , border_rect .bottom - th ))
552
+ surface_blit (tile_ne , (border_rect .right - tw , top ))
553
+ surface_blit (tile_se , (border_rect .right - tw , border_rect .bottom - th ))
554
+
555
+ else : # Color
556
+ if self ._border_width == 0 or self ._border_color is None :
557
+ return self
558
+ border_rect = pygame .Rect (
559
+ int (self ._rect .x - self ._border_width ),
560
+ int (self ._rect .y - self ._border_width ),
561
+ int (self ._rect .width + 2 * self ._border_width ),
562
+ int (self ._rect .height + 2 * self ._border_width )
563
+ )
564
+ pygame .draw .rect (
565
+ surface ,
566
+ self ._border_color ,
567
+ border_rect ,
568
+ self ._border_width
569
+ )
570
+
479
571
return self
480
572
481
573
def get_hidden_width (self ) -> int :
0 commit comments