Search code examples
kivysplitter

How to use several splitters in Kivy?


I'd like to use two splitters in a single screen, so that the user can have either one of the 3 parts to fill the whole screen (but leaving a bit for the splitters to be shown).

I've tried doing it (see code below), but when I shrink part 3 to the minimum and then enlarge part 1 as much as I can, part 3 disappears, which is not the desired behavior (I'd like it to be symmetrical to all 3 parts).

Does anyone have an idea?

BoxLayout:
id: all
min_view_size: sp(30)
strip_size: sp(13)

Splitter:
    sizable_from: 'right'
    strip_size: all.strip_size
    max_size: all.width - (all.min_view_size + all.strip_size)*2
    min_size: all.min_view_size + all.strip_size

    Label:
        text: '1'

Splitter:
    sizable_from: 'right'
    strip_size: all.strip_size
    max_size: all.width - (all.min_view_size + self.strip_size)*2
    min_size: all.min_view_size + self.strip_size

    Label:
        text: '2'

BoxLayout:
    max_size: all.width - (all.min_view_size + all.strip_size)*2
    min_size: all.min_view_size
    Label:
        text: '3'

Solution

  • After some tweaking, here is a working example for 2 horizontal splitters, so the parts between them have a minimum size:

    BoxLayout:
        id: all
        min_view_size: sp(30)
        strip_size: sp(13)
    
    Splitter:
        id: splitter1
        sizable_from: 'right'
        strip_size: all.strip_size
        max_size: all.width - (all.min_view_size + all.strip_size)*2
        min_size: all.min_view_size + all.strip_size
    
        Label:
            text: '1'
    
    Splitter:
        id: splitter2
        sizable_from: 'right'
        strip_size: all.strip_size
        max_size: (all.width - splitter1.width) - (all.min_view_size + self.strip_size)
        min_size: all.min_view_size + self.strip_size
    
        Label:
            text: '2'
    
    BoxLayout:
        Label:
            text: '3'
    

    The trick was to have the min_size rule for the second splitter depend on the size of the first one.

    EDIT:

    And here it is with auto-orientation-adjustment when the window is narrow/wide:

    BoxLayout:
        id: all
        min_view_size: sp(30)
        strip_size: sp(13)
        orientation: 'vertical' if self.width < self.height else 'horizontal'
        vertical: self.orientation == 'vertical'
        bigger_size: self.height if self.vertical else self.width
        default_part_size: (self.bigger_size - self.strip_size*2)/3
    
        # Reset part sizes when orientation changes
        on_vertical:
            if args[1]: (splitter1.height, splitter2.height) = (self.default_part_size, self.default_part_size)
            if not args[1]: (splitter1.width, splitter2.width) = (self.default_part_size, self.default_part_size)
    
    Splitter:
        id: splitter1
        strip_size: all.strip_size
        max_size: all.bigger_size - (all.min_view_size + all.strip_size)*2
        min_size: all.min_view_size + all.strip_size
        sizable_from: 'bottom' if all.vertical else 'right'
        size_hint: (1, None) if all.vertical else (None, 1)
        size: (all.width, all.default_part_size) if all.vertical else (all.default_part_size, all.height)
    
        BoxLayout:
            Button:
                text: '1'
    
    Splitter:
        id: splitter2
        strip_size: all.strip_size
        splitter1_bigger_size: splitter1.height if all.vertical else splitter1.width
        max_size: (all.bigger_size - self.splitter1_bigger_size) - (all.min_view_size + self.strip_size)
        min_size: all.min_view_size + self.strip_size
        sizable_from: 'bottom' if all.vertical else 'right'
        size_hint: (1, None) if all.vertical else (None, 1)
        size: (all.width, all.default_part_size) if all.vertical else (all.default_part_size, all.height)
    
        BoxLayout:    
            Button:
                text: '2'
    
    BoxLayout:
        Button:
            text: '3'