Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
## Plugin Manager (dd-mm-yyyy)
### 1.1.11 (15-07-2026)

- New plugin manager logo

### 1.1.10 (12-06-2026)

Expand Down
6 changes: 6 additions & 0 deletions index.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{
"plugin_manager_url": "https://github.com/bombsquad-community/plugin-manager/{content_type}/{tag}/plugin_manager.py",
"versions": {
"1.1.11": {
"api_version": 9,
"commit_sha": "2d4614e",
"released_on": "17-07-2026",
"md5sum": "5ce3e8c910229e724186f3de6c3be4ea"
},
"1.1.10": {
"api_version": 9,
"commit_sha": "a1baa5f",
Expand Down
193 changes: 130 additions & 63 deletions plugin_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
# Modules used for overriding AllSettingsWindow
import logging

PLUGIN_MANAGER_VERSION = "1.1.10"
PLUGIN_MANAGER_VERSION = "1.1.11"
REPOSITORY_URL = "https://github.com/bombsquad-community/plugin-manager"
# Current tag can be changed to "staging" or any other branch in
# plugin manager repo for testing purpose.
Expand Down Expand Up @@ -176,6 +176,75 @@ def partial_format(string_template, **kwargs):
return string_template


def draw_plugman_logo(parent, position, size, draw_controller=None):
"""Draws the Plugman logo with automatically scaled elements(crafted by brostos).

The Wizard is the Plugin Manager
🧙‍♂️ The Wizard & Wand
Represents the talented modders who dedicate their time to crafting incredible
mods for the BombSquad community.

❤️ The Red Heart
Originally grey in the original mod manager logo by @Mrmaxmeier.
The touch of red was added to represent our deep appreciation and love for
the original creator, contributors, and all past and present plugin manager maintainers.

🪄 The Off-Center Star Stick
The stick holds the star, but it is deliberately not centered perfectly.
This symbolizes imperfection: no plugin is ever completely perfect. It serves
as a reminder to keep updating and improving your plugins.

⭐ The Star
Highlights the open-source nature of the Plugin Manager and its community plugins.
If you love the project, make sure to give it a star!

Args:
parent: The parent widget (e.g., self._root_widget).
position (tuple): The (x, y) starting baseline coordinates of the logo.
size (float): The base width/height for the main asset. Defaults to 120.
draw_controller: The pmb drawing controller reference.
"""
base_x, base_y = position

char_x = base_x + (size * 0.0417) # Originally +5
char_y = base_y + (size * 0.2917) # Originally +35

heart_size = size * 0.3333 # Originally size - 80 (40x40)
heart_x = base_x - (size * 0.1167) # Originally -14
heart_y = base_y + (size * 0.7167) # Originally +86

star_size = size * 0.35 # Originally size - 78 (42x42)
star_x = base_x + (size * 0.80) # Originally +96
star_y = base_y + (size * 1.00) # Originally +120

bui.imagewidget(
parent=parent,
position=(char_x, char_y),
size=(size, size),
color=(0.8, 0.95, 1),
texture=bui.gettexture("storeCharacter"),
draw_controller=draw_controller,
)

bui.imagewidget(
parent=parent,
position=(heart_x, heart_y),
size=(heart_size, heart_size),
color=(1.00, 0.20, 0.20),
texture=bui.gettexture("heart"),
draw_controller=draw_controller,
)

bui.imagewidget(
parent=parent,
position=(star_x, star_y),
size=(star_size, star_size),
color=(1.00, 1.00, 0.00),
texture=bui.gettexture("star"),
draw_controller=draw_controller,
)


class DNSBlockWorkaround:
"""
Some ISPs put a DNS block on domains that are needed for plugin manager to
Expand Down Expand Up @@ -3341,85 +3410,83 @@ def _b_title(
on_activate_call=self._do_plugman
)
_b_title(x_offs6, v, pmb, bui.Lstr(value="Plugin Manager"))
imgw = imgh = 120
bui.imagewidget(
draw_plugman_logo(
parent=self._root_widget,
position=(x_offs6 + basew * 0.49 - imgw * 0.5 + 5, v + 35),
size=(imgw, imgh),
color=(0.8, 0.95, 1),
texture=bui.gettexture('storeIcon'),
position=(x_offs6 + basew * 0.49 - 120 * 0.5, v),
size=110,
draw_controller=pmb
)
self._restore_state()
)
self._restore_state()

def _do_plugman(self) -> None:
# no-op if we're not in control.
if not self.main_window_has_control():
return
def _do_plugman(self) -> None:
# no-op if we're not in control.
if not self.main_window_has_control():
return

self.main_window_replace(
lambda: PluginManagerWindow(
origin_widget=self._plugman_button
)
self.main_window_replace(
lambda: PluginManagerWindow(
origin_widget=self._plugman_button
)
)

def _save_state(self) -> None:
try:
def _save_state(self) -> None:
try:
sel = self._root_widget.get_selected_child()
if sel == self._controllers_button:
sel_name = 'Controllers'
sel_name = 'Controllers'
elif sel == self._graphics_button:
sel_name = 'Graphics'
sel_name = 'Graphics'
elif sel == self._audio_button:
sel_name = 'Audio'
sel_name= 'Audio'
elif sel == self._advanced_button:
sel_name = 'Advanced'
sel_name= 'Advanced'
elif sel == self._plugman_button:
sel_name = 'PlugMan'
sel_name= 'PlugMan'
elif sel == self._back_button:
sel_name = 'Back'
sel_name= 'Back'
else:
raise ValueError(f'unrecognized selection \'{sel}\'')
raise ValueError(f'unrecognized selection \'{sel}\'')
assert bui.app.classic is not None
bui.app.ui_v1.window_states[type(self)] = {'sel_name': sel_name}
except Exception:
logging.exception('Error saving state for %s.', self)
bui.app.ui_v1.window_states[type(self)]= {'sel_name': sel_name}
except Exception:
logging.exception('Error saving state for %s.', self)

def _restore_state(self) -> None:
def _restore_state(self) -> None:
try:
assert bui.app.classic is not None
sel_name = bui.app.ui_v1.window_states.get(type(self), {}).get(
'sel_name'
)
sel: bui.Widget | None
if sel_name == 'Controllers':
sel = self._controllers_button
elif sel_name == 'Graphics':
sel = self._graphics_button
elif sel_name == 'Audio':
sel = self._audio_button
elif sel_name == 'Advanced':
sel = self._advanced_button
elif sel_name == "PlugMan":
sel = self._plugman_button
elif sel_name == 'Back':
sel = self._back_button
else:
sel = self._controllers_button
if sel is not None:
bui.containerwidget(edit=self._root_widget, selected_child=sel)
except Exception:
logging.exception('Error restoring state for %s.', self)


# ba_meta export babase.Plugin
class EntryPoint(babase.Plugin):
def on_app_running(self) -> None:
"""Called when the app is being launched."""
from bauiv1lib.settings import allsettings
allsettings.AllSettingsWindow = NewAllSettingsWindow
DNSBlockWorkaround.apply()
asyncio.set_event_loop(babase._asyncio._g_asyncio_event_loop)
startup_tasks = StartupTasks()

loop.create_task(startup_tasks.execute())
'sel_name'
)
sel: bui.Widget | None
if sel_name == 'Controllers':
sel = self._controllers_button
elif sel_name == 'Graphics':
sel = self._graphics_button
elif sel_name == 'Audio':
sel = self._audio_button
elif sel_name == 'Advanced':
sel = self._advanced_button
elif sel_name == "PlugMan":
sel = self._plugman_button
elif sel_name == 'Back':
sel = self._back_button
else:
sel = self._controllers_button
if sel is not None:
bui.containerwidget(edit=self._root_widget, selected_child=sel)
except Exception:
logging.exception('Error restoring state for %s.', self)


# ba_meta export babase.Plugin

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think u did some formatting mistake, and the indentation got messed up

class EntryPoint(babase.Plugin):
def on_app_running(self) -> None:
"""Called when the app is being launched."""
from bauiv1lib.settings import allsettings
allsettings.AllSettingsWindow= NewAllSettingsWindow
DNSBlockWorkaround.apply()
asyncio.set_event_loop(babase._asyncio._g_asyncio_event_loop)
startup_tasks= StartupTasks()

loop.create_task(startup_tasks.execute())