Page 1 of 1

Stackable inventory with search as you type

Posted: Tue Feb 27, 2024 3:12 pm
by jeffster
Yet another stackable inventory. This time you can type item name to quickly find matching items:
inv2.jpg
inv2.jpg (37.38 KiB) Viewed 1151 times
The zip below contains ready-to-play distributive, with pictures etc. Just unpack it and run "game" folder with Ren'Py 8 SDK.

Code: Select all

define items = {
    "book": ("book.png", "Description of book"),
    "bug":  ("bug.png",  "Description of bug"),
    "dice": ("dice.png", "Description of dice"),
    "film": ("film.png", "Description of film"),
    "look": ("look.png", "Description of look"),
    "pawn": ("pawn.png", "Description of pawn"),
    "sun":  ("sun.png",  "Description of sun"),
    "talk": ("talk.png", "Description of talk"),
    "tool": ("tool.png", "Description of tool"),
    "wand": ("wand.png", "Description of wand"),
}

default inventory = []          # [ [item_name, amount] ]

default filtered_names = []     # for search_fly function

init python:
    def set_item(item_name, amount):
        """ Universal function to add or remove inventory items """
        try:
            i = [x[0] for x in inventory].index(item_name)
            if amount <= 0:
                inventory.pop(i)
            else:
                inventory[i][1] = amount
        except:
            if amount > 0:
                inventory.append([item_name, amount])

    def get_item(item_name):
        """ Get amount of those items """
        try:
            i = [x[0] for x in inventory].index(item_name)
            return inventory[i][1]
        except:
            return 0

    def search_fly(searching, interact=True):
        """ Searching as you type when N symbols were entered """
        if len(searching) >= 2:         # <- N == 2
            store.filtered_names = [
                x for x in items.keys() if searching.casefold() in \
                                renpy.translate_string(x).casefold()]
            if interact:
                renpy.restart_interaction()

    class SearchInputValue(InputValue):
        def __init__(self, default_value="", default=False):
            super(SearchInputValue, self).__init__()
            self.text_value = default_value
            self.default = default

        def get_text(self):
            return self.text_value

        def set_text(self, s):
            self.text_value = s
            search_fly(s)

        def enter(self):
            return self.text_value

screen inv(page_number=0, current_item=""):
    default searchVal = SearchInputValue(current_item, default=False)

    text f"{len(inventory)} items. Page {page_number+1}":
        align (0.5, 0.0)
        size 48

    grid 4 2:
        xalign 0.5
        ypos 80
        spacing 12
        for i in range(8*page_number, 8*page_number+8):
            if i < len(inventory):
                button:
                    size_group "items"
                    background "#345"
                    hover_background "#579"
                    hovered searchVal.Disable()
                    vbox:
                        xalign 0.5
                        add items[inventory[i][0]][0]       # pic
                        text inventory[i][0]:               # name
                            size 42
                            yoffset 24
                        text str(inventory[i][1]):          # amount
                            xalign 1.0
                            yoffset -64
                            color "#FF0"

                    tooltip items[inventory[i][0]][1]   # description
                    action Return((inventory[i][0], inventory[i][1]))

    if page_number > 0:
        textbutton "<" align (0.2, 0.2) action Return(-1):
            text_size 96
            hovered searchVal.Disable()

    if page_number < (len(inventory)-1)//8:
        textbutton ">" align (0.8, 0.2) action Return(1):
            text_size 96
            hovered searchVal.Disable()

    if current_item:
        textbutton "-" align (0.4, 0.9) action Return("-"):
            text_size 96
            hovered searchVal.Disable()
        textbutton "+" align (0.6, 0.9) action Return("+"):
            text_size 96
            hovered searchVal.Disable()
        button:
            align (0.5, 0.9)
            size_group "items"
            background "#123"
            hover_background "#345"
            hovered searchVal.Disable()
            vbox:
                align (0.5, 0.5)
                add items[current_item][0] yoffset 12
                text str(get_item(current_item)):
                    xalign 1.0
                    xoffset 12
                    color "#FF0"
            tooltip items[current_item][1]
            action Return(current_item)

    hbox:
        xalign 0.5
        ypos 0.6
        yanchor 0.0
        spacing 8
        vbox:
            align (1.0, 0.0)
            spacing 4
            ysize 36
            style "itemName"
            button:
                action searchVal.Enable()
                hovered searchVal.Enable()
                background "#597"
                hover_background "#7B9"
                xfill True
                tooltip "Search"
                input:
                    value searchVal
                    copypaste True
                    color "#000"
            for n in filtered_names:
                button:
                    background "#345"
                    hover_background "#579"
                    hovered searchVal.Disable()
                    size_group "names"
                    text "[n!t]"
                    action Return(n)
                    tooltip items[n][1]

    $ tooltip = GetTooltip()
    if tooltip:
        text "[tooltip]" align (0.5, 0.5)

style itemName:
    xsize 600
    background "#345"
    hover_background "#579"


label start:
    python:
        n = 0
        for i in items:
            set_item(i, n)
            n += 1

        pageN = 0
        current_item = ""

label loop:
    call screen inv(pageN, current_item)

    if type(_return) is int:
        # -1 or 1 to flip through pages
        $ pageN = min(max(pageN+_return, 0), (len(inventory)-1)//8)

    elif type(_return) is str:
        # "-" or "+" to modify an item amount

        if _return == '-':
            $ set_item(current_item, get_item(current_item)-1)

        elif _return == '+':
            $ set_item(current_item, get_item(current_item)+1)

        else:
            # An item to select by name
            python:
                if _return in items:
                    current_item = _return
                    del filtered_names[:]
                elif len(filtered_names) == 1:
                    current_item = filtered_names[0]
                    del filtered_names[:]
                elif not filtered_names:
                    renpy.notify(f"No such item: {_return}")

    elif type(_return) is tuple:
        # first element is an item name
        $ current_item = _return[0]

    jump loop