Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/gui/macosx/library/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 11 kB image not shown  

Quelle  VLCLibraryHeaderView.m  Sprache: unbekannt

 
Spracherkennung für: .m vermutete Sprache: Masm {Masm[58] ABAP[41] Cobol[40]} [Methode: maximale Elemente, drei Dimensionen]

/*****************************************************************************
 * VLCLibraryHeaderView.m: MacOS X interface module
 *****************************************************************************
 * Copyright (C) 2025 VLC authors and VideoLAN
 *
 * Authors: Claudio Cambra <developer@claudiocambra.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#import "VLCLibraryHeaderView.h"

#import "extensions/NSAppearance+VLCAdditions.h"
#import "extensions/NSColor+VLCAdditions.h"
#import "extensions/NSFont+VLCAdditions.h"
#import "extensions/NSString+Helpers.h"
#import "extensions/NSView+VLCAdditions.h"

#import "library/VLCLibraryRepresentedItem.h"

#import "views/VLCUIUnits.h"
#import "views/VLCVisualEffectView.h"

const CGFloat VLCLibraryHeaderViewHeight = 66.f;
NSString * const VLCLibraryHeaderViewIdentifier = @"VLCLibraryHeaderView";

@interface VLCLibraryHeaderView ()

@property NSView *backgroundView;
@property NSStackView *rootStackView;
@property NSStackView *labelsStackView;
@property NSStackView *buttonsStackView;
@property NSTextField *titleField;
@property NSTextField *detailField;
@property NSButton *playButton;
@property NSButton *queueButton;

@property CGFloat backgroundTopInset;
@property CGFloat backgroundBottomInset;

@end

@implementation VLCLibraryHeaderView

+ (CGFloat)internalPaddingHeight
{
    const CGFloat topInset = VLCUIUnits.largeSpacing + VLCUIUnits.mediumSpacing;
    CGFloat bottomInset = 0.f;
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 260000
    if (@available(macOS 26.0, *)) {
        bottomInset = VLCUIUnits.largeSpacing + VLCUIUnits.mediumSpacing + VLCUIUnits.smallSpacing;
    }
#endif
    return topInset + bottomInset;
}

+ (CGFloat)paddedHeaderViewHeight
{
    return VLCLibraryHeaderViewHeight + self.internalPaddingHeight;
}

+ (instancetype)paddedHeaderView
{
    const NSRect headerFrame = NSMakeRect(0.f, 0.f, 0.f, self.paddedHeaderViewHeight);
    VLCLibraryHeaderView * const headerView =
        [[self alloc] initWithFrame:headerFrame withInternalPaddingAddedForContentView:YES];
    headerView.autoresizingMask = NSViewWidthSizable;
    return headerView;
}

- (instancetype)initWithFrame:(NSRect)frameRect
{
    self = [super initWithFrame:frameRect];
    if (self) {
        [self commonInit];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
        [self commonInit];
    }
    return self;
}

- (instancetype)initWithFrame:(NSRect)frameRect withInternalPaddingAddedForContentView:(BOOL)internalPaddingAddedForContentView
{
    self = [super initWithFrame:frameRect];
    if (self) {
        _internalPaddingAddedForContentView = internalPaddingAddedForContentView;
        [self commonInit];
    }
    return self;
}

- (void)commonInit
{
    NSView *contentHostView = self;
    self.backgroundTopInset = VLCUIUnits.largeSpacing + VLCUIUnits.mediumSpacing;
    self.backgroundBottomInset = 0.f;

    if (@available(macOS 10.14, *)) {
        VLCVisualEffectView * const visualEffectView = [[VLCVisualEffectView alloc] initWithFrame:self.bounds];
        visualEffectView.translatesAutoresizingMaskIntoConstraints = NO;
        self.backgroundView = visualEffectView;
        contentHostView = visualEffectView.contentView;
        if (visualEffectView.usesGlassEffect) {
            self.backgroundBottomInset = VLCUIUnits.largeSpacing + VLCUIUnits.mediumSpacing + VLCUIUnits.smallSpacing;
        }
    } else {
        NSView * const fallbackBackgroundView = [[NSView alloc] initWithFrame:self.bounds];
        fallbackBackgroundView.translatesAutoresizingMaskIntoConstraints = NO;
        fallbackBackgroundView.wantsLayer = YES;
        fallbackBackgroundView.layer.backgroundColor = NSColor.windowBackgroundColor.CGColor;
        self.backgroundView = fallbackBackgroundView;
        contentHostView = fallbackBackgroundView;
    }

    [self addSubview:self.backgroundView];

    self.titleField = [self buildLabelWithFont:NSFont.VLClibrarySectionHeaderFont
                                      textColor:NSColor.labelColor
                                      alignment:NSTextAlignmentLeft];
    self.detailField = [self buildLabelWithFont:NSFont.VLCLibrarySubsectionSubheaderFont
                                       textColor:NSColor.secondaryLabelColor
                                       alignment:NSTextAlignmentLeft];
    self.playButton = [self buildActionButtonWithTitle:_NS("Play") action:@selector(play:)];
    self.queueButton = [self buildActionButtonWithTitle:_NS("Queue") action:@selector(enqueue:)];

    NSStackView * const labelsStack = [NSStackView stackViewWithViews:@[self.titleField, self.detailField]];
    labelsStack.translatesAutoresizingMaskIntoConstraints = NO;
    labelsStack.orientation = NSUserInterfaceLayoutOrientationVertical;
    labelsStack.alignment = NSLayoutAttributeLeading;
    labelsStack.spacing = VLCUIUnits.smallSpacing;
    [labelsStack setContentHuggingPriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationHorizontal];
    [labelsStack setContentCompressionResistancePriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationHorizontal];
    self.labelsStackView = labelsStack;

    NSStackView * const buttonsStack = [NSStackView stackViewWithViews:@[self.playButton, self.queueButton]];
    buttonsStack.translatesAutoresizingMaskIntoConstraints = NO;
    buttonsStack.orientation = NSUserInterfaceLayoutOrientationHorizontal;
    buttonsStack.alignment = NSLayoutAttributeCenterY;
    buttonsStack.spacing = VLCUIUnits.smallSpacing;
    [buttonsStack setContentHuggingPriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationHorizontal];
    [buttonsStack setContentCompressionResistancePriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationHorizontal];
    self.buttonsStackView = buttonsStack;

    [contentHostView addSubview:labelsStack];
    [contentHostView addSubview:buttonsStack];

    const CGFloat horizontalContentInset = VLCUIUnits.mediumSpacing;

    [NSLayoutConstraint activateConstraints:@[
        [labelsStack.leadingAnchor constraintEqualToAnchor:contentHostView.leadingAnchor constant:horizontalContentInset],
        [labelsStack.centerYAnchor constraintEqualToAnchor:contentHostView.centerYAnchor],
        [contentHostView.trailingAnchor constraintEqualToAnchor:buttonsStack.trailingAnchor constant:horizontalContentInset],
        [buttonsStack.centerYAnchor constraintEqualToAnchor:contentHostView.centerYAnchor],
        [buttonsStack.leadingAnchor constraintGreaterThanOrEqualToAnchor:labelsStack.trailingAnchor constant:VLCUIUnits.largeSpacing],
    ]];
    [self updateBackgroundConstraints];

    self.layer = [CALayer new];
    self.layer.backgroundColor = NSColor.clearColor.CGColor;
    self.layer.masksToBounds = NO;

    if (@available(macOS 26.0, *)) {
    } else {
        self.backgroundView.layer.borderColor = NSColor.VLCSubtleBorderColor.CGColor;
        self.backgroundView.layer.borderWidth = VLCUIUnits.borderThickness;
        self.backgroundView.layer.cornerRadius = VLCUIUnits.cornerRadius;
        self.backgroundView.layer.masksToBounds = YES;

        if (@available(macOS 10.14, *)) {
            [NSApplication.sharedApplication addObserver:self
                                            forKeyPath:@"effectiveAppearance"
                                                options:NSKeyValueObservingOptionNew
                                                context:nil];
        }
    }
}

- (void)updateBackgroundConstraints
{
    if (!self.internalPaddingAddedForContentView) {
        [self.backgroundView applyConstraintsToFillSuperview];
        return;
    }
    [NSLayoutConstraint activateConstraints:@[
        [self.backgroundView.topAnchor constraintEqualToAnchor:self.topAnchor constant:self.backgroundTopInset],
        [self.backgroundView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
        [self.backgroundView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
        [self.backgroundView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-self.backgroundBottomInset],
    ]];
}

- (void)setInternalPaddingAddedForContentView:(BOOL)internalPaddingAddedForContentView
{
    if (_internalPaddingAddedForContentView == internalPaddingAddedForContentView) return;
    _internalPaddingAddedForContentView = internalPaddingAddedForContentView;
    [self updateBackgroundConstraints];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary<NSKeyValueChangeKey,id> *)change
                       context:(void *)context
{
    if (@available(macOS 26.0, *)) {
        return;
    } else if ([keyPath isEqualToString:@"effectiveAppearance"]) {
        if (@available(macOS 10.14, *))  {
            NSAppearance * const appearance = change[NSKeyValueChangeNewKey];
            const BOOL isDark = appearance.shouldShowDarkAppearance;
            self.backgroundView.layer.borderColor = isDark ?
                NSColor.VLCDarkSubtleBorderColor.CGColor : NSColor.VLCLightSubtleBorderColor.CGColor;
        }
    }
}

- (NSTextField *)buildLabelWithFont:(NSFont *)font textColor:(NSColor *)color alignment:(NSTextAlignment)alignment
{
    NSTextField *label = [NSTextField labelWithString:@""];
    label.font = font;
    label.textColor = color;
    label.alignment = alignment;
    label.lineBreakMode = NSLineBreakByTruncatingTail;
    label.translatesAutoresizingMaskIntoConstraints = NO;
    return label;
}

- (NSButton *)buildActionButtonWithTitle:(NSString *)title action:(SEL)selector
{
    NSButton *button = [NSButton buttonWithTitle:title target:self action:selector];
    button.bezelStyle = NSBezelStyleRounded;
    button.translatesAutoresizingMaskIntoConstraints = NO;
    if (@available(macOS 10.14, *))
        button.contentTintColor = NSColor.VLCAccentColor;
    return button;
}

- (void)setRepresentedItem:(VLCLibraryRepresentedItem *)representedItem
{
    _representedItem = representedItem;
    [self applyRepresentedItemWithFallbackTitle:nil fallbackDetail:nil];
}

- (void)applyRepresentedItemWithFallbackTitle:(NSString *)fallbackTitle fallbackDetail:(NSString *)fallbackDetail
{
    id<VLCMediaLibraryItemProtocol> const item = self.representedItem.item;
    if (item == nil) {
        self.titleField.stringValue = fallbackTitle ?: @"";
        self.detailField.stringValue = fallbackDetail ?: @"";
        self.playButton.enabled = NO;
        self.queueButton.enabled = NO;
        return;
    }

    self.titleField.stringValue = item.displayString ?: fallbackTitle ?: @"";
    self.detailField.stringValue = item.primaryDetailString ?: fallbackDetail ?: @"";
    self.playButton.enabled = YES;
    self.queueButton.enabled = YES;
}

- (void)updateWithRepresentedItem:(VLCLibraryRepresentedItem *)representedItem
                    fallbackTitle:(NSString *)fallbackTitle
                   fallbackDetail:(NSString *)fallbackDetail
{
    self.representedItem = representedItem;
    [self applyRepresentedItemWithFallbackTitle:fallbackTitle fallbackDetail:fallbackDetail];
}

#pragma mark - Actions

- (void)play:(id)sender
{
    [self.representedItem play];
}

- (void)enqueue:(id)sender
{
    [self.representedItem queue];
}

@end

[Dauer der Verarbeitung: 0.2 Sekunden, vorverarbeitet 2026-10-24]