3232# Window settings
3333WINDOW_TITLE = "Model Filter Configuration"
3434WINDOW_DEFAULT_SIZE = "1000x750"
35- WINDOW_MIN_WIDTH = 850
36- WINDOW_MIN_HEIGHT = 600
35+ WINDOW_MIN_WIDTH = 600
36+ WINDOW_MIN_HEIGHT = 400
3737
3838# Color scheme (dark mode)
3939BG_PRIMARY = "#1a1a2e" # Main background
@@ -1377,6 +1377,9 @@ def __init__(
13771377
13781378 def _create_content (self ):
13791379 """Build the dual list layout."""
1380+ # Don't let content dictate size - let parent grid control height
1381+ self .grid_propagate (False )
1382+
13801383 # Configure grid
13811384 self .grid_columnconfigure (0 , weight = 1 )
13821385 self .grid_columnconfigure (1 , weight = 1 )
@@ -2017,147 +2020,6 @@ def _render(self):
20172020 )
20182021
20192022
2020- # ════════════════════════════════════════════════════════════════════════════════
2021- # RULE CHIP COMPONENT
2022- # ════════════════════════════════════════════════════════════════════════════════
2023-
2024-
2025- class RuleChip (ctk .CTkFrame ):
2026- """
2027- Individual rule display showing pattern, affected count, and delete button.
2028-
2029- The pattern text is colored with the rule's assigned color.
2030- """
2031-
2032- def __init__ (
2033- self ,
2034- master ,
2035- rule : FilterRule ,
2036- on_delete : Callable [[str ], None ],
2037- on_click : Callable [[FilterRule ], None ],
2038- ):
2039- super ().__init__ (
2040- master ,
2041- fg_color = BG_TERTIARY ,
2042- corner_radius = 6 ,
2043- border_width = 1 ,
2044- border_color = BORDER_COLOR ,
2045- )
2046-
2047- self .rule = rule
2048- self .on_delete = on_delete
2049- self .on_click = on_click
2050- self ._is_highlighted = False
2051- self ._tooltip = None # Store tooltip reference to avoid duplicates
2052-
2053- self ._create_content ()
2054-
2055- # Click binding
2056- self .bind ("<Button-1>" , self ._handle_click )
2057-
2058- def _create_content (self ):
2059- """Build chip content."""
2060- # Container for horizontal layout
2061- self .content = ctk .CTkFrame (self , fg_color = "transparent" )
2062- self .content .pack (fill = "x" , padx = 8 , pady = 6 )
2063-
2064- # Pattern text (colored)
2065- self .pattern_label = ctk .CTkLabel (
2066- self .content ,
2067- text = self .rule .pattern ,
2068- font = (FONT_FAMILY , FONT_SIZE_NORMAL ),
2069- text_color = self .rule .color ,
2070- anchor = "w" ,
2071- )
2072- self .pattern_label .pack (side = "left" , fill = "x" , expand = True )
2073- self .pattern_label .bind ("<Button-1>" , self ._handle_click )
2074-
2075- # Affected count
2076- self .count_label = ctk .CTkLabel (
2077- self .content ,
2078- text = f"({ self .rule .affected_count } )" ,
2079- font = (FONT_FAMILY , FONT_SIZE_SMALL ),
2080- text_color = TEXT_MUTED ,
2081- width = 35 ,
2082- )
2083- self .count_label .pack (side = "left" , padx = (5 , 5 ))
2084- self .count_label .bind ("<Button-1>" , self ._handle_click )
2085-
2086- # Delete button
2087- delete_btn = ctk .CTkButton (
2088- self .content ,
2089- text = "×" ,
2090- font = (FONT_FAMILY , FONT_SIZE_LARGE , "bold" ),
2091- fg_color = "transparent" ,
2092- hover_color = ACCENT_RED ,
2093- text_color = TEXT_MUTED ,
2094- width = 24 ,
2095- height = 24 ,
2096- corner_radius = 4 ,
2097- command = self ._handle_delete ,
2098- )
2099- delete_btn .pack (side = "right" )
2100-
2101- # Tooltip showing affected models - create once, update later
2102- self ._update_tooltip ()
2103-
2104- # Bind tooltip events to child widgets (not delete button)
2105- for widget in [self .content , self .pattern_label , self .count_label ]:
2106- widget .bind ("<Enter>" , self ._on_tooltip_enter )
2107- widget .bind ("<Leave>" , self ._on_tooltip_leave )
2108-
2109- def _on_tooltip_enter (self , event = None ):
2110- """Forward enter event to tooltip."""
2111- if self ._tooltip :
2112- self ._tooltip ._schedule_show (event )
2113-
2114- def _on_tooltip_leave (self , event = None ):
2115- """Forward leave event to tooltip."""
2116- if self ._tooltip :
2117- self ._tooltip ._hide (event )
2118-
2119- def _handle_click (self , event = None ):
2120- """Handle click on rule chip."""
2121- self .on_click (self .rule )
2122-
2123- def _handle_delete (self ):
2124- """Handle delete button click."""
2125- self .on_delete (self .rule .pattern )
2126-
2127- def update_count (self , count : int , affected_models : List [str ]):
2128- """Update the affected count and tooltip."""
2129- self .rule .affected_count = count
2130- self .rule .affected_models = affected_models
2131- self .count_label .configure (text = f"({ count } )" )
2132- self ._update_tooltip ()
2133-
2134- def _update_tooltip (self ):
2135- """Update tooltip with affected models."""
2136- if self .rule .affected_models :
2137- if len (self .rule .affected_models ) <= 5 :
2138- models_text = "\n " .join (self .rule .affected_models )
2139- else :
2140- models_text = "\n " .join (self .rule .affected_models [:5 ])
2141- models_text += f"\n ... and { len (self .rule .affected_models ) - 5 } more"
2142- text = f"Matches:\n { models_text } "
2143- else :
2144- text = "No models match this pattern"
2145-
2146- # Reuse existing tooltip or create new one
2147- if self ._tooltip is None :
2148- self ._tooltip = ToolTip (self , text )
2149- else :
2150- self ._tooltip .update_text (text )
2151-
2152- def set_highlighted (self , highlighted : bool ):
2153- """Set highlighted state."""
2154- self ._is_highlighted = highlighted
2155- if highlighted :
2156- self .configure (border_color = self .rule .color , border_width = 2 )
2157- else :
2158- self .configure (border_color = BORDER_COLOR , border_width = 1 )
2159-
2160-
21612023# ════════════════════════════════════════════════════════════════════════════════
21622024# RULE PANEL COMPONENT
21632025# ════════════════════════════════════════════════════════════════════════════════
@@ -2191,30 +2053,18 @@ def __init__(
21912053
21922054 def _create_content (self ):
21932055 """Build panel content."""
2194- # Title (compact)
2056+ # Title at top (compact)
21952057 title_label = ctk .CTkLabel (
21962058 self ,
21972059 text = self .title ,
21982060 font = (FONT_FAMILY , FONT_SIZE_SMALL , "bold" ),
21992061 text_color = TEXT_PRIMARY ,
22002062 )
2201- title_label .pack (anchor = "w" , padx = 10 , pady = (6 , 3 ))
2063+ title_label .pack (side = "top" , anchor = "w" , padx = 10 , pady = (4 , 2 ))
22022064
2203- # Virtual rule list (replaces CTkScrollableFrame + RuleChips)
2204- self .rule_list = VirtualRuleList (
2205- self ,
2206- rule_type = self .rule_type ,
2207- on_rule_click = self .on_rule_clicked ,
2208- on_rule_delete = self ._on_rule_delete ,
2209- )
2210- self .rule_list .pack (fill = "both" , expand = True , padx = 6 , pady = (0 , 3 ))
2211-
2212- # Set minimum height for rule list to ensure it's visible
2213- self .rule_list .frame .configure (height = 70 )
2214-
2215- # Input frame with fixed height (won't squish on resize)
2065+ # Input frame at BOTTOM - pack BEFORE rule_list to reserve space
22162066 input_frame = ctk .CTkFrame (self , fg_color = "transparent" , height = 32 )
2217- input_frame .pack (fill = "x" , padx = 6 , pady = (0 , 5 ))
2067+ input_frame .pack (side = "bottom" , fill = "x" , padx = 6 , pady = (2 , 4 ))
22182068 input_frame .pack_propagate (False ) # Prevent children from changing frame height
22192069
22202070 # Pattern input
@@ -2228,7 +2078,7 @@ def _create_content(self):
22282078 placeholder_text_color = TEXT_MUTED ,
22292079 height = 28 ,
22302080 )
2231- self .input_entry .pack (side = "left" , fill = "x " , expand = True , padx = (0 , 6 ))
2081+ self .input_entry .pack (side = "left" , fill = "both " , expand = True , padx = (0 , 6 ))
22322082 self .input_entry .bind ("<Return>" , self ._on_add_clicked )
22332083 self .input_entry .bind ("<KeyRelease>" , self ._on_input_key )
22342084
@@ -2245,6 +2095,15 @@ def _create_content(self):
22452095 )
22462096 add_btn .pack (side = "right" )
22472097
2098+ # Virtual rule list fills REMAINING middle space - pack LAST
2099+ self .rule_list = VirtualRuleList (
2100+ self ,
2101+ rule_type = self .rule_type ,
2102+ on_rule_click = self .on_rule_clicked ,
2103+ on_rule_delete = self ._on_rule_delete ,
2104+ )
2105+ self .rule_list .pack (side = "top" , fill = "both" , expand = True , padx = 6 , pady = (0 , 2 ))
2106+
22482107 def _on_input_key (self , event = None ):
22492108 """Handle key release in input field - for real-time preview."""
22502109 text = self .input_entry .get ().strip ()
@@ -2365,20 +2224,24 @@ def __init__(self):
23652224 self .after (100 , self ._activate_window )
23662225
23672226 def _create_main_layout (self ):
2368- """Create the main layout with grid for responsive sizing."""
2369- # Main content frame using grid layout
2370- # This allows proportional sizing between model lists and rule panels
2227+ """Create the main layout with grid weights for 3:1 ratio."""
2228+ # Main content frame - regular frame with grid layout
23712229 self .content_frame = ctk .CTkFrame (self , fg_color = "transparent" )
2372- self .content_frame .pack (fill = "both" , expand = True , padx = 20 , pady = (8 , 10 ))
2230+ self .content_frame .pack (fill = "both" , expand = True , padx = 15 , pady = (5 , 8 ))
23732231
2374- # Configure grid weights for responsive layout
2375- # Using 3:1 ratio so models get significantly more space than rules
2232+ # Configure grid with proper weights for 3:1 ratio
23762233 self .content_frame .grid_columnconfigure (0 , weight = 1 )
2377- self .content_frame .grid_rowconfigure (0 , weight = 0 ) # Header - fixed
2378- self .content_frame .grid_rowconfigure (1 , weight = 0 ) # Search - fixed
2379- self .content_frame .grid_rowconfigure (2 , weight = 3 ) # Model lists - expands most
2380- self .content_frame .grid_rowconfigure (3 , weight = 1 ) # Rule panels - expands less
2381- self .content_frame .grid_rowconfigure (4 , weight = 0 ) # Status bar - fixed
2234+
2235+ # Row 0: Header - fixed height
2236+ self .content_frame .grid_rowconfigure (0 , weight = 0 )
2237+ # Row 1: Search - fixed height
2238+ self .content_frame .grid_rowconfigure (1 , weight = 0 )
2239+ # Row 2: Model lists - weight=3 for 3:1 ratio, minimum 100px
2240+ self .content_frame .grid_rowconfigure (2 , weight = 3 , minsize = 200 )
2241+ # Row 3: Rule panels - weight=1 for 3:1 ratio, minimum 55px
2242+ self .content_frame .grid_rowconfigure (3 , weight = 1 , minsize = 55 )
2243+ # Row 4: Status bar - fixed height
2244+ self .content_frame .grid_rowconfigure (4 , weight = 0 )
23822245
23832246 # Create all sections
23842247 self ._create_header ()
@@ -2527,6 +2390,8 @@ def _create_rule_panels(self):
25272390 """Create the ignore and whitelist rule panels."""
25282391 self .rules_frame = ctk .CTkFrame (self .content_frame , fg_color = "transparent" )
25292392 self .rules_frame .grid (row = 3 , column = 0 , sticky = "nsew" , pady = (0 , 5 ))
2393+ # Don't let content dictate size - let parent grid control height
2394+ self .rules_frame .grid_propagate (False )
25302395 self .rules_frame .grid_columnconfigure (0 , weight = 1 )
25312396 self .rules_frame .grid_columnconfigure (1 , weight = 1 )
25322397 self .rules_frame .grid_rowconfigure (0 , weight = 1 )
0 commit comments