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

rebase #35

Merged
merged 7 commits into from
Sep 13, 2024
Merged
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
2 changes: 1 addition & 1 deletion .github/docker/php/php.ini
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
upload_max_filesize = 100M
post_max_size = 100M
memory_limit = 256M
memory_limit = 1024M
variables_order = "EGPCS"
153 changes: 51 additions & 102 deletions app/Badges/Components/TextField.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,116 +104,65 @@ public function __construct(
* @return ImageInterface The image with the drawn text.
*/
protected function drawTextInBox(ImageInterface $image, PointInterface $position): ImageInterface
{
$fontSize = $this->startFontSize; // Startet mit der anfänglichen Schriftgröße
$lines = []; // Array zum Speichern der Zeilen des Textes
$palette = new RGB(); // Erzeuge eine RGB-Palette

do {
// Wenn der Text ein zusammenhängender String ohne Leerzeichen ist, füge das gesamte Wort in die Zeile ein
if (strpos($this->text, ' ') === false) {
$lines = [$this->text];
$font = new Font($this->font_path, $fontSize, $this->font_color);
$textBox = $font->box($this->text);

// Überprüft, ob der gesamte String in die Breite passt
if ($textBox->getWidth() > $this->width) {
$fontSize--; // Reduziert die Schriftgröße, wenn der Text nicht passt
} else {
break; // Passt, keine weiteren Änderungen erforderlich
}
} else {
// Teilt den Text in Wörter auf
$words = explode(' ', $this->text);
$lines = [];
$currentLine = '';

// Erstelle die Font-Instanz für die aktuelle Schleife
$font = new Font($this->font_path, $fontSize, $this->font_color);

// Verarbeitet jedes Wort und fügt es zur aktuellen Zeile hinzu
foreach ($words as $word) {
$testLine = $currentLine . ($currentLine ? ' ' : '') . $word;
$textBox = $font->box($testLine);

// Überprüft, ob die aktuelle Zeile in die Breite passt
if ($textBox->getWidth() > $this->width) {
if (!empty($currentLine)) {
$lines[] = $currentLine;
}
$currentLine = $word;
} else {
$currentLine = $testLine;
}
}
$lines[] = $currentLine;

// Überprüft, ob die Anzahl der Zeilen die maximale Anzahl überschreitet
if (count($lines) > $this->maxRows) {
$fontSize--; // Reduziert die Schriftgröße, wenn zu viele Zeilen vorhanden sind
} else {
break;
}
}
} while ($fontSize >= $this->minFontSize);
{
$fontSize = $this->startFontSize; // Startet mit der anfänglichen Schriftgröße
$palette = new RGB(); // Erzeuge eine RGB-Palette

// Erstelle die Font-Instanz mit finaler Schriftgröße
do {
// Berechne die Box-Größe mit der aktuellen Schriftgröße
$font = new Font($this->font_path, $fontSize, $this->font_color);
$textBox = $font->box($this->text);

// Berechnet die vertikale Startposition, um den Text zentriert zu platzieren
$y = $position->getY() + ($this->height - (count($lines) * $fontSize)) / 2;

// Zeichne Hintergrundfarbe und Rahmen, wenn angegeben
$drawer = $image->draw();
if ($this->backgroundColor || $this->borderColor) {
$box = new Box($this->width, $this->height);
$boxEnd = new Point($position->getX() + $this->width, $position->getY() + $this->height);

if ($this->backgroundColor) {
// Erzeuge ein Rechteck mit der Hintergrundfarbe
$drawer->rectangle($position, $boxEnd, $this->backgroundColor, true);
}

if ($this->borderThickness > 0 && $this->borderColor) {
// Zeichne den Rahmen
$drawer->rectangle($position, $boxEnd, $this->borderColor, false, $this->borderThickness);
// Überprüft, ob der Text in die Box passt
if ($textBox->getWidth() > $this->width || $textBox->getHeight() > $this->height) {
$fontSize--; // Reduziert die Schriftgröße, wenn der Text zu groß ist
} else {
break; // Passt, keine weiteren Änderungen erforderlich
}
} while ($fontSize >= $this->minFontSize);

// Berechne die vertikale Position, um den Text zentriert zu platzieren
$y = $position->getY() + ($this->height - $textBox->getHeight()) / 2;
// Berechne die horizontale Position basierend auf der Ausrichtung (zentriert, links oder rechts)
$x = $this->calculateXPosition($textBox->getWidth(), $position);

// Zeichnet den Textumriss, falls angegeben
if ($this->textStrokeColor && $this->textStrokeThickness > 0) {
for ($offsetX = -$this->textStrokeThickness; $offsetX <= $this->textStrokeThickness; $offsetX++) {
for ($offsetY = -$this->textStrokeThickness; $offsetY <= $this->textStrokeThickness; $offsetY++) {
if ($offsetX !== 0 || $offsetY !== 0) {
$image->draw()->text(
$this->text,
new Font($this->font_path, $fontSize, $this->textStrokeColor),
new Point($x + $offsetX, $y + $offsetY)
);
}
}
}
}

// Zeichnet jede Zeile auf das Bild
foreach ($lines as $line) {
// Berechnet die X-Position basierend auf der Ausrichtung
$textBox = $font->box($line);

switch ($this->alignment) {
case TextAlignment::CENTER:
$x = $position->getX() + ($this->width - $textBox->getWidth()) / 2;
break;
case TextAlignment::RIGHT:
$x = $position->getX() + ($this->width - $textBox->getWidth());
break;
case TextAlignment::LEFT:
default:
$x = $position->getX(); // Linksbündig
break;
}
// Zeichnet den Text auf das Bild an der berechneten Position
$image->draw()->text($this->text, $font, new Point($x, $y));

// Zeichnet den Textumriss, falls angegeben
if ($this->textStrokeColor && $this->textStrokeThickness > 0) {
for ($offsetX = -$this->textStrokeThickness; $offsetX <= $this->textStrokeThickness; $offsetX++) {
for ($offsetY = -$this->textStrokeThickness; $offsetY <= $this->textStrokeThickness; $offsetY++) {
if ($offsetX !== 0 || $offsetY !== 0) {
$image->draw()->text($line, new Font($this->font_path, $fontSize, $this->textStrokeColor), new Point($x + $offsetX, $y + $offsetY));
}
}
}
}
return $image;
}

// Zeichnet den Text auf das Bild an der berechneten Position
$image->draw()->text($line, $font, new Point($x, $y));
$y += $fontSize; // Verschiebt die Y-Position für die nächste Zeile nach unten
}

return $image;

/**
* Berechnet die X-Position des Textes basierend auf der Ausrichtung.
*/
private function calculateXPosition(int $textWidth, PointInterface $position): int
{
switch ($this->alignment) {
case TextAlignment::CENTER:
return $position->getX() + ($this->width - $textWidth) / 2;
case TextAlignment::RIGHT:
return $position->getX() + ($this->width - $textWidth);
case TextAlignment::LEFT:
default:
return $position->getX(); // Linksbündig
}
}

}
20 changes: 10 additions & 10 deletions app/Badges/EF28_Badge.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,27 +175,27 @@ private function addFourthLayer(ImageInterface $badge_object)
// Position of the texts in the image
$position_attendee_id = new Point(
$this->width_px - 129, // X-Position (adapted)
42 // Y-Position
38 // Y-Position
);

$position_species = new Point(
$this->width_px - 321 - 160, // X-Position (adapted for the width of the text box)
$this->height_px - 67 - 222 // Y-Position
$this->height_px - 67 - 213 // Y-Position
);

$position_name = new Point(
$this->width_px - 321 - 160, // X-Position (adapted for the width of the text box)
$this->height_px - 67 - 348 // Y-Position
$this->height_px - 67 - 339 // Y-Position
);

$position_name_label = new Point(
$this->width_px - 321 - 260, // X-Position (adapted for the width of the text box)
$this->height_px - 67 - 357 // Y-Position
$this->height_px - 67 - 361 // Y-Position
);

$position_species_label = new Point(
$this->width_px - 321 - 275, // X-Position (adapted for the width of the text box)
$this->height_px - 67 - 230 // Y-Position
$this->height_px - 67 - 232 // Y-Position
);

$position_fursuit_badge = new Point(
Expand Down Expand Up @@ -223,7 +223,7 @@ private function addFourthLayer(ImageInterface $badge_object)
new TextField(
$text_species,
321, // Width of the text field
90, // Height of the text field
60, // Height of the text field
15, // Minimum font size
50, // Start font size
$font_path,
Expand All @@ -239,7 +239,7 @@ private function addFourthLayer(ImageInterface $badge_object)
new TextField(
$text_name,
321, // Width of the text field
90, // Height of the text field
60, // Height of the text field
15, // Minimum font size
50, // Start font size
$font_path,
Expand Down Expand Up @@ -314,7 +314,7 @@ private function addFifthLayer(ImageInterface $badge_object, Box $size)
$overlayImage->resize($size);

// Textposition
$position = new Point($this->width_px - 552, $this->height_px - 173);
$position = new Point($this->width_px - 558, $this->height_px - 182);

// Create color palette - Text color
$palette = new RGB();
Expand All @@ -326,11 +326,11 @@ private function addFifthLayer(ImageInterface $badge_object, Box $size)
$badge_object->paste($overlayImage, new Point(0, 0));

new TextField(
$this->addLetterSpacing(strtoupper($this->badge->fursuit->catch_code), 2),
$this->addLetterSpacing(strtoupper($this->badge->fursuit->catch_code), 1),
500, // Width of the text field
90, // Height of the text field
15, // Minimum font size
65, // Start font size
60, // Start font size
resource_path('badges/ef28/fonts/upcib.ttf'),
$font_color,
$badge_object,
Expand Down
144 changes: 144 additions & 0 deletions app/Filament/Resources/BadgeResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php

namespace App\Filament\Resources;

use App\Filament\Resources\BadgeResource\Pages;
use App\Jobs\Printing\PrintBadgeJob;
use App\Models\Badge\Badge;
use App\Models\Badge\States\BadgeStatusState;
use App\Models\Badge\States\Pending;
use App\Models\Badge\States\PickedUp;
use App\Models\Badge\States\Printed;
use App\Models\Badge\States\ReadyForPickup;
use App\Models\Fursuit\States\FursuitStatusState;
use App\Models\Machine;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Collection;

class BadgeResource extends Resource
{
protected static ?string $model = Badge::class;

protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';

public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Select::make('fursuit_id')
->label('Fursuit')
->disabled()
->relationship('fursuit', 'name')
->required(),
// Status
Forms\Components\Select::make('status')
->label('Status')
->options(BadgeStatusState::getStateMapping()->keys()->mapWithKeys(fn($key) => [$key => ucfirst($key)]))
->required(),
Forms\Components\Group::make([
// Total
Forms\Components\TextInput::make('total')
->label('Total'),
// Tax
Forms\Components\TextInput::make('tax')
->label('Tax')
->disabled(),
// Subtotal
Forms\Components\TextInput::make('subtotal')
->label('Sub-Total')
->disabled(),
])->columnSpanFull()->columns(3)
]);
}

public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('fursuit.user.attendee_id')
->sortable()
->label('Fursuit'),
Tables\Columns\TextColumn::make('fursuit.name')
->label('Fursuit'),
Tables\Columns\TextColumn::make('status')->badge()->colors([
Pending::$name => 'default',
Printed::$name => 'success',
ReadyForPickup::$name => 'success',
PickedUp::$name => 'warning',
]),
])
->filters([
Tables\Filters\SelectFilter::make('status')
->options(BadgeStatusState::getStateMapping()->keys()->mapWithKeys(fn($key) => [ucfirst($key) => $key]))
->label('Badge Status'),
Tables\Filters\SelectFilter::make('fursuit_status')
->options(FursuitStatusState::getStateMapping()->keys()->mapWithKeys(fn($key) => [$key => ucfirst($key)]))
->query(function (Builder $query, array $data) {
$query->when($data, fn($query, $data) => $query->whereHas('fursuit', function (Builder $query) use ($data) {
$query->where('status', $data);
}));
})
->label('Fursuit Status'),
// Duplex Bool Filter
Tables\Filters\TernaryFilter::make('dual_side_print')
->label('Double Sided'),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\Action::make('printBadge')
->color('warning')
->icon('heroicon-o-printer')
->requiresConfirmation(true)
->label('Print Badge')
->action(function (Badge $record) {
return static::printBadge($record);
}),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
Tables\Actions\BulkAction::make('printBadgeBulk')
->label('Print Badge')
->requiresConfirmation()
->action(function (Collection $records) {
return $records->reverse()->each(fn(Badge $record, $index) => static::printBadge($record, $index));
}),
])
->selectCurrentPageOnly()
->paginationPageOptions([10, 25, 50, 100])
->defaultSort('fursuit.user.attendee_id', 'asc');
}

public static function printBadge(Badge $badge,$mass = 0): Badge
{
if ($badge->status !== Printed::class && $badge->status->canTransitionTo(Printed::class)) {
$badge->status->transitionTo(Printed::class);
}
// Add delay for mass printing so they are generated in order
PrintBadgeJob::dispatch($badge, Machine::first())->delay(now()->addSeconds($mass * 15));
return $badge;
}

public static function getRelations(): array
{
return [
//
];
}

public static function getPages(): array
{
return [
'index' => Pages\ListBadges::route('/'),
'create' => Pages\CreateBadge::route('/create'),
'edit' => Pages\EditBadge::route('/{record}/edit'),
];
}
}
Loading
Loading