Last active
April 13, 2022 00:18
-
-
Save Cheaterman/4b54af8eb62ff94b79af3b8ecf8fc7f1 to your computer and use it in GitHub Desktop.
eselection.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from dataclasses import dataclass, field | |
from typing import Callable, List | |
from samp import ( | |
INVALID_TEXT_DRAW, | |
CancelSelectTextDraw, | |
CreatePlayerTextDraw, | |
GetTickCount, | |
IsPlayerConnected, | |
PlayerTextDrawAlignment, | |
PlayerTextDrawBackgroundColor, | |
PlayerTextDrawBoxColor, | |
PlayerTextDrawColor, | |
PlayerTextDrawDestroy, | |
PlayerTextDrawFont, | |
PlayerTextDrawHide, | |
PlayerTextDrawLetterSize, | |
PlayerTextDrawSetOutline, | |
PlayerTextDrawSetPreviewModel, | |
PlayerTextDrawSetPreviewRot, | |
PlayerTextDrawSetProportional, | |
PlayerTextDrawSetSelectable, | |
PlayerTextDrawSetShadow, | |
PlayerTextDrawSetString, | |
PlayerTextDrawShow, | |
PlayerTextDrawTextSize, | |
PlayerTextDrawUseBox, | |
SelectTextDraw, | |
TextDrawAlignment, | |
TextDrawBackgroundColor, | |
TextDrawBoxColor, | |
TextDrawColor, | |
TextDrawCreate, | |
TextDrawFont, | |
TextDrawHideForPlayer, | |
TextDrawLetterSize, | |
TextDrawSetOutline, | |
TextDrawSetProportional, | |
TextDrawSetSelectable, | |
TextDrawSetShadow, | |
TextDrawShowForPlayer, | |
TextDrawTextSize, | |
TextDrawUseBox, | |
) | |
ITEMS_PER_PAGE = 18 | |
_static_graphics = None | |
_player_menus = {} | |
class StaticGraphics: | |
"""Contains static graphics elements (background, etc) textdraws.""" | |
def __init__(self): | |
self.background = background = TextDrawCreate( | |
531.333374, | |
140.877777, | |
'_' | |
) | |
TextDrawBackgroundColor(background, 0) | |
TextDrawAlignment(background, 1) | |
TextDrawFont(background, 0) | |
TextDrawLetterSize(background, 0.000000, 22.912965) | |
TextDrawColor(background, 0) | |
TextDrawSetOutline(background, 0) | |
TextDrawSetProportional(background, 1) | |
TextDrawSetShadow(background, 0) | |
TextDrawUseBox(background, 1) | |
TextDrawBoxColor(background, 0x000000DD) | |
TextDrawTextSize(background, 121.333328, 0.000000) | |
TextDrawSetSelectable(background, 0) | |
self.right_arrow = right_arrow = TextDrawCreate( | |
521.333374, | |
339.318542, | |
'LD_BEAT:right' | |
) | |
TextDrawLetterSize(right_arrow, 0.000000, 0.000000) | |
TextDrawTextSize(right_arrow, 5.999938, 7.051818) | |
TextDrawAlignment(right_arrow, 1) | |
TextDrawColor(right_arrow, 0xC0C0C0FF) | |
TextDrawSetShadow(right_arrow, 0) | |
TextDrawSetOutline(right_arrow, 0) | |
TextDrawFont(right_arrow, 4) | |
TextDrawSetSelectable(right_arrow, True) | |
self.left_arrow = left_arrow = TextDrawCreate( | |
507.000305, | |
339.074066, | |
'LD_BEAT:left' | |
) | |
TextDrawLetterSize(left_arrow, 0.000000, 0.000000) | |
TextDrawTextSize(left_arrow, 5.999938, 7.051818) | |
TextDrawAlignment(left_arrow, 1) | |
TextDrawColor(left_arrow, 0xC0C0C0FF) | |
TextDrawSetShadow(left_arrow, 0) | |
TextDrawSetOutline(left_arrow, 0) | |
TextDrawFont(left_arrow, 4) | |
TextDrawSetSelectable(left_arrow, True) | |
self.top_banner = top_banner = TextDrawCreate( | |
531.000244, | |
155.811111, | |
'TopBanner' | |
) | |
TextDrawLetterSize(top_banner, 0.000000, -0.447120) | |
TextDrawTextSize(top_banner, 121.333328, 0.000000) | |
TextDrawAlignment(top_banner, 1) | |
TextDrawColor(top_banner, 0) | |
TextDrawUseBox(top_banner, True) | |
TextDrawBoxColor(top_banner, 0x808080FF) | |
TextDrawSetShadow(top_banner, 0) | |
TextDrawSetOutline(top_banner, 0) | |
TextDrawFont(top_banner, 0) | |
self.bottom_banner = bottom_banner = TextDrawCreate( | |
531.333618, | |
338.500305, | |
'BottomBanner' | |
) | |
TextDrawLetterSize(bottom_banner, 0.000000, -0.447120) | |
TextDrawTextSize(bottom_banner, 120.666656, 0.000000) | |
TextDrawAlignment(bottom_banner, 1) | |
TextDrawColor(bottom_banner, 0) | |
TextDrawUseBox(bottom_banner, True) | |
TextDrawBoxColor(bottom_banner, 0x808080FF) | |
TextDrawSetShadow(bottom_banner, 0) | |
TextDrawSetOutline(bottom_banner, 0) | |
TextDrawFont(bottom_banner, 0) | |
self.close_button = close_button = TextDrawCreate( | |
490.666809, | |
337.829711, | |
'CLOSE' | |
) | |
TextDrawLetterSize(close_button, 0.128333, 0.957036) | |
TextDrawTextSize(close_button, 10.5021, 10.0187) | |
TextDrawAlignment(close_button, 2) | |
TextDrawColor(close_button, 0xC0C0C0FF) | |
TextDrawSetShadow(close_button, 0) | |
TextDrawSetOutline(close_button, 0) | |
TextDrawBackgroundColor(close_button, 0x00000033) | |
TextDrawFont(close_button, 2) | |
TextDrawSetProportional(close_button, 1) | |
TextDrawSetSelectable(close_button, True) | |
def show(self, playerid): | |
TextDrawShowForPlayer(playerid, self.right_arrow) | |
TextDrawShowForPlayer(playerid, self.left_arrow) | |
TextDrawShowForPlayer(playerid, self.background) | |
TextDrawShowForPlayer(playerid, self.top_banner) | |
TextDrawShowForPlayer(playerid, self.bottom_banner) | |
TextDrawShowForPlayer(playerid, self.close_button) | |
def hide(self, playerid): | |
TextDrawHideForPlayer(playerid, self.right_arrow) | |
TextDrawHideForPlayer(playerid, self.left_arrow) | |
TextDrawHideForPlayer(playerid, self.background) | |
TextDrawHideForPlayer(playerid, self.top_banner) | |
TextDrawHideForPlayer(playerid, self.bottom_banner) | |
TextDrawHideForPlayer(playerid, self.close_button) | |
@dataclass | |
class MenuItem: | |
"""A menu item containing a 3D model and a text label.""" | |
model_id: int | |
text: str = '' | |
rot_x: float = 0. | |
rot_y: float = 0. | |
rot_z: float = 0. | |
zoom: float = 1. | |
@dataclass | |
class Menu: | |
"""A menu that has a title and a list of menu items.""" | |
title: str | |
items: List[MenuItem] = field(default_factory=list) | |
on_select: Callable[[int, MenuItem], None] = lambda playerid, item: None | |
on_cancel: Callable[[int], None] = lambda playerid: None | |
def add(self, item): | |
if item in self.items: | |
raise ValueError( | |
f'Adding the same menu item to the same menu twice: {item:r}' | |
) | |
self.items.append(item) | |
def remove(self, item): | |
if item not in self.items: | |
raise ValueError( | |
f'Removing menu item not present in menu: {item:r}' | |
) | |
self.items.remove(item) | |
def show(self, playerid): | |
global _player_menus | |
if not IsPlayerConnected(playerid): | |
return | |
if _player_menus.get(playerid): | |
_player_menus[playerid].hide() | |
_player_menus[playerid] = player_menu = PlayerMenu(self, playerid) | |
player_menu.show() | |
@dataclass | |
class PlayerMenu: | |
"""A menu that is being shown to a player. Handles paging, etc.""" | |
menu: Menu | |
playerid: int | |
_show_time: int = 0 | |
_current_page: int = 0 | |
_total_pages: int = 0 | |
_paging_text: int = INVALID_TEXT_DRAW | |
_header_text: int = INVALID_TEXT_DRAW | |
_item_models: List[int] = field(default_factory=list) | |
_item_texts: List[int] = field(default_factory=list) | |
def __post_init__(self): | |
# eg. 18 items in list, 18 items per page, should be one. | |
# Same for 17, but not for 19. | |
# This will also be zero if there's no items. | |
self._total_pages = (len(self.menu.items) - 1) // ITEMS_PER_PAGE + 1 | |
def show(self): | |
if not _static_graphics: | |
raise RuntimeError( | |
f"{__name__} module isn't initialized. " | |
f"Did you forget to pyload('{__name__.partition('.')[2]}')?" | |
) | |
self._show_time = GetTickCount() | |
self._destroy_player_textdraws() | |
self._create_player_textdraws() | |
for index, item in enumerate(self.menu.items[:ITEMS_PER_PAGE]): | |
self._show_item_at_index(item, index) | |
playerid = self.playerid | |
PlayerTextDrawSetString( | |
playerid, | |
self._paging_text, | |
f'1/{self._total_pages}' | |
) | |
PlayerTextDrawSetString(playerid, self._header_text, self.menu.title) | |
PlayerTextDrawShow(playerid, self._paging_text) | |
PlayerTextDrawShow(playerid, self._header_text) | |
_static_graphics.show(playerid) | |
SelectTextDraw(playerid, 0xFFFFFFFF) | |
def hide(self): | |
global _player_menus | |
playerid = self.playerid | |
self._destroy_player_textdraws() | |
_static_graphics.hide(playerid) | |
CancelSelectTextDraw(playerid) | |
del _player_menus[playerid] | |
def set_page(self, page): | |
if not (0 <= page < self._total_pages): | |
return | |
playerid = self.playerid | |
for item_model, item_text in zip(self._item_models, self._item_texts): | |
PlayerTextDrawHide(playerid, item_model) | |
PlayerTextDrawHide(playerid, item_text) | |
start_index = ITEMS_PER_PAGE * page | |
for index, item in enumerate( | |
self.menu.items[start_index:start_index + ITEMS_PER_PAGE] | |
): | |
self._show_item_at_index(item, index) | |
self._current_page = page | |
PlayerTextDrawSetString( | |
playerid, | |
self._paging_text, | |
f'{page + 1}/{self._total_pages}' | |
) | |
def next_page(self): | |
if self._current_page >= self._total_pages - 1: | |
return | |
self.set_page(self._current_page + 1) | |
def previous_page(self): | |
if self._current_page <= 0: | |
return | |
self.set_page(self._current_page - 1) | |
def showed_at_least(self, ticks): | |
return GetTickCount() - self._show_time >= ticks | |
def get_clicked_item(self, playertextid): | |
item_models = self._item_models | |
if playertextid not in item_models: | |
return None | |
return self.menu.items[ | |
self._current_page * ITEMS_PER_PAGE | |
+ item_models.index(playertextid) | |
] | |
def on_select(self, item): | |
self.menu.on_select(self.playerid, item) | |
def on_cancel(self): | |
self.menu.on_cancel(self.playerid) | |
def _create_player_textdraws(self): | |
playerid = self.playerid | |
self._paging_text = paging_text = CreatePlayerTextDraw( | |
playerid, | |
523.333251, | |
139.792648, | |
'0/1' | |
) | |
PlayerTextDrawLetterSize(playerid, paging_text, 0.190666, 1.110518) | |
PlayerTextDrawAlignment(playerid, paging_text, 3) | |
PlayerTextDrawColor(playerid, paging_text, 0xC0C0C0FF) | |
PlayerTextDrawSetShadow(playerid, paging_text, 0) | |
PlayerTextDrawSetOutline(playerid, paging_text, 1) | |
PlayerTextDrawBackgroundColor(playerid, paging_text, 0x00000033) | |
PlayerTextDrawFont(playerid, paging_text, 2) | |
PlayerTextDrawSetProportional(playerid, paging_text, 1) | |
self._header_text = header_text = CreatePlayerTextDraw( | |
playerid, | |
128.333312, | |
139.377761, | |
'header' | |
) | |
PlayerTextDrawLetterSize(playerid, header_text, 0.315000, 1.247407) | |
PlayerTextDrawAlignment(playerid, header_text, 1) | |
PlayerTextDrawColor(playerid, header_text, 0xC0C0C0FF) | |
PlayerTextDrawSetShadow(playerid, header_text, 0) | |
PlayerTextDrawSetOutline(playerid, header_text, 1) | |
PlayerTextDrawBackgroundColor(playerid, header_text, 0x00000033) | |
PlayerTextDrawFont(playerid, header_text, 2) | |
PlayerTextDrawSetProportional(playerid, header_text, 1) | |
item_models, item_texts = self._item_models, self._item_texts | |
origin = (140., 162.) | |
for index, item in enumerate(self.menu.items): | |
if index >= ITEMS_PER_PAGE: | |
break | |
# Hard-coded because that's how it was | |
current_col = index % 6 | |
current_line = index // 6 | |
current_coords = ( | |
origin[0] + 62 * current_col, | |
origin[1] + 55 * current_line, | |
) | |
item_model = CreatePlayerTextDraw( | |
playerid, | |
current_coords[0], | |
current_coords[1], | |
'_' | |
) | |
item_models.append(item_model) | |
PlayerTextDrawBackgroundColor(playerid, item_model, 0xD3D3D344) | |
PlayerTextDrawFont(playerid, item_model, 5) | |
PlayerTextDrawLetterSize(playerid, item_model, 1.430000, 5.700000) | |
PlayerTextDrawColor(playerid, item_model, 0xC0C0C0FF) | |
PlayerTextDrawSetOutline(playerid, item_model, 1) | |
PlayerTextDrawSetProportional(playerid, item_model, 1) | |
PlayerTextDrawUseBox(playerid, item_model, 1) | |
PlayerTextDrawBoxColor(playerid, item_model, 0) | |
PlayerTextDrawTextSize(playerid, item_model, 61.000000, 54.000000) | |
PlayerTextDrawSetSelectable(playerid, item_model, 1) | |
item_text = CreatePlayerTextDraw( | |
playerid, | |
current_coords[0] + 31, | |
current_coords[1], '_' | |
) | |
item_texts.append(item_text) | |
PlayerTextDrawFont(playerid, item_text, 2) | |
PlayerTextDrawLetterSize(playerid, item_text, 0.199999, 0.6) | |
PlayerTextDrawAlignment(playerid, item_text, 2) | |
PlayerTextDrawSetOutline(playerid, item_text, 0) | |
PlayerTextDrawSetProportional(playerid, item_text, 1) | |
PlayerTextDrawTextSize(playerid, item_text, 0.0, 62.0) | |
PlayerTextDrawSetShadow(playerid, item_text, 0) | |
PlayerTextDrawColor(playerid, item_text, 0xD3D3D3AA) | |
def _destroy_player_textdraws(self): | |
playerid = self.playerid | |
PlayerTextDrawDestroy(playerid, self._paging_text) | |
PlayerTextDrawDestroy(playerid, self._header_text) | |
self._paging_text = INVALID_TEXT_DRAW | |
self._header_text = INVALID_TEXT_DRAW | |
for item_model, item_text in zip(self._item_models, self._item_texts): | |
PlayerTextDrawDestroy(playerid, item_model) | |
PlayerTextDrawDestroy(playerid, item_text) | |
self._item_models = [] | |
self._item_texts = [] | |
def _show_item_at_index(self, item, index): | |
playerid = self.playerid | |
item_model = self._item_models[index] | |
PlayerTextDrawSetPreviewModel(playerid, item_model, item.model_id) | |
PlayerTextDrawSetPreviewRot( | |
playerid, | |
item_model, | |
item.rot_x, | |
item.rot_y, | |
item.rot_z, | |
item.zoom | |
) | |
PlayerTextDrawShow(playerid, item_model) | |
if item.text: | |
item_text = self._item_texts[index] | |
PlayerTextDrawSetString(playerid, item_text, item.text) | |
PlayerTextDrawShow(playerid, item_text) | |
def OnGameModeInit(): | |
global _static_graphics | |
_static_graphics = StaticGraphics() | |
def OnPlayerClickTextDraw(playerid, clickedid): | |
global _static_graphics, _player_menus | |
if not _player_menus.get(playerid): | |
return | |
player_menu = _player_menus[playerid] | |
# Handle on_select showing another Menu | |
if not player_menu.showed_at_least(600): | |
return | |
if clickedid in (INVALID_TEXT_DRAW, _static_graphics.close_button): | |
player_menu.on_cancel() | |
player_menu.hide() | |
elif clickedid == _static_graphics.right_arrow: | |
player_menu.next_page() | |
elif clickedid == _static_graphics.left_arrow: | |
player_menu.previous_page() | |
def OnPlayerClickPlayerTextDraw(playerid, playertextid): | |
global _static_graphics, _player_menus | |
if not _player_menus.get(playerid): | |
return | |
player_menu = _player_menus[playerid] | |
# Handle on_select showing another Menu | |
if not player_menu.showed_at_least(600): | |
return | |
item = player_menu.get_clicked_item(playertextid) | |
if not item: | |
return | |
player_menu.hide() | |
player_menu.on_select(item) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment