feat: you can summary screen shot directly
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
//go:build darwin
|
||||
|
||||
package main
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c -fobjc-arc -fblocks
|
||||
#cgo LDFLAGS: -framework AppKit -framework QuartzCore
|
||||
#include <stdlib.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
static NSPanel *operationPanel = nil;
|
||||
static NSTextField *operationTitleLabel = nil;
|
||||
static NSTextField *operationDetailLabel = nil;
|
||||
static NSTextField *operationIconLabel = nil;
|
||||
static NSProgressIndicator *operationSpinner = nil;
|
||||
|
||||
static NSString *statusString(const char *value) {
|
||||
if (value == NULL) {
|
||||
return @"";
|
||||
}
|
||||
NSString *text = [NSString stringWithUTF8String:value];
|
||||
return text ?: @"";
|
||||
}
|
||||
|
||||
static void ensureOperationPanel(void) {
|
||||
if (operationPanel != nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSRect frame = NSMakeRect(0, 0, 360, 118);
|
||||
operationPanel = [[NSPanel alloc]
|
||||
initWithContentRect:frame
|
||||
styleMask:NSWindowStyleMaskBorderless
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
[operationPanel setOpaque:NO];
|
||||
[operationPanel setBackgroundColor:[NSColor clearColor]];
|
||||
[operationPanel setLevel:NSFloatingWindowLevel];
|
||||
[operationPanel setHidesOnDeactivate:NO];
|
||||
[operationPanel setCollectionBehavior:
|
||||
NSWindowCollectionBehaviorCanJoinAllSpaces |
|
||||
NSWindowCollectionBehaviorFullScreenAuxiliary |
|
||||
NSWindowCollectionBehaviorStationary];
|
||||
|
||||
NSView *root = [[NSView alloc] initWithFrame:frame];
|
||||
[root setWantsLayer:YES];
|
||||
[[root layer] setCornerRadius:14];
|
||||
[[root layer] setBackgroundColor:[[NSColor colorWithCalibratedWhite:0.08 alpha:0.92] CGColor]];
|
||||
[[root layer] setShadowColor:[[NSColor blackColor] CGColor]];
|
||||
[[root layer] setShadowOpacity:0.28];
|
||||
[[root layer] setShadowRadius:18];
|
||||
[[root layer] setShadowOffset:CGSizeMake(0, -8)];
|
||||
|
||||
operationSpinner = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(24, 42, 34, 34)];
|
||||
[operationSpinner setStyle:NSProgressIndicatorStyleSpinning];
|
||||
[operationSpinner setIndeterminate:YES];
|
||||
|
||||
operationIconLabel = [NSTextField labelWithString:@"OK"];
|
||||
[operationIconLabel setFrame:NSMakeRect(21, 43, 42, 30)];
|
||||
[operationIconLabel setAlignment:NSTextAlignmentCenter];
|
||||
[operationIconLabel setFont:[NSFont systemFontOfSize:17 weight:NSFontWeightSemibold]];
|
||||
[operationIconLabel setTextColor:[NSColor colorWithCalibratedRed:74.0/255.0 green:222.0/255.0 blue:128.0/255.0 alpha:1.0]];
|
||||
[operationIconLabel setHidden:YES];
|
||||
|
||||
operationTitleLabel = [NSTextField labelWithString:@""];
|
||||
[operationTitleLabel setFrame:NSMakeRect(76, 61, 260, 24)];
|
||||
[operationTitleLabel setFont:[NSFont systemFontOfSize:15 weight:NSFontWeightSemibold]];
|
||||
[operationTitleLabel setTextColor:[NSColor whiteColor]];
|
||||
|
||||
operationDetailLabel = [NSTextField labelWithString:@""];
|
||||
[operationDetailLabel setFrame:NSMakeRect(76, 34, 260, 22)];
|
||||
[operationDetailLabel setFont:[NSFont systemFontOfSize:12 weight:NSFontWeightRegular]];
|
||||
[operationDetailLabel setTextColor:[NSColor colorWithCalibratedWhite:0.82 alpha:1.0]];
|
||||
[operationDetailLabel setLineBreakMode:NSLineBreakByTruncatingTail];
|
||||
|
||||
[root addSubview:operationSpinner];
|
||||
[root addSubview:operationIconLabel];
|
||||
[root addSubview:operationTitleLabel];
|
||||
[root addSubview:operationDetailLabel];
|
||||
[operationPanel setContentView:root];
|
||||
}
|
||||
|
||||
static void snipShowOperationStatus(const char *titleC, const char *detailC, int state) {
|
||||
NSString *title = statusString(titleC);
|
||||
NSString *detail = statusString(detailC);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
ensureOperationPanel();
|
||||
[operationTitleLabel setStringValue:title];
|
||||
[operationDetailLabel setStringValue:detail];
|
||||
|
||||
if (state == 0) {
|
||||
[operationIconLabel setHidden:YES];
|
||||
[operationSpinner setHidden:NO];
|
||||
[operationSpinner startAnimation:nil];
|
||||
} else {
|
||||
[operationSpinner stopAnimation:nil];
|
||||
[operationSpinner setHidden:YES];
|
||||
[operationIconLabel setHidden:NO];
|
||||
if (state == 2) {
|
||||
[operationIconLabel setStringValue:@"!"];
|
||||
[operationIconLabel setTextColor:[NSColor colorWithCalibratedRed:248.0/255.0 green:113.0/255.0 blue:113.0/255.0 alpha:1.0]];
|
||||
} else {
|
||||
[operationIconLabel setStringValue:@"OK"];
|
||||
[operationIconLabel setTextColor:[NSColor colorWithCalibratedRed:74.0/255.0 green:222.0/255.0 blue:128.0/255.0 alpha:1.0]];
|
||||
}
|
||||
}
|
||||
|
||||
NSScreen *screen = [NSScreen mainScreen];
|
||||
if (screen != nil) {
|
||||
NSRect visible = [screen visibleFrame];
|
||||
NSRect panelFrame = [operationPanel frame];
|
||||
panelFrame.origin.x = NSMidX(visible) - panelFrame.size.width / 2;
|
||||
panelFrame.origin.y = NSMaxY(visible) - panelFrame.size.height - 48;
|
||||
[operationPanel setFrame:panelFrame display:YES];
|
||||
}
|
||||
[operationPanel orderFrontRegardless];
|
||||
});
|
||||
}
|
||||
|
||||
static void snipHideOperationStatus(void) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (operationPanel != nil) {
|
||||
[operationSpinner stopAnimation:nil];
|
||||
[operationPanel orderOut:nil];
|
||||
}
|
||||
});
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
operationStatusRunning = iota
|
||||
operationStatusSuccess
|
||||
operationStatusError
|
||||
)
|
||||
|
||||
var operationStatusSeq atomic.Uint64
|
||||
|
||||
func showOperationStatus(title, detail string, state int) {
|
||||
operationStatusSeq.Add(1)
|
||||
ctitle := C.CString(title)
|
||||
cdetail := C.CString(detail)
|
||||
defer C.free(unsafe.Pointer(ctitle))
|
||||
defer C.free(unsafe.Pointer(cdetail))
|
||||
C.snipShowOperationStatus(ctitle, cdetail, C.int(state))
|
||||
}
|
||||
|
||||
func hideOperationStatusAfter(delay time.Duration) {
|
||||
seq := operationStatusSeq.Load()
|
||||
time.AfterFunc(delay, func() {
|
||||
if operationStatusSeq.Load() == seq {
|
||||
C.snipHideOperationStatus()
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user