Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

popup management and updates #392

Open
nizaralheet opened this issue Nov 10, 2024 · 4 comments
Open

popup management and updates #392

nizaralheet opened this issue Nov 10, 2024 · 4 comments

Comments

@nizaralheet
Copy link

I'm trying to understand the proper way to manage popups in Qtile, specifically:

  • If I have a widget that shows a popup on callback , clicking it multiple times creates multiple popups instead of managing a single instance. What I want is:
    If there's no popup showing: create and show a new popup
    If there's already a popup showing: close it
    So each click should toggle the popup (show/hide) rather than creating multiple instances.

here is an example

def keylay(qtile):
    thelay = subprocess.check_output("setxkbmap -query | grep layout | awk '{print $2}' | tr 'a-z' 'A-Z'", shell=True, text=True)
    thelay = "󰌌 : " + thelay.strip()
    
    controls = [
        PopupText(
            text=thelay,
            font="Iosevka NF SemiBold",
            fontsize=22,
            pos_x=0.0,
            pos_y=0.0,
            height=1,
            width=1,
            h_align="center",
        )
    ]
    

    layout_kb = PopupRelativeLayout(
        qtile,
        width=200,
        height=60,
        controls=controls,
        close_on_click=True,
        hide_on_timeout=2,
    )
    layout_kb.show(x=860, y=140)

I'd appreciate any guidance on the proper approach to handle these popup behaviors. Are there built-in methods or recommended patterns for managing popup lifecycles ?
Thanks!

@elParaguayo
Copy link
Owner

Yes. Definitely possible but I don't have time to show you the code now.

One way to do this would be to define the layout outside of your function (so there's only ever one instance) and then the function then just toggles visibility and updates the text.

@nizaralheet
Copy link
Author

i would appreciate it if you could show my the code , or refer to it

@elParaguayo
Copy link
Owner

I was thinking something like this (untested):

from libqtile import qtile


class KBPopup:
    def __init___(self):
        self.hidden = True
        self.started = False

    def _create_layout(self, initial_text):
        controls = [
            PopupText(
                name="layout",
                text=initial_text,
                font="Iosevka NF SemiBold",
                fontsize=22,
                pos_x=0.0,
                pos_y=0.0,
                height=1,
                width=1,
                h_align="center",
            )
        ]
        
        self.layout = PopupRelativeLayout(
            qtile,
            width=200,
            height=60,
            controls=controls,
            close_on_click=True,
            hide_on_timeout=2,
        )

    def toggle(self, text="", x=0, y=0):
        if not self.started:
            self._create_layout(text)
            self.layout.show(qtile=qtile, x=x, y=y)
            self.started = True
            self.hidden = False
        elif self.hidden:
            self.layout.update_controls(layout=text)
            self.layout.show(x=x, y=y)
            self.hidden = False
        else:
            self.layout.hide()
            self.hidden = True


kb_layout = KBPopup()

def keylay(qtile):
    thelay = subprocess.check_output("setxkbmap -query | grep layout | awk '{print $2}' | tr 'a-z' 'A-Z'", shell=True, text=True)
    thelay = "󰌌 : " + thelay.strip()
    kb_layout.toggle(x=860, y=140)

@nizaralheet
Copy link
Author

nizaralheet commented Nov 21, 2024

Hi , i have tested it a little bit , it did work but not in the way that i want , so i used it for another popup , and it works good so far but there was one problem with hiding the popup with close_on_click=true it kill the popup then without changing self.hidden to true , so i tried to add a callback for the popup but for some reason the callback is not working at all .
It works good when i close it by 'reclicking at the widget ' -it spawn with callback for widget- but not when click at the popup body

class CalendarPopup:
    def __init__(self):
        self.started = False
        self.hidden = True

    def _create_layout(self):

        # Get the calendar from the shell command 
        today = datetime.datetime.now().day
        cal_output = subprocess.check_output("cal", shell=True, text=True)
        cal_lines = cal_output.splitlines()
        highlighted_cal = []
        for line in cal_lines:
            highlighted_line = re.sub(
                rf"\b{today}\b", 
                f'<span background="#f0f0f0" foreground="#0f0f0f" weight="bold">{today}</span>', 
                line
            )
            highlighted_cal.append(highlighted_line)
        highlighted_cal_output = "\n".join(highlighted_cal)  
        #############

        controls = [
            PopupText(
                highlighted_cal_output,
                font="Iosevka NF SemiBold",
                markup=True,
                fontsize=18,
                row=1,
                col=1,
                row_span=8,
                col_span=8,
                #mouse_callbacks={ "Button1": lambda: self.hide_popup()} # This also works but in a less effective way
            )
        ]

        self.layout = PopupGridLayout(
            qtile,
            rows=10, 
            cols=10,
            height=210,
            width=250,
            close_on_click=False,
            controls=controls,
            background=Color1,
            hide_interval=10,
        )
        self.layout.bind_callbacks(calendar_text={"Button1": self.hide_popup})  # This seems not to work; tested with other callbacks that work

    def hide_popup(self):
        self.hidden = True
        self.layout.hide()

    def toggle(self, x=0, y=0):
        if not self.started:
            self._create_layout()
            self.layout.show(qtile=qtile, x=x, y=y, relative_to_bar=True)
            self.started = True
            self.hidden = False
        elif self.hidden:
            # self.layout.update_controls(relative_to_bar=True)
            self.layout.show(qtile=qtile, x=x, y=y, relative_to_bar=True)
            self.hidden = False
        else:
            self.layout.hide()
            self.hidden = True

show_cal = CalendarPopup()

def calendar(qtile):
    show_cal.toggle(x=720, y=10)

here is a video for current setup

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants