@@ -335,14 +335,14 @@ def __init__(self, pkginfo, installer, name, background, color, is_flatpak, app_
335335#BannerTitle {
336336 color: %(color)s;
337337 font-weight: bold;
338- font-size: 48px ;
339- padding-top: 12px ;
338+ font-size: 44px ;
339+ padding-top: 8px ;
340340}
341341#BannerSummary {
342342 color: %(color)s;
343343 font-weight: normal;
344344 font-size: 16px;
345- padding-top: 10px ;
345+ padding-top: 4px ;
346346}
347347#BannerFlatpakLabel {
348348 font-weight: normal;
@@ -371,7 +371,7 @@ def __init__(self, pkginfo, installer, name, background, color, is_flatpak, app_
371371
372372 image = Gtk .Image .new_from_file (self .image_uri )
373373
374- vbox = Gtk .Box (orientation = Gtk .Orientation .VERTICAL , spacing = 12 , halign = Gtk .Align .START )
374+ vbox = Gtk .Box (orientation = Gtk .Orientation .VERTICAL , spacing = 8 , margin_bottom = 17 , halign = Gtk .Align .START )
375375 vbox .get_style_context ().add_provider (style_provider , Gtk .STYLE_PROVIDER_PRIORITY_APPLICATION )
376376 vbox .set_border_width (6 )
377377
@@ -969,8 +969,8 @@ def list_header_func(row, before, user_data=None):
969969 self .flowbox_featured = None
970970 self .flowbox_top_rated = None
971971 self .banner_tile = None
972- self .banner_dot_box = None
973972 self .banner_stack = None
973+ self .banner_dots_box = None
974974 self .banner_slideshow_timeout_id = 0
975975
976976 self .package_type_store = Gtk .ListStore (int , str , str , str , object ) # index, label, summary, icon-name, remotename, pkginfo
@@ -1090,6 +1090,11 @@ def print_startup_time(self):
10901090
10911091 @print_timing
10921092 def load_banner (self ):
1093+ """
1094+ Load and configure the banner display with navigation controls.
1095+ The banner shows featured applications in a slideshow format.
1096+ """
1097+ # Get the main banner container
10931098 box = self .builder .get_object ("box_banner" )
10941099
10951100 if self .low_res :
@@ -1100,9 +1105,11 @@ def load_banner(self):
11001105 self .main_window .set_default_size (800 , 500 )
11011106 return
11021107
1108+ # Clear existing content
11031109 for child in box .get_children ():
11041110 child .destroy ()
11051111
1112+ # Setup main container and stack
11061113 overlay = Gtk .Overlay ()
11071114 box .pack_start (overlay , True , True , 0 )
11081115
@@ -1111,17 +1118,110 @@ def load_banner(self):
11111118 self .banner_stack .set_transition_duration (BANNER_TIMER )
11121119 overlay .add (self .banner_stack )
11131120
1114- self .banner_dot_box = Gtk .Box (orientation = Gtk .Orientation .HORIZONTAL ,
1115- halign = Gtk .Align .CENTER ,
1116- valign = Gtk .Align .END )
1117- overlay .add_overlay (self .banner_dot_box )
1118-
1121+ # Create navigation buttons
1122+ left_arrow = Gtk .Button ()
1123+ right_arrow = Gtk .Button ()
1124+ left_image = Gtk .Image .new_from_icon_name ("go-previous-symbolic" , Gtk .IconSize .SMALL_TOOLBAR )
1125+ right_image = Gtk .Image .new_from_icon_name ("go-next-symbolic" , Gtk .IconSize .SMALL_TOOLBAR )
1126+
1127+ # Setup button styling
1128+ button_style_override = """
1129+ button {
1130+ background-color: transparent;
1131+ border: none;
1132+ padding: 0;
1133+ margin: 0;
1134+ min-height: 16px;
1135+ min-width: 16px;
1136+ }
1137+ button:hover image {
1138+ color: rgb(255, 255, 255);
1139+ }
1140+ button image {
1141+ color: rgba(255, 255, 255, 0.6);
1142+ }
1143+ """
1144+ css_provider = Gtk .CssProvider ()
1145+ css_provider .load_from_data (str .encode (button_style_override ))
1146+
1147+ # Apply styling to navigation elements
1148+ for widget in (left_arrow , right_arrow , left_image , right_image ):
1149+ context = widget .get_style_context ()
1150+ context .add_provider (css_provider , Gtk .STYLE_PROVIDER_PRIORITY_APPLICATION )
1151+
1152+ # Configure navigation buttons
1153+ left_arrow .add (left_image )
1154+ right_arrow .add (right_image )
1155+
1156+ for button in (left_arrow , right_arrow ):
1157+ button .set_relief (Gtk .ReliefStyle .NONE )
1158+
1159+ # Set navigation directions
1160+ left_arrow .direction = - 1
1161+ right_arrow .direction = 1
1162+
1163+ # Connect button signals
1164+ left_arrow .connect ("clicked" , self .on_arrow_clicked , self .banner_stack )
1165+ right_arrow .connect ("clicked" , self .on_arrow_clicked , self .banner_stack )
1166+
1167+ # Create dots container (centered)
1168+ self .banner_dots_box = Gtk .Box (orientation = Gtk .Orientation .HORIZONTAL ,
1169+ spacing = 4 ,
1170+ halign = Gtk .Align .CENTER ,
1171+ valign = Gtk .Align .CENTER )
1172+
1173+ # Create a background frame for navigation
1174+ dots_frame = Gtk .EventBox ()
1175+ dots_frame .set_name ("dots-frame" )
1176+
1177+ # Add CSS styling for the frame
1178+ frame_box_css = """
1179+ #dots-frame {
1180+ background-color: rgba(0, 0, 0, 0.25);
1181+ border-radius: 12px;
1182+ }
1183+ """
1184+ css_provider = Gtk .CssProvider ()
1185+ css_provider .load_from_data (frame_box_css .encode ())
1186+ dots_frame .get_style_context ().add_provider (css_provider , Gtk .STYLE_PROVIDER_PRIORITY_APPLICATION )
1187+
1188+ # Create navigation container with arrows and dots
1189+ nav_container = Gtk .Box (orientation = Gtk .Orientation .HORIZONTAL ,
1190+ spacing = 8 ,
1191+ halign = Gtk .Align .CENTER ,
1192+ valign = Gtk .Align .CENTER )
1193+
1194+ # Add padding around navigation
1195+ nav_container .set_margin_start (7 )
1196+ nav_container .set_margin_end (7 )
1197+ nav_container .set_margin_top (4 )
1198+ nav_container .set_margin_bottom (4 )
1199+
1200+ # Pack everything together
1201+ nav_container .pack_start (left_arrow , False , False , 0 )
1202+ nav_container .pack_start (self .banner_dots_box , True , False , 0 )
1203+ nav_container .pack_start (right_arrow , False , False , 0 )
1204+
1205+ dots_frame .add (nav_container )
1206+
1207+ frame_container = Gtk .Box (orientation = Gtk .Orientation .HORIZONTAL ,
1208+ halign = Gtk .Align .CENTER ,
1209+ valign = Gtk .Align .END ,
1210+ margin_bottom = 5 )
1211+ frame_container .pack_start (dots_frame , True , False , 0 )
1212+ overlay .add_overlay (frame_container )
1213+
1214+ self .dots = []
1215+ self .current_dot_index = 0
1216+
1217+ # Load featured applications
11191218 json_array = json .load (open ("/usr/share/linuxmint/mintinstall/featured/featured.json" , "r" ))
11201219 random .shuffle (json_array )
11211220
11221221 selected_apps = set ()
11231222 num_selected = 0
11241223
1224+ # Process featured applications
11251225 for app_json in json_array :
11261226 if num_selected >= 5 :
11271227 break
@@ -1133,13 +1233,12 @@ def load_banner(self):
11331233 if name in selected_apps :
11341234 continue
11351235
1236+ # Handle Flatpak and regular applications
11361237 if name .startswith ("flatpak:" ):
11371238 name = name .replace ("flatpak:" , "" )
11381239 pkginfo = self .installer .find_pkginfo (name , installer .PKG_TYPE_FLATPAK )
1139-
11401240 if pkginfo is None or not pkginfo .verified :
11411241 continue
1142-
11431242 is_flatpak = True
11441243 else :
11451244 pkginfo = self .installer .find_pkginfo (name , installer .PKG_TYPE_APT )
@@ -1148,6 +1247,7 @@ def load_banner(self):
11481247 if pkginfo is None :
11491248 continue
11501249
1250+ # Add application to banner
11511251 selected_apps .add (name )
11521252 num_selected += 1
11531253
@@ -1161,48 +1261,72 @@ def load_banner(self):
11611261
11621262 tile = BannerTile (pkginfo , self .installer , name , background , color , is_flatpak , app_json , self .on_banner_clicked )
11631263 flowbox .insert (tile , - 1 )
1164-
11651264 flowbox .show_all ()
11661265 self .banner_stack .add_named (flowbox , str (len (self .banner_stack .get_children ())))
11671266
1168- icon = Gtk .Image .new_from_icon_name ("mintinstall-banner-dot" , Gtk .IconSize .MENU )
1169- icon .set_pixel_size (5 )
1170-
1171- button_class_override = """
1172- #BannerDotOverlay {
1173- background-color: rgba(0, 0, 0, 0);
1174- background-image: none;
1175- border-color: rgba(0, 0, 0, 0);
1176- min-height: 12px;
1177- min-width: 22px;
1178- -gtk-icon-shadow: none;
1179- -gtk-icon-effect: none;
1180- box-shadow: none;
1181- }
1182- """
1183- provider = Gtk .CssProvider ()
1184- provider .load_from_data (str .encode (button_class_override ))
1185-
1186- dot_button = Gtk .Button (
1187- halign = Gtk .Align .CENTER ,
1188- valign = Gtk .Align .END ,
1189- name = "BannerDotOverlay" ,
1190- relief = Gtk .ReliefStyle .NONE ,
1191- can_focus = False ,
1192- image = icon
1193- )
1194-
1195- dot_button .get_style_context ().add_provider (provider , Gtk .STYLE_PROVIDER_PRIORITY_APPLICATION )
1196- dot_button .connect ("clicked" , self .on_dot_clicked , len (self .banner_stack .get_children ()) - 1 )
1197- self .banner_dot_box .pack_start (dot_button , False , False , 0 )
1267+ # Create dot indicator
1268+ dot = Gtk .DrawingArea ()
1269+ dot .set_size_request (10 , 10 )
1270+ dot .index = len (self .dots ) # Store index as a property
1271+ dot .connect ("draw" , self .draw_dot )
1272+ self .dots .append (dot )
1273+ self .banner_dots_box .pack_start (dot , False , False , 0 )
11981274
1199- self . update_dot_buttons ( 0 )
1275+ # Display the banner
12001276 box .show_all ()
1277+ self .update_dots (0 )
1278+ self .start_slideshow_timer ()
12011279
1202- def on_dot_clicked (self , button , index ):
1280+ def draw_dot (self , widget , cr ):
1281+ """
1282+ Draw a circular dot indicator with outline
1283+ """
1284+ # Get the dot's dimensions
1285+ width = widget .get_allocated_width ()
1286+ height = widget .get_allocated_height ()
1287+
1288+ # Calculate center and radius
1289+ center_x = width / 2
1290+ center_y = height / 2
1291+ radius = min (width , height ) / 2 - 1
1292+
1293+ # Draw outline circle
1294+ cr .set_line_width (1 )
1295+ cr .arc (center_x , center_y , radius , 0 , 2 * math .pi )
1296+ cr .set_source_rgba (0 , 0 , 0 , 0.25 ) # Semi-transparent black outline
1297+ cr .stroke_preserve ()
1298+
1299+ # Fill circle
1300+ if widget .index == self .current_dot_index :
1301+ cr .set_source_rgba (1 , 1 , 1 , 1 ) # Active dot: solid white
1302+ else :
1303+ cr .set_source_rgba (1 , 1 , 1 , 0.40 ) # Inactive dot: semi-transparent white
1304+
1305+ cr .fill ()
1306+ return False
1307+
1308+ def update_dots (self , current_index ):
1309+ """
1310+ Update the appearance of dots based on the current banner index
1311+ """
1312+ self .current_dot_index = current_index
1313+ for dot in self .dots :
1314+ dot .queue_draw ()
1315+
1316+ def on_arrow_clicked (self , button , banner_stack ):
1317+ current_index = int (self .banner_stack .get_visible_child_name ())
1318+ direction = getattr (button , "direction" , 1 )
1319+
1320+ if direction == 1 : # next
1321+ self .banner_stack .set_transition_type (Gtk .StackTransitionType .SLIDE_LEFT )
1322+ new_index = (current_index + 1 ) % len (self .banner_stack .get_children ())
1323+ else : # previous
1324+ self .banner_stack .set_transition_type (Gtk .StackTransitionType .SLIDE_RIGHT )
1325+ new_index = (current_index - 1 ) % len (self .banner_stack .get_children ())
1326+
1327+ self .banner_stack .set_visible_child_name (str (new_index ))
1328+ self .update_dots (new_index )
12031329 self .start_slideshow_timer ()
1204- self .banner_stack .set_visible_child_name (str (index ))
1205- self .update_dot_buttons (index )
12061330
12071331 def start_slideshow_timer (self ):
12081332 if self .low_res :
@@ -1220,24 +1344,13 @@ def stop_slideshow_timer(self):
12201344 self .banner_slideshow_timeout_id = 0
12211345
12221346 def on_slideshow_timeout (self ):
1223- visible_child = self .banner_stack .get_visible_child ( )
1224- index = self .banner_stack .get_children (). index ( visible_child )
1225- new_index = (index + 1 ) % len (self .banner_stack .get_children ())
1347+ current_index = int ( self .banner_stack .get_visible_child_name () )
1348+ self .banner_stack .set_transition_type ( Gtk . StackTransitionType . SLIDE_LEFT )
1349+ new_index = (current_index + 1 ) % len (self .banner_stack .get_children ())
12261350 self .banner_stack .set_visible_child_name (str (new_index ))
1227- self .update_dot_buttons (new_index )
1351+ self .update_dots (new_index )
12281352 return True
12291353
1230- def update_dot_buttons (self , current_index ):
1231- for i , button in enumerate (self .banner_dot_box .get_children ()):
1232- if i == current_index : #Bigger do if current slide
1233- icon = Gtk .Image .new_from_icon_name ("mintinstall-banner-dot" , Gtk .IconSize .MENU )
1234- icon .set_pixel_size (10 )
1235- button .set_image (icon )
1236- else :
1237- icon = Gtk .Image .new_from_icon_name ("mintinstall-banner-dot" , Gtk .IconSize .MENU )
1238- icon .set_pixel_size (5 )
1239- button .set_image (icon )
1240-
12411354 def on_banner_clicked (self , button , pkginfo ):
12421355 self .show_package (pkginfo , self .PAGE_LANDING )
12431356
0 commit comments