* @copyright 2014-2020 ManiaControl Team * @license http://www.gnu.org/licenses/ GNU General Public License, Version 3 */ class ElementBuilder { /** * Constants */ const COLUMN_ACTION_WIDTH = 4; const COLUMN_ACTION_WIDTH_MIN = 20; const COLUMN_ENTRY_WIDTH = 4; const FOOTER_BUTTON_HEIGHT = 4; const FOOTER_HEIGHT = 5; const FOOTER_SPACING = 2; const FOOTER_SPACING_BOTTOM = 10; const HEADER_HEIGHT = 5; const HEADER_SPACING = 2; const HEADER_WIDTH_FACTOR = 0.9; const ROW_LINE_HEIGHT = 4; const ROW_SPACING_BOTTOM = 5; const ROW_SPACING_SIDES = 2; const ROW_SPACING_TOP = 5; const DEFAULT_KARMA_PLUGIN = 'MCTeam\KarmaPlugin'; /** * Private Properties */ /** @var array $actions */ private $actions = array(); /** @var array $columns */ private $columns = array(); /** @var callable $entryCurrent */ private $entryCurrent = null; /** @var array $footerButtons */ private $footerButtons = array(); /** @var Frame $headerFrame */ private $headerFrame = null; /** @var array $rowData */ private $rowData = array(); /** * Construct a new ElementBuilder instance * * @param ManiaControl $maniaControl */ public function __construct(ManiaControl $maniaControl) { $this->maniaControl = $maniaControl; } /** * Adds actions to list entry * @param string $icon * @param bool $confirmation * @param callable $tooltipFunction */ public function addAction($icon, $confirmation, $tooltipFunction) { array_push($this->actions, array($icon, $confirmation, $tooltipFunction)); } /** * Adds a column to the list * @param string $name * @param float $widthFactor * @param callable $dataFunction */ public function addColumn($name, $widthFactor, $dataFunction) { array_push($this->columns, array($name, $widthFactor, $dataFunction)); } /** * Adds a arrow to point to the current/personal entry * @param callable $function */ public function addEntryCurrent($function) { $this->entryCurrent = $function; } /** * Adds a footer button to the list * @param string $description * @param string $action * @param callable $tooltipFunction */ public function addFooterButton($description, $action, $tooltipFunction = null) { array_push($this->footerButtons, array($description, $action, $tooltipFunction)); } /** * Adds a header frame to the list * @param Frame $headerFrame */ public function addHeaderFrame(Frame $headerFrame) { $this->headerFrame = $headerFrame; $this->headerFrame->setHeight(self::HEADER_HEIGHT); $this->headerFrame->setWidth($this->getHeaderFrameWidth()); } /** * Adds rows to the list * @param array $rows */ public function addRows(array $rows) { $this->rowData = array_merge($this->rowData, $rows); } /** * Build Round Text Button * @param string $description * @param float $width * @param float $height * @param string $action * @param string $logoUrl */ public function buildRoundTextButton($description, $width, $height, $action, $logoUrl = null) { $frame = new Frame(); $quad = new Quad_BgsPlayerCard(); $frame->addChild($quad); $quad->setAction($action); $quad->setSize($width, $height); $quad->setSubStyle($quad::SUBSTYLE_BgPlayerCardBig); $quad->setZ(-1); $label = new Label_Button(); $frame->addChild($label); $label->setText($description); $label->setTextSize($height / 4); $label->setZ(1); if ($logoUrl) { $logoQuad = new Quad(); $frame->addChild($logoQuad); $logoQuad->setImageUrl($logoUrl); $logoQuad->setSize(0.75*$height, 0.75*$height); $logoQuad->setX(-$width/2 + 0.75*$height); $logoQuad->setZ(1); $label->setHorizontalAlign($label::RIGHT); $label->setX($width/2 - 0.5*$height); } return $frame; } /** * Build Karma Gauge * @param Map|MXMapInfo $map * @param float $width * @param float $height * @param float $textSize */ public function buildKarmaGauge($map, $width, $height, $textSize = 0.9) { $karmaPlugin = $this->maniaControl->getPluginManager()->getPlugin(self::DEFAULT_KARMA_PLUGIN); if (!$karmaPlugin) { return null; } // default elements $frame = new Frame(); $karmaGauge = new Gauge(); $frame->addChild($karmaGauge); $karmaGauge->setDrawBackground(false); $karmaGauge->setSize($width, $height); $karmaGauge->setZ(-1); $karmaLabel = new Label_Text(); $frame->addChild($karmaLabel); $karmaLabel->setSize($width/2, $height * $textSize); $karmaLabel->setStyle($this->maniaControl->getManialinkManager()->getStyleManager()->getDefaultLabelStyle()); $karmaLabel->setTextColor('fff'); $karmaLabel->setTextSize($textSize); $karmaLabel->setY(-$height/50); $karmaLabel->setZ(1); // fetch MX Karma $displayMxKarma = $this->maniaControl->getSettingManager()->getSettingValue($karmaPlugin, $karmaPlugin::SETTING_WIDGET_DISPLAY_MX); $karma = null; $votes = null; $mxInfo = null; if ($map instanceof Map && isset($map->mx)) { $mxInfo = $map->mx; } elseif ($map instanceof MXMapInfo) { $mxInfo = $map; } if ($displayMxKarma && $mxInfo) { $karma = $mxInfo->ratingVoteAverage / 100; $votes = array("count" => $mxInfo->ratingVoteCount); } elseif ($map instanceof Map) { $karma = $karmaPlugin->getMapKarma($map); $votes = $karmaPlugin->getMapVotes($map); } if (!is_numeric($karma) || $votes['count'] <= 0) { // No Karma $karmaGauge->setColor('00fb'); $karmaGauge->setRatio(0.); $karmaLabel->setText('-'); return $frame; } // Karma available $karma = floatval($karma); $karmaText = ''; if ($this->maniaControl->getSettingManager()->getSettingValue($karmaPlugin, $karmaPlugin::SETTING_NEWKARMA)) { $karmaText = ' ' . round($karma * 100.) . '% (' . $votes['count'] . ')'; } else { $minus = 0; $plus = 0; foreach ($votes as $vote) { if (!isset($vote->vote) || $vote->vote === 0.5) { continue; } if ($vote->vote < 0.5) { $minus += $vote->count; } else { $plus += $vote->count; } } $endKarma = $plus - $minus; $karmaText = ' ' . $endKarma . ' (' . $votes['count'] . 'x / ' . round($karma * 100.) . '%)'; } $karmaColor = ColorUtil::floatToStatusColor($karma); $karmaGauge->setColor($karmaColor . '8'); $karmaGauge->setRatio(0.15 + 0.85*$karma); $karmaLabel->setText($karmaText); return $frame; } /** * Returns the width of the optional header frame * * @return int */ public function getHeaderFrameWidth() { return (int) (self::HEADER_WIDTH_FACTOR * $this->maniaControl->getManialinkManager()->getStyleManager()->getListWidgetsWidth()); } public function renderList(Player $player) { $nbActions = count($this->actions); $nbFooterButtons = count($this->footerButtons); $hasActions = $nbActions > 0; $hasEntryCurrent = $this->entryCurrent !== null; $hasFooter = $nbFooterButtons > 0; $hasHeader = $this->headerFrame !== null; $height = $this->maniaControl->getManialinkManager()->getStyleManager()->getListWidgetsHeight(); $width = $this->maniaControl->getManialinkManager()->getStyleManager()->getListWidgetsWidth(); $heightRows = $height - self::ROW_SPACING_TOP - self::ROW_SPACING_BOTTOM; $posYRows = $height/2 - self::ROW_SPACING_TOP - self::ROW_LINE_HEIGHT/2; // Create ManiaLink $maniaLink = new ManiaLink(ManialinkManager::MAIN_MLID); $script = $maniaLink->getScript(); $paging = new Paging(); $script->addFeature($paging); // Main frame $frame = $this->maniaControl->getManialinkManager()->getStyleManager()->getDefaultListFrame($script, $paging); $maniaLink->addChild($frame); // Header frame if ($hasHeader) { $frame->addChild($this->headerFrame); $this->headerFrame->setY($height/2 - self::HEADER_SPACING - self::HEADER_HEIGHT/2); $headerSize = 2*self::HEADER_SPACING + self::HEADER_HEIGHT; $heightRows -= $headerSize; if ($posYRows > $height/2 - $headerSize) $posYRows = $height/2 - $headerSize; } // Footer if ($hasFooter) { $nbFooterSections = 3*$nbFooterButtons + 1; $buttonSpacing = (1. / $nbFooterSections) * $width; $buttonWidth = $buttonSpacing * 2; for ($i = 0; $i < $nbFooterButtons; $i++) { list($description, $action, $tooltipFunction) = $this->footerButtons[$i]; $label = new Label_Button(); $frame->addChild($label); $label->setHeight(self::FOOTER_HEIGHT); $label->setText($description); $label->setTextSize(1); $label->setWidth($buttonWidth); $label->setX(-$width/2 + ($i+1)*$buttonSpacing + $i*$buttonWidth + $buttonWidth/2); $label->setY(-$height/2 + self::FOOTER_SPACING_BOTTOM); $label->setZ(0.1); $quad = new Quad_BgsPlayerCard(); $frame->addChild($quad); $quad->setAction($action); $quad->setHeight(self::FOOTER_HEIGHT); $quad->setSubStyle($quad::SUBSTYLE_BgPlayerCardBig); $quad->setWidth($buttonWidth); $quad->setX(-$width/2 + ($i+1)*$buttonSpacing + $i*$buttonWidth + $buttonWidth/2); $quad->setY(-$height/2 + self::FOOTER_SPACING_BOTTOM); $quad->setZ(0.01); } $footerSize = self::FOOTER_SPACING_BOTTOM + self::FOOTER_HEIGHT + self::FOOTER_SPACING; $heightRows -= $footerSize; } $actionsWidth = max(self::COLUMN_ACTION_WIDTH_MIN, $nbActions * self::COLUMN_ACTION_WIDTH); $baseColumnPosX = -$width / 2 + self::ROW_SPACING_SIDES + self::COLUMN_ENTRY_WIDTH; $baseRowPosY = $posYRows; $baseColumnWidth = $width - 2*self::ROW_SPACING_SIDES - self::COLUMN_ENTRY_WIDTH - $actionsWidth; $nbRows = (int) ($heightRows / self::ROW_LINE_HEIGHT) - 1; // Description Row $descriptionFrame = new Frame(); $frame->addChild($descriptionFrame); $descriptionFrame->setX($baseColumnPosX); $descriptionFrame->setY($baseRowPosY); $labelLine = new LabelLine($descriptionFrame); $columnPosX = self::ROW_SPACING_SIDES; if ($hasEntryCurrent) { $columnPosX += self::COLUMN_ENTRY_WIDTH; } foreach ($this->columns as $column) { list($name, $widthFactor, $dataFunction) = $column; $labelLine->addLabelEntryText($name, $columnPosX); $columnPosX += $widthFactor * $baseColumnWidth; } $labelLine->addLabelEntryText('Actions', $columnPosX); $labelLine->render(); // Data Rows $pageFrame = null; $columnPosX = self::ROW_SPACING_SIDES; $baseRowPosY -= self::ROW_LINE_HEIGHT; $rowPosY = $baseRowPosY; $pageNumber = 1; for ($i = 0; $i < count($this->rowData); $i++) { $data = $this->rowData[$i]; if ($i % $nbRows === 0) { $pageFrame = new Frame(); $frame->addChild($pageFrame); $paging->addPageControl($pageFrame, $pageNumber); $pageNumber++; $rowPosY = $baseRowPosY; } $playerFrame = new Frame(); $pageFrame->addChild($playerFrame); $playerFrame->setX($baseColumnPosX); $playerFrame->setY($rowPosY); if ($i % 2 === 1) { $lineQuad = new Quad_BgsPlayerCard(); $playerFrame->addChild($lineQuad); $lineQuad->setSize($width, self::ROW_LINE_HEIGHT); $lineQuad->setSubStyle($lineQuad::SUBSTYLE_BgPlayerCardBig); $lineQuad->setZ(-1); } if ($hasEntryCurrent) { } $rowPosY -= self::ROW_LINE_HEIGHT; } $this->maniaControl->getManialinkManager()->sendManialink($maniaLink, $player); $this->reset(); } /** * Resets the internal builder data */ private function reset() { $this->actions = array(); $this->columns = array(); $this->entryCurrent = null; $this->footerButtons = array(); $this->headerFrame = null; $this->rowData = array(); } }