diff options
Diffstat (limited to 'src/osx')
29 files changed, 0 insertions, 3216 deletions
diff --git a/src/osx/CMakeLists.txt b/src/osx/CMakeLists.txt deleted file mode 100644 index 0a8bb7af..00000000 --- a/src/osx/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -add_library(CruPlatformBaseOsx SHARED - Resource.cpp -) - -find_library(FOUNDATION Foundation REQUIRED) -find_library(CORE_FOUNDATION CoreFoundation REQUIRED) - -target_link_libraries(CruPlatformBaseOsx PUBLIC CruPlatformBase ${FOUNDATION} ${CORE_FOUNDATION}) - -add_subdirectory(graphics) -add_subdirectory(gui) diff --git a/src/osx/Resource.cpp b/src/osx/Resource.cpp deleted file mode 100644 index dbf15d48..00000000 --- a/src/osx/Resource.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "cru/osx/Resource.h" diff --git a/src/osx/graphics/CMakeLists.txt b/src/osx/graphics/CMakeLists.txt deleted file mode 100644 index 980c2f93..00000000 --- a/src/osx/graphics/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(quartz) diff --git a/src/osx/graphics/quartz/Brush.cpp b/src/osx/graphics/quartz/Brush.cpp deleted file mode 100644 index cfb8f635..00000000 --- a/src/osx/graphics/quartz/Brush.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "cru/osx/graphics/quartz/Brush.h" -#include "cru/common/String.h" -#include "cru/common/Format.h" - -namespace cru::platform::graphics::osx::quartz { -QuartzSolidColorBrush::QuartzSolidColorBrush(IGraphicsFactory* graphics_factory, - const Color& color) - : QuartzBrush(graphics_factory), color_(color) { - cg_color_ = - CGColorCreateGenericRGB(color.GetFloatRed(), color.GetFloatGreen(), - color.GetFloatBlue(), color.GetFloatAlpha()); - Ensures(cg_color_); -} - -QuartzSolidColorBrush::~QuartzSolidColorBrush() { CGColorRelease(cg_color_); } - -void QuartzSolidColorBrush::SetColor(const Color& color) { - color_ = color; - CGColorRelease(cg_color_); - cg_color_ = - CGColorCreateGenericRGB(color.GetFloatRed(), color.GetFloatGreen(), - color.GetFloatBlue(), color.GetFloatAlpha()); - Ensures(cg_color_); -} - -void QuartzSolidColorBrush::Select(CGContextRef context) { - Expects(context); - Expects(cg_color_); - CGContextSetStrokeColorWithColor(context, cg_color_); - CGContextSetFillColorWithColor(context, cg_color_); -} - -String QuartzSolidColorBrush::GetDebugString() { - return Format(u"QuartzSolidColorBrush(Color: {})", color_); -} -} // namespace cru::platform::graphics::osx::quartz diff --git a/src/osx/graphics/quartz/CMakeLists.txt b/src/osx/graphics/quartz/CMakeLists.txt deleted file mode 100644 index 1fcaff26..00000000 --- a/src/osx/graphics/quartz/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -add_library(CruPlatformGraphicsQuartz SHARED - Brush.cpp - Convert.cpp - Factory.cpp - Font.cpp - Geometry.cpp - Image.cpp - ImageFactory.cpp - Painter.cpp - Resource.cpp - TextLayout.cpp -) - -find_library(CORE_GRAPHICS CoreGraphics REQUIRED) -find_library(CORE_TEXT CoreText REQUIRED) -find_library(IMAGE_IO ImageIO REQUIRED) - -target_link_libraries(CruPlatformGraphicsQuartz PUBLIC ${CORE_GRAPHICS} ${CORE_TEXT} ${IMAGE_IO}) -target_link_libraries(CruPlatformGraphicsQuartz PUBLIC CruPlatformBaseOsx CruPlatformGraphics) diff --git a/src/osx/graphics/quartz/Convert.cpp b/src/osx/graphics/quartz/Convert.cpp deleted file mode 100644 index df62a206..00000000 --- a/src/osx/graphics/quartz/Convert.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "cru/osx/graphics/quartz/Convert.h" -#include <cstdint> - -namespace cru::platform::graphics::osx::quartz { - -CGPoint Convert(const Point& point) { return CGPoint{point.x, point.y}; } -Point Convert(const CGPoint& point) { return Point(point.x, point.y); } - -CGSize Convert(const Size& size) { return CGSize{size.width, size.height}; } -Size Convert(const CGSize& size) { return Size(size.width, size.height); } - -CGAffineTransform Convert(const Matrix& matrix) { - return CGAffineTransformMake(matrix.m11, matrix.m12, matrix.m21, matrix.m22, - matrix.m31, matrix.m32); -} - -Matrix Convert(const CGAffineTransform& matrix) { - return Matrix(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty); -} - -CGRect Convert(const Rect& rect) { - return CGRect{CGPoint{rect.left, rect.top}, CGSize{rect.width, rect.height}}; -} - -Rect Convert(const CGRect& rect) { - return Rect{static_cast<float>(rect.origin.x), - static_cast<float>(rect.origin.y), - static_cast<float>(rect.size.width), - static_cast<float>(rect.size.height)}; -} - -const CGDataProviderSequentialCallbacks kStreamToCGDataProviderCallbacks{ - 1, - [](void* stream, void* buffer, size_t size) -> size_t { - return static_cast<io::Stream*>(stream)->Read( - static_cast<std::byte*>(buffer), size); - }, - [](void* stream, off_t offset) -> off_t { - auto s = static_cast<io::Stream*>(stream); - auto current_position = s->Tell(); - s->Seek(offset, io::Stream::SeekOrigin::Current); - return s->Tell() - current_position; - }, - [](void* stream) { static_cast<io::Stream*>(stream)->Rewind(); }, - [](void* stream) {}}; - -CGDataProviderRef ConvertStreamToCGDataProvider(io::Stream* stream) { - return CGDataProviderCreateSequential(stream, - &kStreamToCGDataProviderCallbacks); -} - -const CGDataConsumerCallbacks kStreamToCGDataConsumerCallbacks{ - [](void* info, const void* buffer, size_t count) -> size_t { - return static_cast<io::Stream*>(info)->Write( - static_cast<const std::byte*>(buffer), count); - }, - [](void* info) {}}; - -CGDataConsumerRef ConvertStreamToCGDataConsumer(io::Stream* stream) { - return CGDataConsumerCreate(stream, &kStreamToCGDataConsumerCallbacks); -} - -} // namespace cru::platform::graphics::osx::quartz diff --git a/src/osx/graphics/quartz/Factory.cpp b/src/osx/graphics/quartz/Factory.cpp deleted file mode 100644 index 283341e5..00000000 --- a/src/osx/graphics/quartz/Factory.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "cru/osx/graphics/quartz/Factory.h" - -#include "cru/osx/graphics/quartz/Brush.h" -#include "cru/osx/graphics/quartz/Font.h" -#include "cru/osx/graphics/quartz/Geometry.h" -#include "cru/osx/graphics/quartz/ImageFactory.h" -#include "cru/osx/graphics/quartz/TextLayout.h" -#include "cru/platform/Check.h" -#include "cru/platform/graphics/ImageFactory.h" - -#include <memory> - -namespace cru::platform::graphics::osx::quartz { -QuartzGraphicsFactory::QuartzGraphicsFactory() - : OsxQuartzResource(this), image_factory_(new QuartzImageFactory(this)) {} - -QuartzGraphicsFactory::~QuartzGraphicsFactory() {} - -std::unique_ptr<ISolidColorBrush> -QuartzGraphicsFactory::CreateSolidColorBrush() { - return std::make_unique<QuartzSolidColorBrush>(this, colors::black); -} - -std::unique_ptr<IGeometryBuilder> -QuartzGraphicsFactory::CreateGeometryBuilder() { - return std::make_unique<QuartzGeometryBuilder>(this); -} - -std::unique_ptr<IFont> QuartzGraphicsFactory::CreateFont(String font_family, - float font_size) { - return std::make_unique<OsxCTFont>(this, font_family, font_size); -} - -std::unique_ptr<ITextLayout> QuartzGraphicsFactory::CreateTextLayout( - std::shared_ptr<IFont> font, String text) { - auto f = CheckPlatform<OsxCTFont>(font, GetPlatformId()); - return std::make_unique<OsxCTTextLayout>(this, f, text); -} - -IImageFactory* QuartzGraphicsFactory::GetImageFactory() { - return image_factory_.get(); -} -} // namespace cru::platform::graphics::osx::quartz diff --git a/src/osx/graphics/quartz/Font.cpp b/src/osx/graphics/quartz/Font.cpp deleted file mode 100644 index a1b8bac2..00000000 --- a/src/osx/graphics/quartz/Font.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "cru/osx/graphics/quartz/Font.h" - -#include "cru/osx/Convert.h" -#include "cru/osx/graphics/quartz/Convert.h" -#include "cru/osx/graphics/quartz/Resource.h" - -namespace cru::platform::graphics::osx::quartz { -using cru::platform::osx::Convert; - -OsxCTFont::OsxCTFont(IGraphicsFactory* graphics_factory, const String& name, - float size) - : OsxQuartzResource(graphics_factory), name_(name) { - CFStringRef n = Convert(name); - - if (name.empty()) { - ct_font_ = - CTFontCreateUIFontForLanguage(kCTFontUIFontSystem, size, nullptr); - } else { - ct_font_ = CTFontCreateWithName(n, size, nullptr); - } - Ensures(ct_font_); - - CFRelease(n); -} - -OsxCTFont::~OsxCTFont() { CFRelease(ct_font_); } - -String OsxCTFont::GetFontName() { return name_; } -float OsxCTFont::GetFontSize() { return CTFontGetSize(ct_font_); } -} // namespace cru::platform::graphics::osx::quartz diff --git a/src/osx/graphics/quartz/Geometry.cpp b/src/osx/graphics/quartz/Geometry.cpp deleted file mode 100644 index c88add87..00000000 --- a/src/osx/graphics/quartz/Geometry.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "cru/osx/graphics/quartz/Geometry.h" -#include "cru/osx/graphics/quartz/Convert.h" - -#include <memory> - -namespace cru::platform::graphics::osx::quartz { -QuartzGeometry::QuartzGeometry(IGraphicsFactory *graphics_factory, - CGPathRef cg_path) - : OsxQuartzResource(graphics_factory), cg_path_(cg_path) {} - -QuartzGeometry::~QuartzGeometry() { CGPathRelease(cg_path_); } - -bool QuartzGeometry::FillContains(const Point &point) { - return CGPathContainsPoint(cg_path_, nullptr, CGPoint{point.x, point.y}, - kCGPathFill); -} - -Rect QuartzGeometry::GetBounds() { - auto bounds = CGPathGetPathBoundingBox(cg_path_); - if (CGRectIsNull(bounds)) return {}; - return Convert(bounds); -} - -std::unique_ptr<IGeometry> QuartzGeometry::Transform(const Matrix &matrix) { - auto cg_matrix = Convert(matrix); - auto cg_path = CGPathCreateCopyByTransformingPath(cg_path_, &cg_matrix); - return std::make_unique<QuartzGeometry>(GetGraphicsFactory(), cg_path); -} - -std::unique_ptr<IGeometry> QuartzGeometry::CreateStrokeGeometry(float width) { - auto cg_path = CGPathCreateCopyByStrokingPath( - cg_path_, nullptr, width, kCGLineCapButt, kCGLineJoinMiter, 10); - return std::make_unique<QuartzGeometry>(GetGraphicsFactory(), cg_path); -} - -QuartzGeometryBuilder::QuartzGeometryBuilder(IGraphicsFactory *graphics_factory) - : OsxQuartzResource(graphics_factory) { - cg_mutable_path_ = CGPathCreateMutable(); -} - -QuartzGeometryBuilder::~QuartzGeometryBuilder() { - CGPathRelease(cg_mutable_path_); -} - -Point QuartzGeometryBuilder::GetCurrentPosition() { - return Convert(CGPathGetCurrentPoint(cg_mutable_path_)); -} - -void QuartzGeometryBuilder::MoveTo(const Point &point) { - CGPathMoveToPoint(cg_mutable_path_, nullptr, point.x, point.y); -} - -void QuartzGeometryBuilder::LineTo(const Point &point) { - CGPathAddLineToPoint(cg_mutable_path_, nullptr, point.x, point.y); -} - -void QuartzGeometryBuilder::CubicBezierTo(const Point &start_control_point, - const Point &end_control_point, - const Point &end_point) { - CGPathAddCurveToPoint(cg_mutable_path_, nullptr, start_control_point.x, - start_control_point.y, end_control_point.x, - end_control_point.y, end_point.x, end_point.y); -} - -void QuartzGeometryBuilder::QuadraticBezierTo(const Point &control_point, - const Point &end_point) { - CGPathAddQuadCurveToPoint(cg_mutable_path_, nullptr, control_point.x, - control_point.y, end_point.x, end_point.y); -} - -void QuartzGeometryBuilder::CloseFigure(bool close) { - if (close) CGPathCloseSubpath(cg_mutable_path_); -} - -std::unique_ptr<IGeometry> QuartzGeometryBuilder::Build() { - return std::make_unique<QuartzGeometry>(GetGraphicsFactory(), - CGPathCreateCopy(cg_mutable_path_)); -} -} // namespace cru::platform::graphics::osx::quartz diff --git a/src/osx/graphics/quartz/Image.cpp b/src/osx/graphics/quartz/Image.cpp deleted file mode 100644 index 28087000..00000000 --- a/src/osx/graphics/quartz/Image.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "cru/osx/graphics/quartz/Image.h" -#include "cru/common/Exception.h" -#include "cru/osx/graphics/quartz/Convert.h" -#include "cru/osx/graphics/quartz/Painter.h" - -namespace cru::platform::graphics::osx::quartz { -QuartzImage::QuartzImage(IGraphicsFactory* graphics_factory, - IImageFactory* image_factory, CGImageRef image, - bool auto_release, unsigned char* buffer) - : OsxQuartzResource(graphics_factory), - image_factory_(image_factory), - image_(image), - auto_release_(auto_release), - buffer_(buffer) { - Expects(image); -} - -QuartzImage::~QuartzImage() { - if (auto_release_) { - CGImageRelease(image_); - } -} - -float QuartzImage::GetWidth() { return CGImageGetWidth(image_); } - -float QuartzImage::GetHeight() { return CGImageGetHeight(image_); } - -std::unique_ptr<IImage> QuartzImage::CreateWithRect(const Rect& rect) { - auto new_cg_image = CGImageCreateWithImageInRect(image_, Convert(rect)); - - return std::make_unique<QuartzImage>(GetGraphicsFactory(), image_factory_, - new_cg_image, true); -} - -std::unique_ptr<IPainter> QuartzImage::CreatePainter() { - if (!buffer_) - throw Exception( - u"Failed to create painter for image because failed to get its " - u"buffer."); - - auto width = CGImageGetWidth(image_); - auto height = CGImageGetHeight(image_); - auto bits_per_component = CGImageGetBitsPerComponent(image_); - auto bytes_per_row = CGImageGetBytesPerRow(image_); - auto color_space = CGImageGetColorSpace(image_); - auto bitmap_info = CGImageGetBitmapInfo(image_); - - auto cg_context = - CGBitmapContextCreate(buffer_, width, height, bits_per_component, - bytes_per_row, color_space, bitmap_info); - - return std::make_unique<QuartzCGContextPainter>( - GetGraphicsFactory(), cg_context, true, Size(width, height), - [](QuartzCGContextPainter* painter) { - - }); -} -} // namespace cru::platform::graphics::osx::quartz diff --git a/src/osx/graphics/quartz/ImageFactory.cpp b/src/osx/graphics/quartz/ImageFactory.cpp deleted file mode 100644 index 5ff262c3..00000000 --- a/src/osx/graphics/quartz/ImageFactory.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "cru/osx/graphics/quartz/ImageFactory.h" -#include "cru/common/Exception.h" -#include "cru/common/platform/osx/Convert.h" -#include "cru/osx/graphics/quartz/Convert.h" -#include "cru/osx/graphics/quartz/Image.h" -#include "cru/platform/Check.h" -#include "cru/platform/graphics/Image.h" - -#include <ImageIO/ImageIO.h> - -namespace cru::platform::graphics::osx::quartz { -using cru::platform::osx::Convert; - -QuartzImageFactory::QuartzImageFactory(IGraphicsFactory* graphics_factory) - : OsxQuartzResource(graphics_factory) {} - -QuartzImageFactory::~QuartzImageFactory() {} - -std::unique_ptr<IImage> QuartzImageFactory::DecodeFromStream( - io::Stream* stream) { - CGDataProviderRef data_provider = ConvertStreamToCGDataProvider(stream); - CGImageSourceRef image_source = - CGImageSourceCreateWithDataProvider(data_provider, nullptr); - - CGImageRef cg_image = - CGImageSourceCreateImageAtIndex(image_source, 0, nullptr); - - CFRelease(image_source); - CGDataProviderRelease(data_provider); - - return std::unique_ptr<IImage>( - new QuartzImage(GetGraphicsFactory(), this, cg_image, true)); -} - -static String GetImageFormatUniformTypeIdentifier(ImageFormat format) { - switch (format) { - case ImageFormat::Png: - return u"public.png"; - case ImageFormat::Jpeg: - return u"public.jpeg"; - case ImageFormat::Gif: - return u"com.compuserve.gif"; - default: - throw Exception(u"Unknown image format."); - } -} - -void QuartzImageFactory::EncodeToStream(IImage* image, io::Stream* stream, - ImageFormat format, float quality) { - if (quality <= 0 || quality > 1) { - throw Exception(u"Invalid quality value."); - } - - auto quartz_image = CheckPlatform<QuartzImage>(image, GetPlatformId()); - auto cg_image = quartz_image->GetCGImage(); - - CFStringRef uti = Convert(GetImageFormatUniformTypeIdentifier(format)); - CGDataConsumerRef data_consumer = ConvertStreamToCGDataConsumer(stream); - CGImageDestinationRef destination = - CGImageDestinationCreateWithDataConsumer(data_consumer, uti, 1, nullptr); - - CFMutableDictionaryRef properties = - CFDictionaryCreateMutable(nullptr, 0, nullptr, nullptr); - CFNumberRef quality_wrap = - CFNumberCreate(nullptr, kCFNumberFloatType, &quality); - CFDictionaryAddValue(properties, kCGImageDestinationLossyCompressionQuality, - quality_wrap); - - CGImageDestinationAddImage(destination, cg_image, properties); - - if (!CGImageDestinationFinalize(destination)) { - throw Exception(u"Failed to finalize image destination."); - } - - CFRelease(quality_wrap); - CFRelease(properties); - CFRelease(destination); - CFRelease(data_consumer); - CFRelease(uti); -} - -std::unique_ptr<IImage> QuartzImageFactory::CreateBitmap(int width, - int height) { - if (width <= 0) throw Exception(u"Image width should be greater than 0."); - if (height <= 0) throw Exception(u"Image height should be greater than 0."); - - CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB(); - - const auto buffer_size = width * height * 4; - auto buffer = new unsigned char[buffer_size]{0}; - - auto cg_data_provider = CGDataProviderCreateWithData( - nullptr, buffer, buffer_size, - [](void* info, const void* data, size_t size) { - delete[] static_cast<const unsigned char*>(data); - }); - - auto cg_image = - CGImageCreate(width, height, 8, 32, 4 * width, color_space, - kCGImageAlphaPremultipliedLast, cg_data_provider, nullptr, - true, kCGRenderingIntentDefault); - - CGColorSpaceRelease(color_space); - CGDataProviderRelease(cg_data_provider); - - return std::unique_ptr<IImage>( - new QuartzImage(GetGraphicsFactory(), this, cg_image, true, buffer)); -} -} // namespace cru::platform::graphics::osx::quartz diff --git a/src/osx/graphics/quartz/Painter.cpp b/src/osx/graphics/quartz/Painter.cpp deleted file mode 100644 index a8c3715a..00000000 --- a/src/osx/graphics/quartz/Painter.cpp +++ /dev/null @@ -1,230 +0,0 @@ -#include "cru/osx/graphics/quartz/Painter.h" - -#include "cru/osx/graphics/quartz/Brush.h" -#include "cru/osx/graphics/quartz/Convert.h" -#include "cru/osx/graphics/quartz/Geometry.h" -#include "cru/osx/graphics/quartz/Image.h" -#include "cru/osx/graphics/quartz/TextLayout.h" -#include "cru/platform/Check.h" -#include "cru/platform/Color.h" -#include "cru/platform/Exception.h" - -namespace cru::platform::graphics::osx::quartz { -QuartzCGContextPainter::QuartzCGContextPainter( - IGraphicsFactory* graphics_factory, CGContextRef cg_context, - bool auto_release, const Size& size, - std::function<void(QuartzCGContextPainter*)> on_end_draw) - : OsxQuartzResource(graphics_factory), - cg_context_(cg_context), - auto_release_(auto_release), - size_(size), - on_end_draw_(std::move(on_end_draw)) { - Expects(cg_context); - - CGContextConcatCTM(cg_context_, - CGAffineTransformInvert(CGContextGetCTM(cg_context_))); - - transform_ = Matrix::Scale(1, -1) * Matrix::Translation(0, size.height); - CGContextConcatCTM(cg_context_, Convert(transform_)); -} - -QuartzCGContextPainter::~QuartzCGContextPainter() { - DoEndDraw(); - if (auto_release_) { - CGContextRelease(cg_context_); - cg_context_ = nullptr; - } -} - -Matrix QuartzCGContextPainter::GetTransform() { return transform_; } - -void QuartzCGContextPainter::SetTransform(const Matrix& matrix) { - CGContextConcatCTM(cg_context_, Convert(*transform_.Inverted())); - CGContextConcatCTM(cg_context_, Convert(matrix)); - transform_ = matrix; -} - -void QuartzCGContextPainter::ConcatTransform(const Matrix& matrix) { - CGContextConcatCTM(cg_context_, Convert(matrix)); - transform_ = matrix * transform_; -} - -void QuartzCGContextPainter::Clear(const Color& color) { - Validate(); - - CGContextSetRGBFillColor(cg_context_, color.GetFloatRed(), - color.GetFloatGreen(), color.GetFloatBlue(), - color.GetFloatAlpha()); - CGContextFillRect(cg_context_, Convert(Rect{Point{}, size_})); -} - -void QuartzCGContextPainter::DrawLine(const Point& start, const Point& end, - IBrush* brush, float width) { - Validate(); - - CGContextBeginPath(cg_context_); - CGContextMoveToPoint(cg_context_, start.x, start.y); - CGContextAddLineToPoint(cg_context_, end.x, end.y); - - QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId()); - b->Select(cg_context_); - SetLineWidth(width); - - CGContextStrokePath(cg_context_); -} - -void QuartzCGContextPainter::StrokeRectangle(const Rect& rectangle, - IBrush* brush, float width) { - Validate(); - - QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId()); - b->Select(cg_context_); - CGContextStrokeRectWithWidth(cg_context_, Convert(rectangle), width); -} - -void QuartzCGContextPainter::FillRectangle(const Rect& rectangle, - IBrush* brush) { - Validate(); - - QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId()); - b->Select(cg_context_); - CGContextFillRect(cg_context_, Convert(rectangle)); -} - -void QuartzCGContextPainter::StrokeEllipse(const Rect& outline_rect, - IBrush* brush, float width) { - Validate(); - - QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId()); - b->Select(cg_context_); - SetLineWidth(width); - - CGContextStrokeEllipseInRect(cg_context_, Convert(outline_rect)); -} - -void QuartzCGContextPainter::FillEllipse(const Rect& outline_rect, - IBrush* brush) { - Validate(); - - QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId()); - b->Select(cg_context_); - CGContextFillEllipseInRect(cg_context_, Convert(outline_rect)); -} - -void QuartzCGContextPainter::StrokeGeometry(IGeometry* geometry, IBrush* brush, - float width) { - Validate(); - - QuartzGeometry* g = CheckPlatform<QuartzGeometry>(geometry, GetPlatformId()); - QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId()); - - b->Select(cg_context_); - SetLineWidth(width); - - CGContextBeginPath(cg_context_); - CGContextAddPath(cg_context_, g->GetCGPath()); - CGContextStrokePath(cg_context_); -} - -void QuartzCGContextPainter::FillGeometry(IGeometry* geometry, IBrush* brush) { - Validate(); - - QuartzGeometry* g = CheckPlatform<QuartzGeometry>(geometry, GetPlatformId()); - QuartzBrush* b = CheckPlatform<QuartzBrush>(brush, GetPlatformId()); - - b->Select(cg_context_); - CGContextBeginPath(cg_context_); - CGContextAddPath(cg_context_, g->GetCGPath()); - CGContextEOFillPath(cg_context_); -} - -void QuartzCGContextPainter::DrawText(const Point& offset, - ITextLayout* text_layout, IBrush* brush) { - Validate(); - - auto tl = CheckPlatform<OsxCTTextLayout>(text_layout, GetPlatformId()); - - Color color; - - if (auto b = dynamic_cast<QuartzSolidColorBrush*>(brush)) { - color = b->GetColor(); - } else { - color = colors::black; - } - - Matrix transform = tl->GetTransform(); - - CGContextSaveGState(cg_context_); - - CGContextConcatCTM(cg_context_, Convert(transform * Matrix::Translation( - offset.x, offset.y))); - - auto frame = tl->CreateFrameWithColor(color); - Ensures(frame); - CTFrameDraw(frame, cg_context_); - CFRelease(frame); - - CGContextRestoreGState(cg_context_); -} - -void QuartzCGContextPainter::DrawImage(const Point& offset, IImage* image) { - Validate(); - auto i = CheckPlatform<QuartzImage>(image, GetPlatformId()); - - auto cg_image = i->GetCGImage(); - - auto width = CGImageGetWidth(cg_image); - auto height = CGImageGetHeight(cg_image); - - CGContextDrawImage(cg_context_, CGRectMake(offset.x, offset.y, width, height), - cg_image); -} - -void QuartzCGContextPainter::PushLayer(const Rect& bounds) { - Validate(); - clip_stack_.push_back(bounds); - CGContextClipToRect(cg_context_, Convert(bounds)); -} - -void QuartzCGContextPainter::PopLayer() { - Validate(); - clip_stack_.pop_back(); - if (clip_stack_.empty()) { - CGContextResetClip(cg_context_); - } else { - CGContextClipToRect(cg_context_, Convert(clip_stack_.back())); - } -} - -void QuartzCGContextPainter::PushState() { - Validate(); - CGContextSaveGState(cg_context_); -} - -void QuartzCGContextPainter::PopState() { - Validate(); - CGContextRestoreGState(cg_context_); -} - -void QuartzCGContextPainter::EndDraw() { DoEndDraw(); } - -void QuartzCGContextPainter::SetLineWidth(float width) { - if (cg_context_) { - CGContextSetLineWidth(cg_context_, width); - } -} - -void QuartzCGContextPainter::DoEndDraw() { - if (cg_context_) { - CGContextFlush(cg_context_); - CGContextSynchronize(cg_context_); - - on_end_draw_(this); - } -} - -void QuartzCGContextPainter::Validate() { - if (cg_context_ == nullptr) - throw ReuseException(u"QuartzCGContextPainter has already be released."); -} -} // namespace cru::platform::graphics::osx::quartz diff --git a/src/osx/graphics/quartz/Resource.cpp b/src/osx/graphics/quartz/Resource.cpp deleted file mode 100644 index 00bd5c94..00000000 --- a/src/osx/graphics/quartz/Resource.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "cru/osx/graphics/quartz/Resource.h" diff --git a/src/osx/graphics/quartz/TextLayout.cpp b/src/osx/graphics/quartz/TextLayout.cpp deleted file mode 100644 index 6013efba..00000000 --- a/src/osx/graphics/quartz/TextLayout.cpp +++ /dev/null @@ -1,456 +0,0 @@ -#include "cru/osx/graphics/quartz/TextLayout.h" -#include "cru/common/Base.h" -#include "cru/common/Format.h" -#include "cru/common/StringUtil.h" -#include "cru/osx/Convert.h" -#include "cru/osx/graphics/quartz/Convert.h" -#include "cru/osx/graphics/quartz/Resource.h" -#include "cru/platform/Check.h" -#include "cru/platform/graphics/Base.h" - -#include <algorithm> -#include <limits> - -namespace cru::platform::graphics::osx::quartz { -using cru::platform::osx::Convert; - -OsxCTTextLayout::OsxCTTextLayout(IGraphicsFactory* graphics_factory, - std::shared_ptr<OsxCTFont> font, - const String& str) - : OsxQuartzResource(graphics_factory), - max_width_(std::numeric_limits<float>::max()), - max_height_(std::numeric_limits<float>::max()), - font_(std::move(font)), - text_(str) { - Expects(font_); - - DoSetText(std::move(text_)); - - RecreateFrame(); -} - -OsxCTTextLayout::~OsxCTTextLayout() { - ReleaseResource(); - CFRelease(cf_attributed_text_); -} - -void OsxCTTextLayout::SetFont(std::shared_ptr<IFont> font) { - font_ = CheckPlatform<OsxCTFont>(font, GetPlatformId()); - RecreateFrame(); -} - -void OsxCTTextLayout::DoSetText(String text) { - text_ = std::move(text); - - if (text_.empty()) { - head_empty_line_count_ = 0; - tail_empty_line_count_ = 1; - - actual_text_ = {}; - } else { - head_empty_line_count_ = 0; - tail_empty_line_count_ = 0; - - for (auto i = text_.cbegin(); i != text_.cend(); ++i) { - if (*i == u'\n') { - head_empty_line_count_++; - } else { - break; - } - } - - for (auto i = text_.crbegin(); i != text_.crend(); ++i) { - if (*i == u'\n') { - tail_empty_line_count_++; - } else { - break; - } - } - - if (text_.size() == tail_empty_line_count_) { - head_empty_line_count_ = 1; - actual_text_ = {}; - } else { - actual_text_ = String(text_.cbegin() + head_empty_line_count_, - text_.cend() - tail_empty_line_count_); - } - } - - CFStringRef s = Convert(actual_text_); - cf_attributed_text_ = CFAttributedStringCreateMutable(nullptr, 0); - CFAttributedStringReplaceString(cf_attributed_text_, CFRangeMake(0, 0), s); - Ensures(cf_attributed_text_); - CFAttributedStringSetAttribute( - cf_attributed_text_, - CFRangeMake(0, CFAttributedStringGetLength(cf_attributed_text_)), - kCTFontAttributeName, font_->GetCTFont()); - CFRelease(s); -} - -void OsxCTTextLayout::SetText(String new_text) { - if (new_text == text_) return; - - CFRelease(cf_attributed_text_); - DoSetText(std::move(new_text)); - - RecreateFrame(); -} - -void OsxCTTextLayout::SetMaxWidth(float max_width) { - max_width_ = max_width; - RecreateFrame(); -} - -void OsxCTTextLayout::SetMaxHeight(float max_height) { - max_height_ = max_height; - RecreateFrame(); -} - -bool OsxCTTextLayout::IsEditMode() { return edit_mode_; } - -void OsxCTTextLayout::SetEditMode(bool enable) { - edit_mode_ = enable; - RecreateFrame(); -} - -Index OsxCTTextLayout::GetLineIndexFromCharIndex(Index char_index) { - if (char_index < 0 || char_index >= text_.size()) { - return -1; - } - - auto line_index = 0; - for (Index i = 0; i < char_index; ++i) { - if (text_[i] == u'\n') { - line_index++; - } - } - - return line_index; -} - -Index OsxCTTextLayout::GetLineCount() { return line_count_; } - -float OsxCTTextLayout::GetLineHeight(Index line_index) { - if (line_index < 0 || line_index >= line_count_) { - return 0.0f; - } - return line_heights_[line_index]; -} - -Rect OsxCTTextLayout::GetTextBounds(bool includingTrailingSpace) { - if (text_.empty() && edit_mode_) return Rect(0, 0, 0, font_->GetFontSize()); - - auto result = DoGetTextBoundsIncludingEmptyLines(includingTrailingSpace); - return Rect(0, 0, result.size.width, result.size.height); -} - -std::vector<Rect> OsxCTTextLayout::TextRangeRect(const TextRange& text_range) { - if (text_.empty()) return {}; - - auto tr = text_range; - tr = text_range.CoerceInto(head_empty_line_count_, - text_.size() - tail_empty_line_count_); - tr.position -= head_empty_line_count_; - - std::vector<CGRect> results = DoTextRangeRect(tr); - std::vector<Rect> r; - - for (auto& rect : results) { - r.push_back(transform_.TransformRect(Convert(rect))); - } - - return r; -} - -Rect OsxCTTextLayout::TextSinglePoint(Index position, bool trailing) { - Expects(position >= 0 && position <= text_.size()); - - if (text_.empty()) return {0, 0, 0, font_->GetFontSize()}; - - if (position < head_empty_line_count_) { - return {0, position * font_->GetFontSize(), 0, font_->GetFontSize()}; - } else if (position > text_.size() - tail_empty_line_count_) { - return { - 0, - static_cast<float>(text_bounds_without_trailing_space_.size.height) + - (head_empty_line_count_ + position - - (text_.size() - tail_empty_line_count_) - 1) * - font_->GetFontSize(), - 0, font_->GetFontSize()}; - } else { - auto result = - DoTextSinglePoint(position - head_empty_line_count_, trailing); - return transform_.TransformRect(Convert(result)); - } -} - -TextHitTestResult OsxCTTextLayout::HitTest(const Point& point) { - if (point.y < head_empty_line_count_ * font_->GetFontSize()) { - if (point.y < 0) { - return {0, false, false}; - } else { - for (int i = 1; i <= head_empty_line_count_; ++i) { - if (point.y < i * font_->GetFontSize()) { - return {i - 1, false, false}; - } - } - } - } - - auto text_bounds = text_bounds_without_trailing_space_; - - auto text_height = static_cast<float>(text_bounds.size.height); - auto th = text_height + head_empty_line_count_ * font_->GetFontSize(); - if (point.y >= th) { - for (int i = 1; i <= tail_empty_line_count_; ++i) { - if (point.y < th + i * font_->GetFontSize()) { - return {text_.size() - (tail_empty_line_count_ - i), false, false}; - } - } - return {text_.size(), false, false}; - } - - auto p = point; - p.y -= head_empty_line_count_ * font_->GetFontSize(); - p.y = text_height - p.y; - - for (int i = 0; i < line_count_; i++) { - auto line = lines_[i]; - auto line_origin = line_origins_[i]; - - auto range = CTLineGetStringRange(line); - - CGRect bounds{line_origin.x, line_origin.y - line_descents_[i], - CTLineGetOffsetForStringIndex( - line, range.location + range.length, nullptr), - line_heights_[i]}; - - bool force_inside = false; - if (i == 0 && p.y >= bounds.origin.y + bounds.size.height) { - force_inside = true; - } - - if (i == line_count_ - 1 && p.y < bounds.origin.y) { - force_inside = true; - } - - if (p.y >= bounds.origin.y || force_inside) { - auto pp = p; - pp.y = bounds.origin.y; - Index po; - bool inside_text; - - if (pp.x < bounds.origin.x) { - po = actual_text_.IndexFromCodePointToCodeUnit(range.location); - inside_text = false; - } else if (pp.x > bounds.origin.x + bounds.size.width) { - po = actual_text_.IndexFromCodePointToCodeUnit(range.location + - range.length); - inside_text = false; - } else { - int position = CTLineGetStringIndexForPosition( - line, - CGPointMake(pp.x - line_origins_[i].x, pp.y - line_origins_[i].y)); - - po = actual_text_.IndexFromCodePointToCodeUnit(position); - inside_text = true; - } - - if (po != 0 && - po == actual_text_.IndexFromCodePointToCodeUnit(range.location + - range.length) && - actual_text_[po - 1] == u'\n') { - --po; - } - - return {po + head_empty_line_count_, false, inside_text}; - } - } - - return TextHitTestResult{0, false, false}; -} - -void OsxCTTextLayout::ReleaseResource() { - line_count_ = 0; - line_origins_.clear(); - lines_.clear(); - line_ascents_.clear(); - line_descents_.clear(); - line_heights_.clear(); - if (ct_framesetter_) CFRelease(ct_framesetter_); - if (ct_frame_) CFRelease(ct_frame_); -} - -void OsxCTTextLayout::RecreateFrame() { - ReleaseResource(); - - ct_framesetter_ = - CTFramesetterCreateWithAttributedString(cf_attributed_text_); - Ensures(ct_framesetter_); - - CFRange fit_range; - - suggest_height_ = - CTFramesetterSuggestFrameSizeWithConstraints( - ct_framesetter_, - CFRangeMake(0, CFAttributedStringGetLength(cf_attributed_text_)), - nullptr, CGSizeMake(max_width_, max_height_), &fit_range) - .height; - - auto path = CGPathCreateMutable(); - Ensures(path); - CGPathAddRect(path, nullptr, CGRectMake(0, 0, max_width_, suggest_height_)); - - ct_frame_ = CTFramesetterCreateFrame( - ct_framesetter_, - CFRangeMake(0, CFAttributedStringGetLength(cf_attributed_text_)), path, - nullptr); - Ensures(ct_frame_); - - CGPathRelease(path); - - const auto lines = CTFrameGetLines(ct_frame_); - line_count_ = CFArrayGetCount(lines); - lines_.resize(line_count_); - line_origins_.resize(line_count_); - line_ascents_.resize(line_count_); - line_descents_.resize(line_count_); - line_heights_.resize(line_count_); - CTFrameGetLineOrigins(ct_frame_, CFRangeMake(0, 0), line_origins_.data()); - for (int i = 0; i < line_count_; i++) { - lines_[i] = static_cast<CTLineRef>(CFArrayGetValueAtIndex(lines, i)); - double ascent, descent; - CTLineGetTypographicBounds(lines_[i], &ascent, &descent, nullptr); - line_ascents_[i] = static_cast<float>(ascent); - line_descents_[i] = static_cast<float>(descent); - line_heights_[i] = line_ascents_[i] + line_descents_[i]; - } - - auto bounds = DoGetTextBounds(false); - text_bounds_without_trailing_space_ = bounds; - text_bounds_with_trailing_space_ = DoGetTextBounds(true); - - auto right = bounds.origin.x + bounds.size.width; - auto bottom = bounds.origin.y + bounds.size.height; - - transform_ = - Matrix::Translation(-right / 2, -bottom / 2) * Matrix::Scale(1, -1) * - Matrix::Translation(right / 2, bottom / 2) * - Matrix::Translation(0, head_empty_line_count_ * font_->GetFontSize()); -} - -CTFrameRef OsxCTTextLayout::CreateFrameWithColor(const Color& color) { - auto path = CGPathCreateMutable(); - CGPathAddRect(path, nullptr, CGRectMake(0, 0, max_width_, suggest_height_)); - - CGColorRef cg_color = - CGColorCreateGenericRGB(color.GetFloatRed(), color.GetFloatGreen(), - color.GetFloatBlue(), color.GetFloatAlpha()); - CFAttributedStringSetAttribute( - cf_attributed_text_, - CFRangeMake(0, CFAttributedStringGetLength(cf_attributed_text_)), - kCTForegroundColorAttributeName, cg_color); - - auto frame = CTFramesetterCreateFrame( - ct_framesetter_, - CFRangeMake(0, CFAttributedStringGetLength(cf_attributed_text_)), path, - nullptr); - Ensures(frame); - - CGPathRelease(path); - - return frame; -} - -String OsxCTTextLayout::GetDebugString() { - return Format(u"OsxCTTextLayout(text: {}, size: ({}, {}))", text_, max_width_, - max_height_); -} - -CGRect OsxCTTextLayout::DoGetTextBounds(bool includingTrailingSpace) { - if (actual_text_.empty()) return CGRect{}; - - auto rects = DoTextRangeRect(TextRange{0, actual_text_.size()}); - - float left = std::numeric_limits<float>::max(); - float bottom = std::numeric_limits<float>::max(); - float right = 0; - float top = 0; - - for (auto& rect : rects) { - if (rect.origin.x < left) left = rect.origin.x; - if (rect.origin.y < bottom) bottom = rect.origin.y; - if (rect.origin.x + rect.size.width > right) - right = rect.origin.x + rect.size.width; - if (rect.origin.y + rect.size.height > top) - top = rect.origin.y + rect.size.height; - } - - return CGRectMake(left, bottom, right - left, top - bottom); -} - -CGRect OsxCTTextLayout::DoGetTextBoundsIncludingEmptyLines( - bool includingTrailingSpace) { - auto result = includingTrailingSpace ? text_bounds_with_trailing_space_ - : text_bounds_without_trailing_space_; - - result.size.height += head_empty_line_count_ * font_->GetFontSize(); - result.size.height += tail_empty_line_count_ * font_->GetFontSize(); - - return result; -} - -std::vector<CGRect> OsxCTTextLayout::DoTextRangeRect( - const TextRange& text_range) { - const auto r = - actual_text_.RangeFromCodeUnitToCodePoint(text_range).Normalize(); - - std::vector<CGRect> results; - - for (int i = 0; i < line_count_; i++) { - auto line = lines_[i]; - auto line_origin = line_origins_[i]; - - Range range = Convert(CTLineGetStringRange(line)); - range = range.CoerceInto(r.GetStart(), r.GetEnd()); - - if (range.count) { - CGRect line_rect{line_origin.x, line_origin.y - line_descents_[i], 0, - line_heights_[i]}; - float start_offset = - CTLineGetOffsetForStringIndex(line, range.GetStart(), nullptr); - float end_offset = - CTLineGetOffsetForStringIndex(line, range.GetEnd(), nullptr); - line_rect.origin.x += start_offset; - line_rect.size.width = end_offset - start_offset; - results.push_back(line_rect); - } - } - - return results; -} - -CGRect OsxCTTextLayout::DoTextSinglePoint(Index position, bool trailing) { - Expects(position >= 0 && position <= actual_text_.size()); - - if (actual_text_.empty()) return CGRectMake(0, 0, 0, font_->GetFontSize()); - - position = actual_text_.IndexFromCodeUnitToCodePoint(position); - - for (int i = 0; i < line_count_; i++) { - auto line = lines_[i]; - auto line_origin = line_origins_[i]; - - CFRange range = CTLineGetStringRange(line); - if (range.location <= position && - position < range.location + range.length || - i == line_count_ - 1 && position == range.location + range.length) { - auto offset = CTLineGetOffsetForStringIndex(line, position, nullptr); - return CGRectMake(offset + line_origin.x, - line_origin.y - line_descents_[i], 0, line_heights_[i]); - } - } - - UnreachableCode(); -} -} // namespace cru::platform::graphics::osx::quartz diff --git a/src/osx/gui/CMakeLists.txt b/src/osx/gui/CMakeLists.txt deleted file mode 100644 index 5442ad15..00000000 --- a/src/osx/gui/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -add_library(CruPlatformGuiOsx SHARED - Clipboard.mm - Cursor.mm - InputMethod.mm - Keyboard.mm - Menu.mm - Resource.cpp - UiApplication.mm - Window.mm -) - -find_library(APPKIT AppKit REQUIRED) -find_library(UNIFORMTYPEIDENTIFIERS UniformTypeIdentifiers REQUIRED) - -target_link_libraries(CruPlatformGuiOsx PUBLIC CruPlatformGui CruPlatformGraphicsQuartz ${APPKIT} ${UNIFORMTYPEIDENTIFIERS}) diff --git a/src/osx/gui/Clipboard.mm b/src/osx/gui/Clipboard.mm deleted file mode 100644 index 6e3fb076..00000000 --- a/src/osx/gui/Clipboard.mm +++ /dev/null @@ -1,46 +0,0 @@ -#include "cru/osx/gui/Clipboard.h" -#include "ClipboardPrivate.h" - -#include "cru/common/log/Logger.h" -#include "cru/osx/Convert.h" - -#include <memory> - -namespace cru::platform::gui::osx { -using cru::platform::osx::Convert; - -OsxClipboard::OsxClipboard(cru::platform::gui::IUiApplication* ui_application, - std::unique_ptr<details::OsxClipboardPrivate> p) - : OsxGuiResource(ui_application), p_(std::move(p)) {} - -OsxClipboard::~OsxClipboard() {} - -String OsxClipboard::GetText() { return p_->GetText(); } - -void OsxClipboard::SetText(String text) { p_->SetText(text); } - -namespace details { -OsxClipboardPrivate::OsxClipboardPrivate(NSPasteboard* pasteboard) : pasteboard_(pasteboard) {} - -OsxClipboardPrivate::~OsxClipboardPrivate() {} - -String OsxClipboardPrivate::GetText() { - auto result = [pasteboard_ readObjectsForClasses:@[ NSString.class ] options:nil]; - if (result == nil) { - CRU_LOG_WARN(u"Failed to get text from clipboard"); - return u""; - } else { - if (result.count == 0) { - return u""; - } else { - return Convert((CFStringRef)result[0]); - } - } -} - -void OsxClipboardPrivate::SetText(String text) { - [pasteboard_ clearContents]; - [pasteboard_ writeObjects:@[ (NSString*)Convert(text) ]]; -} -} -} // namespace cru::platform::gui::osx diff --git a/src/osx/gui/ClipboardPrivate.h b/src/osx/gui/ClipboardPrivate.h deleted file mode 100644 index 63145a64..00000000 --- a/src/osx/gui/ClipboardPrivate.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include "cru/common/Base.h" -#include "cru/osx/gui/Clipboard.h" - -#include <AppKit/AppKit.h> - -namespace cru::platform::gui::osx { -namespace details { -class OsxClipboardPrivate : public Object { - CRU_DEFINE_CLASS_LOG_TAG(u"OsxClipboardPrivate") - public: - explicit OsxClipboardPrivate(NSPasteboard* pasteboard); - - CRU_DELETE_COPY(OsxClipboardPrivate) - CRU_DELETE_MOVE(OsxClipboardPrivate) - - ~OsxClipboardPrivate(); - - public: - String GetText(); - void SetText(String text); - - private: - NSPasteboard* pasteboard_; -}; -} // namespace details -} // namespace cru::platform::gui::osx diff --git a/src/osx/gui/Cursor.mm b/src/osx/gui/Cursor.mm deleted file mode 100644 index 13bdc858..00000000 --- a/src/osx/gui/Cursor.mm +++ /dev/null @@ -1,93 +0,0 @@ -#include "cru/osx/gui/Cursor.h" -#include "CursorPrivate.h" - -#include "cru/osx/Exception.h" -#include "cru/osx/gui/Resource.h" -#include "cru/platform/gui/Cursor.h" -#include "cru/platform/gui/UiApplication.h" - -#include <memory> - -namespace cru::platform::gui::osx { -namespace details { -OsxCursorPrivate::OsxCursorPrivate(OsxCursor* cursor, SystemCursorType cursor_type) { - cursor_ = cursor; - - switch (cursor_type) { - case SystemCursorType::Arrow: - ns_cursor_ = [NSCursor arrowCursor]; - break; - case SystemCursorType::Hand: - ns_cursor_ = [NSCursor pointingHandCursor]; - break; - case SystemCursorType::IBeam: - ns_cursor_ = [NSCursor IBeamCursor]; - break; - default: - throw Exception(u"Unknown system cursor type."); - } -} - -OsxCursorPrivate::~OsxCursorPrivate() {} -} - -OsxCursor::OsxCursor(IUiApplication* ui_application, SystemCursorType cursor_type) - : OsxGuiResource(ui_application) { - p_ = std::make_unique<details::OsxCursorPrivate>(this, cursor_type); -} - -OsxCursor::~OsxCursor() {} - -namespace details { -class OsxCursorManagerPrivate { - friend OsxCursorManager; - - public: - explicit OsxCursorManagerPrivate(OsxCursorManager* cursor_manager); - - CRU_DELETE_COPY(OsxCursorManagerPrivate) - CRU_DELETE_MOVE(OsxCursorManagerPrivate) - - ~OsxCursorManagerPrivate(); - - private: - OsxCursorManager* cursor_manager_; - - std::shared_ptr<OsxCursor> arrow_cursor_; - std::shared_ptr<OsxCursor> hand_cursor_; - std::shared_ptr<OsxCursor> ibeam_cursor_; -}; - -OsxCursorManagerPrivate::OsxCursorManagerPrivate(OsxCursorManager* cursor_manager) { - cursor_manager_ = cursor_manager; - arrow_cursor_ = - std::make_shared<OsxCursor>(cursor_manager->GetUiApplication(), SystemCursorType::Arrow); - hand_cursor_ = - std::make_shared<OsxCursor>(cursor_manager->GetUiApplication(), SystemCursorType::Hand); - ibeam_cursor_ = - std::make_shared<OsxCursor>(cursor_manager->GetUiApplication(), SystemCursorType::IBeam); -} - -OsxCursorManagerPrivate::~OsxCursorManagerPrivate() {} -} - -OsxCursorManager::OsxCursorManager(IUiApplication* ui_application) - : OsxGuiResource(ui_application) { - p_ = std::make_unique<details::OsxCursorManagerPrivate>(this); -} - -OsxCursorManager::~OsxCursorManager() {} - -std::shared_ptr<ICursor> OsxCursorManager::GetSystemCursor(SystemCursorType type) { - switch (type) { - case SystemCursorType::Arrow: - return p_->arrow_cursor_; - case SystemCursorType::Hand: - return p_->hand_cursor_; - case SystemCursorType::IBeam: - return p_->ibeam_cursor_; - default: - throw Exception(u"Unknown system cursor type."); - } -} -} diff --git a/src/osx/gui/CursorPrivate.h b/src/osx/gui/CursorPrivate.h deleted file mode 100644 index c840e286..00000000 --- a/src/osx/gui/CursorPrivate.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#include "cru/osx/gui/Cursor.h" - -#import <AppKit/NSCursor.h> - -namespace cru::platform::gui::osx { -class OsxWindow; - -namespace details { -class OsxWindowPrivate; - -class OsxCursorPrivate { - friend OsxWindow; - friend OsxWindowPrivate; - - public: - OsxCursorPrivate(OsxCursor* cursor, SystemCursorType cursor_type); - - CRU_DELETE_COPY(OsxCursorPrivate) - CRU_DELETE_MOVE(OsxCursorPrivate) - - ~OsxCursorPrivate(); - - private: - OsxCursor* cursor_; - NSCursor* ns_cursor_; -}; -} // namespace details -} // namespace cru::platform::gui::osx diff --git a/src/osx/gui/InputMethod.mm b/src/osx/gui/InputMethod.mm deleted file mode 100644 index 2c19c358..00000000 --- a/src/osx/gui/InputMethod.mm +++ /dev/null @@ -1,84 +0,0 @@ -#include "cru/osx/gui/InputMethod.h" - -#import <AppKit/AppKit.h> -#include "InputMethodPrivate.h" -#include "WindowPrivate.h" -#include "cru/common/log/Logger.h" -#include "cru/osx/Convert.h" -#include "cru/osx/gui/Window.h" - -namespace cru::platform::gui::osx { -namespace details { -OsxInputMethodContextPrivate::OsxInputMethodContextPrivate( - OsxInputMethodContext* input_method_context, OsxWindow* window) { - input_method_context_ = input_method_context; - window_ = window; -} - -OsxInputMethodContextPrivate::~OsxInputMethodContextPrivate() {} - -void OsxInputMethodContextPrivate::RaiseCompositionStartEvent() { - composition_start_event_.Raise(nullptr); -} -void OsxInputMethodContextPrivate::RaiseCompositionEndEvent() { - composition_end_event_.Raise(nullptr); -} -void OsxInputMethodContextPrivate::RaiseCompositionEvent() { composition_event_.Raise(nullptr); } - -void OsxInputMethodContextPrivate::RaiseTextEvent(StringView text) { text_event_.Raise(text); } - -void OsxInputMethodContextPrivate::PerformSel(SEL sel) { - // [window_->p_->GetNSWindow() performSelector:sel]; -} - -void OsxInputMethodContextPrivate::Activate() { is_enabled_ = true; } - -void OsxInputMethodContextPrivate::Deactivate() { - input_method_context_->CompleteComposition(); - is_enabled_ = false; -} -} - -OsxInputMethodContext::OsxInputMethodContext(OsxWindow* window) - : OsxGuiResource(window->GetUiApplication()) { - p_ = std::make_unique<details::OsxInputMethodContextPrivate>(this, window); -} - -OsxInputMethodContext::~OsxInputMethodContext() {} - -void OsxInputMethodContext::EnableIME() { p_->Activate(); } - -void OsxInputMethodContext::DisableIME() { p_->Deactivate(); } - -bool OsxInputMethodContext::ShouldManuallyDrawCompositionText() { return true; } - -void OsxInputMethodContext::CompleteComposition() { - // TODO: Implement this. -} - -void OsxInputMethodContext::CancelComposition() { - [[NSTextInputContext currentInputContext] discardMarkedText]; -} - -CompositionText OsxInputMethodContext::GetCompositionText() { return p_->composition_text_; } - -void OsxInputMethodContext::SetCandidateWindowPosition(const Point& point) { - p_->SetCandidateWindowPosition(point); -} - -IEvent<std::nullptr_t>* OsxInputMethodContext::CompositionStartEvent() { - return &p_->composition_start_event_; -} - -IEvent<std::nullptr_t>* OsxInputMethodContext::CompositionEndEvent() { - return &p_->composition_end_event_; -} - -IEvent<std::nullptr_t>* OsxInputMethodContext::CompositionEvent() { - return &p_->composition_event_; -} - -IEvent<StringView>* OsxInputMethodContext::TextEvent() { return &p_->text_event_; } - -bool OsxInputMethodContext::IsEnabled() { return p_->is_enabled_; } -} diff --git a/src/osx/gui/InputMethodPrivate.h b/src/osx/gui/InputMethodPrivate.h deleted file mode 100644 index 1df21b37..00000000 --- a/src/osx/gui/InputMethodPrivate.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include "cru/osx/gui/InputMethod.h" - -#include <AppKit/AppKit.h> - -namespace cru::platform::gui::osx { -namespace details { -class OsxInputMethodContextPrivate { - friend OsxInputMethodContext; - - public: - OsxInputMethodContextPrivate(OsxInputMethodContext* input_method_context, - OsxWindow* window); - - CRU_DELETE_COPY(OsxInputMethodContextPrivate) - CRU_DELETE_MOVE(OsxInputMethodContextPrivate) - - ~OsxInputMethodContextPrivate(); - - void SetCompositionText(CompositionText composition_text) { - composition_text_ = std::move(composition_text); - } - - void RaiseCompositionStartEvent(); - void RaiseCompositionEndEvent(); - void RaiseCompositionEvent(); - void RaiseTextEvent(StringView text); - - Point GetCandidateWindowPosition() const { return candidate_window_point_; } - void SetCandidateWindowPosition(const Point& p) { - candidate_window_point_ = p; - } - - Range GetSelectionRange() const { return selection_range_; } - void SetSelectionRange(Range selection_range) { - selection_range_ = selection_range; - } - - void PerformSel(SEL sel); - - void Activate(); - void Deactivate(); - - private: - OsxWindow* window_; - - CompositionText composition_text_; - - Range selection_range_; - - OsxInputMethodContext* input_method_context_; - - // On Osx, this is the text lefttop point on screen. - Point candidate_window_point_; - - Event<std::nullptr_t> composition_start_event_; - Event<std::nullptr_t> composition_event_; - Event<std::nullptr_t> composition_end_event_; - Event<StringView> text_event_; - - bool is_enabled_ = false; -}; -} // namespace details -} // namespace cru::platform::gui::osx diff --git a/src/osx/gui/Keyboard.mm b/src/osx/gui/Keyboard.mm deleted file mode 100644 index 3e78eecb..00000000 --- a/src/osx/gui/Keyboard.mm +++ /dev/null @@ -1,283 +0,0 @@ -#include "cru/osx/gui/Keyboard.h" - -#import <AppKit/NSText.h> -#import <Carbon/Carbon.h> -#import "KeyboardPrivate.h" - -namespace cru::platform::gui::osx { -KeyCode KeyCodeFromOsxToCru(unsigned short n) { - switch (n) { -#define CRU_DEFINE_KEYCODE_MAP(osx, cru) \ - case osx: \ - return cru; - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_0, KeyCode::N0) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_1, KeyCode::N1) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_2, KeyCode::N2) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_3, KeyCode::N3) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_4, KeyCode::N4) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_5, KeyCode::N5) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_6, KeyCode::N6) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_7, KeyCode::N7) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_8, KeyCode::N8) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_9, KeyCode::N9) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_A, KeyCode::A) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_B, KeyCode::B) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_C, KeyCode::C) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_D, KeyCode::D) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_E, KeyCode::E) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_F, KeyCode::F) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_G, KeyCode::G) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_H, KeyCode::H) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_I, KeyCode::I) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_J, KeyCode::J) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_K, KeyCode::K) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_L, KeyCode::L) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_M, KeyCode::M) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_N, KeyCode::N) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_O, KeyCode::O) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_P, KeyCode::P) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Q, KeyCode::Q) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_R, KeyCode::R) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_S, KeyCode::S) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_T, KeyCode::T) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_U, KeyCode::U) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_V, KeyCode::V) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_W, KeyCode::W) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_X, KeyCode::X) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Y, KeyCode::Y) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Z, KeyCode::Z) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Comma, KeyCode::Comma) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Period, KeyCode::Period) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Slash, KeyCode::Slash) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Semicolon, KeyCode::Semicolon) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Quote, KeyCode::Quote) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_LeftBracket, KeyCode::LeftSquareBracket) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_RightBracket, KeyCode::RightSquareBracket) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Minus, KeyCode::Minus) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Equal, KeyCode::Equal) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Backslash, KeyCode::BackSlash) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Grave, KeyCode::GraveAccent) - CRU_DEFINE_KEYCODE_MAP(kVK_Escape, KeyCode::Escape) - CRU_DEFINE_KEYCODE_MAP(kVK_Tab, KeyCode::Tab) - CRU_DEFINE_KEYCODE_MAP(kVK_CapsLock, KeyCode::CapsLock) - CRU_DEFINE_KEYCODE_MAP(kVK_Shift, KeyCode::LeftShift) - CRU_DEFINE_KEYCODE_MAP(kVK_RightShift, KeyCode::RightShift) - CRU_DEFINE_KEYCODE_MAP(kVK_Control, KeyCode::LeftCtrl) - CRU_DEFINE_KEYCODE_MAP(kVK_RightControl, KeyCode::RightCtrl) - CRU_DEFINE_KEYCODE_MAP(kVK_Option, KeyCode::LeftAlt) - CRU_DEFINE_KEYCODE_MAP(kVK_RightOption, KeyCode::RightAlt) - CRU_DEFINE_KEYCODE_MAP(kVK_Command, KeyCode::LeftCommand) - CRU_DEFINE_KEYCODE_MAP(kVK_RightCommand, KeyCode::RightCommand) - CRU_DEFINE_KEYCODE_MAP(kVK_Delete, KeyCode::Backspace) - CRU_DEFINE_KEYCODE_MAP(kVK_Return, KeyCode::Return) - CRU_DEFINE_KEYCODE_MAP(kVK_ForwardDelete, KeyCode::Delete) - CRU_DEFINE_KEYCODE_MAP(kVK_Home, KeyCode::Home) - CRU_DEFINE_KEYCODE_MAP(kVK_End, KeyCode::End) - CRU_DEFINE_KEYCODE_MAP(kVK_PageUp, KeyCode::PageUp) - CRU_DEFINE_KEYCODE_MAP(kVK_PageDown, KeyCode::PageDown) - CRU_DEFINE_KEYCODE_MAP(kVK_LeftArrow, KeyCode::Left) - CRU_DEFINE_KEYCODE_MAP(kVK_RightArrow, KeyCode::Right) - CRU_DEFINE_KEYCODE_MAP(kVK_UpArrow, KeyCode::Up) - CRU_DEFINE_KEYCODE_MAP(kVK_DownArrow, KeyCode::Down) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Keypad0, KeyCode::NumPad0) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Keypad1, KeyCode::NumPad1) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Keypad2, KeyCode::NumPad2) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Keypad3, KeyCode::NumPad3) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Keypad4, KeyCode::NumPad4) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Keypad5, KeyCode::NumPad5) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Keypad6, KeyCode::NumPad6) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Keypad7, KeyCode::NumPad7) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Keypad8, KeyCode::NumPad8) - CRU_DEFINE_KEYCODE_MAP(kVK_ANSI_Keypad9, KeyCode::NumPad9) - CRU_DEFINE_KEYCODE_MAP(kVK_Space, KeyCode::Space) - default: - return KeyCode::Unknown; - } - -#undef CRU_DEFINE_KEYCODE_MAP -} - -unsigned short KeyCodeFromCruToOsx(KeyCode k) { - switch (k) { -#define CRU_DEFINE_KEYCODE_MAP(cru, osx) \ - case cru: \ - return osx; - CRU_DEFINE_KEYCODE_MAP(KeyCode::N0, kVK_ANSI_0) - CRU_DEFINE_KEYCODE_MAP(KeyCode::N1, kVK_ANSI_1) - CRU_DEFINE_KEYCODE_MAP(KeyCode::N2, kVK_ANSI_2) - CRU_DEFINE_KEYCODE_MAP(KeyCode::N3, kVK_ANSI_3) - CRU_DEFINE_KEYCODE_MAP(KeyCode::N4, kVK_ANSI_4) - CRU_DEFINE_KEYCODE_MAP(KeyCode::N5, kVK_ANSI_5) - CRU_DEFINE_KEYCODE_MAP(KeyCode::N6, kVK_ANSI_6) - CRU_DEFINE_KEYCODE_MAP(KeyCode::N7, kVK_ANSI_7) - CRU_DEFINE_KEYCODE_MAP(KeyCode::N8, kVK_ANSI_8) - CRU_DEFINE_KEYCODE_MAP(KeyCode::N9, kVK_ANSI_9) - CRU_DEFINE_KEYCODE_MAP(KeyCode::A, kVK_ANSI_A) - CRU_DEFINE_KEYCODE_MAP(KeyCode::B, kVK_ANSI_B) - CRU_DEFINE_KEYCODE_MAP(KeyCode::C, kVK_ANSI_C) - CRU_DEFINE_KEYCODE_MAP(KeyCode::D, kVK_ANSI_D) - CRU_DEFINE_KEYCODE_MAP(KeyCode::E, kVK_ANSI_E) - CRU_DEFINE_KEYCODE_MAP(KeyCode::F, kVK_ANSI_F) - CRU_DEFINE_KEYCODE_MAP(KeyCode::G, kVK_ANSI_G) - CRU_DEFINE_KEYCODE_MAP(KeyCode::H, kVK_ANSI_H) - CRU_DEFINE_KEYCODE_MAP(KeyCode::I, kVK_ANSI_I) - CRU_DEFINE_KEYCODE_MAP(KeyCode::J, kVK_ANSI_J) - CRU_DEFINE_KEYCODE_MAP(KeyCode::K, kVK_ANSI_K) - CRU_DEFINE_KEYCODE_MAP(KeyCode::L, kVK_ANSI_L) - CRU_DEFINE_KEYCODE_MAP(KeyCode::M, kVK_ANSI_M) - CRU_DEFINE_KEYCODE_MAP(KeyCode::N, kVK_ANSI_N) - CRU_DEFINE_KEYCODE_MAP(KeyCode::O, kVK_ANSI_O) - CRU_DEFINE_KEYCODE_MAP(KeyCode::P, kVK_ANSI_P) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Q, kVK_ANSI_Q) - CRU_DEFINE_KEYCODE_MAP(KeyCode::R, kVK_ANSI_R) - CRU_DEFINE_KEYCODE_MAP(KeyCode::S, kVK_ANSI_S) - CRU_DEFINE_KEYCODE_MAP(KeyCode::T, kVK_ANSI_T) - CRU_DEFINE_KEYCODE_MAP(KeyCode::U, kVK_ANSI_U) - CRU_DEFINE_KEYCODE_MAP(KeyCode::V, kVK_ANSI_V) - CRU_DEFINE_KEYCODE_MAP(KeyCode::W, kVK_ANSI_W) - CRU_DEFINE_KEYCODE_MAP(KeyCode::X, kVK_ANSI_X) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Y, kVK_ANSI_Y) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Z, kVK_ANSI_Z) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Comma, kVK_ANSI_Comma) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Period, kVK_ANSI_Period) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Slash, kVK_ANSI_Slash) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Semicolon, kVK_ANSI_Semicolon) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Quote, kVK_ANSI_Quote) - CRU_DEFINE_KEYCODE_MAP(KeyCode::LeftSquareBracket, kVK_ANSI_LeftBracket) - CRU_DEFINE_KEYCODE_MAP(KeyCode::RightSquareBracket, kVK_ANSI_RightBracket) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Minus, kVK_ANSI_Minus) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Equal, kVK_ANSI_Equal) - CRU_DEFINE_KEYCODE_MAP(KeyCode::BackSlash, kVK_ANSI_Backslash) - CRU_DEFINE_KEYCODE_MAP(KeyCode::GraveAccent, kVK_ANSI_Grave) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Escape, kVK_Escape) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Tab, kVK_Tab) - CRU_DEFINE_KEYCODE_MAP(KeyCode::CapsLock, kVK_CapsLock) - CRU_DEFINE_KEYCODE_MAP(KeyCode::LeftShift, kVK_Shift) - CRU_DEFINE_KEYCODE_MAP(KeyCode::RightShift, kVK_RightShift) - CRU_DEFINE_KEYCODE_MAP(KeyCode::LeftCtrl, kVK_Control) - CRU_DEFINE_KEYCODE_MAP(KeyCode::RightCtrl, kVK_RightControl) - CRU_DEFINE_KEYCODE_MAP(KeyCode::LeftAlt, kVK_Option) - CRU_DEFINE_KEYCODE_MAP(KeyCode::RightAlt, kVK_RightOption) - CRU_DEFINE_KEYCODE_MAP(KeyCode::LeftCommand, kVK_Command) - CRU_DEFINE_KEYCODE_MAP(KeyCode::RightCommand, kVK_RightCommand) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Backspace, kVK_Delete) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Return, kVK_Return) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Delete, kVK_ForwardDelete) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Home, kVK_Home) - CRU_DEFINE_KEYCODE_MAP(KeyCode::End, kVK_End) - CRU_DEFINE_KEYCODE_MAP(KeyCode::PageUp, kVK_PageUp) - CRU_DEFINE_KEYCODE_MAP(KeyCode::PageDown, kVK_PageDown) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Left, kVK_LeftArrow) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Right, kVK_RightArrow) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Up, kVK_UpArrow) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Down, kVK_DownArrow) - CRU_DEFINE_KEYCODE_MAP(KeyCode::NumPad0, kVK_ANSI_Keypad0) - CRU_DEFINE_KEYCODE_MAP(KeyCode::NumPad1, kVK_ANSI_Keypad1) - CRU_DEFINE_KEYCODE_MAP(KeyCode::NumPad2, kVK_ANSI_Keypad2) - CRU_DEFINE_KEYCODE_MAP(KeyCode::NumPad3, kVK_ANSI_Keypad3) - CRU_DEFINE_KEYCODE_MAP(KeyCode::NumPad4, kVK_ANSI_Keypad4) - CRU_DEFINE_KEYCODE_MAP(KeyCode::NumPad5, kVK_ANSI_Keypad5) - CRU_DEFINE_KEYCODE_MAP(KeyCode::NumPad6, kVK_ANSI_Keypad6) - CRU_DEFINE_KEYCODE_MAP(KeyCode::NumPad7, kVK_ANSI_Keypad7) - CRU_DEFINE_KEYCODE_MAP(KeyCode::NumPad8, kVK_ANSI_Keypad8) - CRU_DEFINE_KEYCODE_MAP(KeyCode::NumPad9, kVK_ANSI_Keypad9) - CRU_DEFINE_KEYCODE_MAP(KeyCode::Space, kVK_Space) - default: - return 0; - } -#undef CRU_DEFINE_KEYCODE_MAP -} - -NSString* ConvertKeyCodeToKeyEquivalent(KeyCode key_code) { -#define CRU_DEFINE_KEYCODE_MAP(key_code, str) \ - case key_code: \ - return str; - - switch (key_code) { - CRU_DEFINE_KEYCODE_MAP(KeyCode::A, @"a") - CRU_DEFINE_KEYCODE_MAP(KeyCode::B, @"b") - CRU_DEFINE_KEYCODE_MAP(KeyCode::C, @"c") - CRU_DEFINE_KEYCODE_MAP(KeyCode::D, @"d") - CRU_DEFINE_KEYCODE_MAP(KeyCode::E, @"e") - CRU_DEFINE_KEYCODE_MAP(KeyCode::F, @"f") - CRU_DEFINE_KEYCODE_MAP(KeyCode::G, @"g") - CRU_DEFINE_KEYCODE_MAP(KeyCode::H, @"h") - CRU_DEFINE_KEYCODE_MAP(KeyCode::I, @"i") - CRU_DEFINE_KEYCODE_MAP(KeyCode::J, @"j") - CRU_DEFINE_KEYCODE_MAP(KeyCode::K, @"k") - CRU_DEFINE_KEYCODE_MAP(KeyCode::L, @"l") - CRU_DEFINE_KEYCODE_MAP(KeyCode::M, @"m") - CRU_DEFINE_KEYCODE_MAP(KeyCode::N, @"n") - CRU_DEFINE_KEYCODE_MAP(KeyCode::O, @"o") - CRU_DEFINE_KEYCODE_MAP(KeyCode::P, @"p") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Q, @"q") - CRU_DEFINE_KEYCODE_MAP(KeyCode::R, @"r") - CRU_DEFINE_KEYCODE_MAP(KeyCode::S, @"s") - CRU_DEFINE_KEYCODE_MAP(KeyCode::T, @"t") - CRU_DEFINE_KEYCODE_MAP(KeyCode::U, @"u") - CRU_DEFINE_KEYCODE_MAP(KeyCode::V, @"v") - CRU_DEFINE_KEYCODE_MAP(KeyCode::W, @"w") - CRU_DEFINE_KEYCODE_MAP(KeyCode::X, @"x") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Y, @"y") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Z, @"z") - CRU_DEFINE_KEYCODE_MAP(KeyCode::N0, @"0") - CRU_DEFINE_KEYCODE_MAP(KeyCode::N1, @"1") - CRU_DEFINE_KEYCODE_MAP(KeyCode::N2, @"2") - CRU_DEFINE_KEYCODE_MAP(KeyCode::N3, @"3") - CRU_DEFINE_KEYCODE_MAP(KeyCode::N4, @"4") - CRU_DEFINE_KEYCODE_MAP(KeyCode::N5, @"5") - CRU_DEFINE_KEYCODE_MAP(KeyCode::N6, @"6") - CRU_DEFINE_KEYCODE_MAP(KeyCode::N7, @"7") - CRU_DEFINE_KEYCODE_MAP(KeyCode::N8, @"8") - CRU_DEFINE_KEYCODE_MAP(KeyCode::N9, @"9") - CRU_DEFINE_KEYCODE_MAP(KeyCode::F1, @"F1") - CRU_DEFINE_KEYCODE_MAP(KeyCode::F2, @"F2") - CRU_DEFINE_KEYCODE_MAP(KeyCode::F3, @"F3") - CRU_DEFINE_KEYCODE_MAP(KeyCode::F4, @"F4") - CRU_DEFINE_KEYCODE_MAP(KeyCode::F5, @"F5") - CRU_DEFINE_KEYCODE_MAP(KeyCode::F6, @"F6") - CRU_DEFINE_KEYCODE_MAP(KeyCode::F7, @"F7") - CRU_DEFINE_KEYCODE_MAP(KeyCode::F8, @"F8") - CRU_DEFINE_KEYCODE_MAP(KeyCode::F9, @"F9") - CRU_DEFINE_KEYCODE_MAP(KeyCode::F10, @"F10") - CRU_DEFINE_KEYCODE_MAP(KeyCode::F11, @"F11") - CRU_DEFINE_KEYCODE_MAP(KeyCode::F12, @"F12") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Minus, @"-") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Equal, @"=") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Comma, @",") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Period, @".") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Slash, @"/") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Semicolon, @";") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Quote, @"'") - CRU_DEFINE_KEYCODE_MAP(KeyCode::LeftSquareBracket, @"[") - CRU_DEFINE_KEYCODE_MAP(KeyCode::RightSquareBracket, @"]") - CRU_DEFINE_KEYCODE_MAP(KeyCode::BackSlash, @"\\") - CRU_DEFINE_KEYCODE_MAP(KeyCode::GraveAccent, @"`") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Return, @"\n") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Escape, @"\e") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Tab, @"\t") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Backspace, @"\x08") - CRU_DEFINE_KEYCODE_MAP(KeyCode::Delete, @"\x7F") - default: - throw Exception(u"Failed to convert key code to key equivalent string."); - } -#undef CRU_DEFINE_KEYCODE_MAP -} - -NSEventModifierFlags ConvertKeyModifier(KeyModifier k) { - NSEventModifierFlags flags = 0; - if (k & KeyModifiers::shift) { - flags |= NSEventModifierFlagShift; - } - if (k & KeyModifiers::ctrl) { - flags |= NSEventModifierFlagControl; - } - if (k & KeyModifiers::alt) { - flags |= NSEventModifierFlagOption; - } - if (k & KeyModifiers::command) { - flags |= NSEventModifierFlagCommand; - } - return flags; -} -} diff --git a/src/osx/gui/KeyboardPrivate.h b/src/osx/gui/KeyboardPrivate.h deleted file mode 100644 index b98ea5d4..00000000 --- a/src/osx/gui/KeyboardPrivate.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "cru/osx/gui/Keyboard.h" - -#import <AppKit/NSEvent.h> - -namespace cru::platform::gui::osx { -NSString* ConvertKeyCodeToKeyEquivalent(KeyCode key_code); -NSEventModifierFlags ConvertKeyModifier(KeyModifier k); -} diff --git a/src/osx/gui/Menu.mm b/src/osx/gui/Menu.mm deleted file mode 100644 index 5d0fd4d5..00000000 --- a/src/osx/gui/Menu.mm +++ /dev/null @@ -1,180 +0,0 @@ -#include "cru/osx/gui/Menu.h" -#import "MenuPrivate.h" - -#include "KeyboardPrivate.h" -#include "cru/common/platform/osx/Convert.h" - -#import <AppKit/NSApplication.h> - -namespace cru::platform::gui::osx { -using platform::osx::Convert; - -namespace { -std::unique_ptr<OsxMenu> application_menu = nullptr; -} - -namespace details { -OsxMenuItemPrivate::OsxMenuItemPrivate(OsxMenuItem* d) { - d_ = d; - sub_menu_ = new OsxMenu(d->GetUiApplication()); - sub_menu_->p_->SetParentItem(d); - handler_ = [[CruOsxMenuItemClickHandler alloc] init:this]; -} - -OsxMenuItemPrivate::~OsxMenuItemPrivate() { delete sub_menu_; } - -void OsxMenuItemPrivate::AttachToNative(NSMenuItem* native_menu_item, bool check_submenu) { - Expects(sub_menu_); - - menu_item_ = native_menu_item; - [native_menu_item setTarget:handler_]; - [native_menu_item setAction:@selector(handleClick)]; - if (check_submenu && [native_menu_item hasSubmenu]) { - sub_menu_->p_->AttachToNative([native_menu_item submenu]); - } -} - -OsxMenuPrivate::OsxMenuPrivate(OsxMenu* d) { d_ = d; } - -OsxMenuPrivate::~OsxMenuPrivate() { - for (auto item : items_) { - delete item; - } -} - -void OsxMenuPrivate::AttachToNative(NSMenu* native_menu) { - menu_ = native_menu; - - auto item_count = [native_menu numberOfItems]; - for (int i = 0; i < item_count; i++) { - auto native_item = [native_menu itemAtIndex:i]; - auto item = new OsxMenuItem(d_->GetUiApplication()); - item->p_->SetParentMenu(d_); - item->p_->AttachToNative(native_item, true); - items_.push_back(item); - } -} -} - -OsxMenuItem::OsxMenuItem(IUiApplication* ui_application) : OsxGuiResource(ui_application) { - p_ = new details::OsxMenuItemPrivate(this); -} - -OsxMenuItem::~OsxMenuItem() { delete p_; } - -String OsxMenuItem::GetTitle() { return Convert((CFStringRef)[p_->menu_item_ title]); } - -void OsxMenuItem::SetTitle(String title) { [p_->menu_item_ setTitle:(NSString*)Convert(title)]; } - -bool OsxMenuItem::IsEnabled() { return [p_->menu_item_ isEnabled]; } - -void OsxMenuItem::SetEnabled(bool enabled) { [p_->menu_item_ setEnabled:enabled]; } - -IMenu* OsxMenuItem::GetParentMenu() { return p_->parent_menu_; } - -IMenu* OsxMenuItem::GetSubmenu() { return p_->sub_menu_; } - -void OsxMenuItem::SetKeyboardShortcut(KeyCode key, KeyModifier modifiers) { - [p_->menu_item_ setKeyEquivalent:ConvertKeyCodeToKeyEquivalent(key)]; - [p_->menu_item_ setKeyEquivalentModifierMask:ConvertKeyModifier(modifiers)]; -} - -void OsxMenuItem::DeleteKeyboardShortcut() { - [p_->menu_item_ setKeyEquivalent:@""]; - [p_->menu_item_ setKeyEquivalentModifierMask:0]; -} - -void OsxMenuItem::SetOnClickHandler(std::function<void()> handler) { - p_->on_click_handler_ = std::move(handler); -} - -OsxMenu* OsxMenu::CreateOrGetApplicationMenu(IUiApplication* ui_application) { - if (application_menu) { - return application_menu.get(); - } - - NSMenu* native_main_menu = [[NSMenu alloc] init]; - [NSApp setMainMenu:native_main_menu]; - [native_main_menu setAutoenablesItems:NO]; - - application_menu.reset(new OsxMenu(ui_application)); - application_menu->p_->AttachToNative(native_main_menu); - - application_menu->CreateItemAt(0); - - return application_menu.get(); -} - -OsxMenu::OsxMenu(IUiApplication* ui_application) : OsxGuiResource(ui_application) { - p_ = new details::OsxMenuPrivate(this); -} - -OsxMenu::~OsxMenu() { delete p_; } - -IMenuItem* OsxMenu::GetItemAt(int index) { - if (index < 0 || index >= p_->items_.size()) { - return nullptr; - } - - return p_->items_[index]; -} - -int OsxMenu::GetItemCount() { return p_->items_.size(); } - -IMenuItem* OsxMenu::CreateItemAt(int index) { - if (index < 0) index = 0; - if (index > p_->items_.size()) index = p_->items_.size(); - - if (p_->parent_item_ && p_->items_.empty()) { - Expects(p_->menu_ == nullptr); - p_->menu_ = [[NSMenu alloc] init]; - [p_->menu_ setAutoenablesItems:NO]; - [p_->parent_item_->p_->GetNative() setSubmenu:p_->menu_]; - } - - auto native_item = [[NSMenuItem alloc] init]; - [p_->menu_ insertItem:native_item atIndex:index]; - - auto item = new OsxMenuItem(GetUiApplication()); - item->p_->SetParentMenu(this); - item->p_->AttachToNative(native_item, false); - p_->items_.insert(p_->items_.begin() + index, item); - - return item; -} - -void OsxMenu::RemoveItemAt(int index) { - if (index < 0 || index >= p_->items_.size()) { - return; - } - - auto item = p_->items_[index]; - [p_->menu_ removeItem:item->p_->GetNative()]; - p_->items_.erase(p_->items_.begin() + index); - - delete item; - - if (p_->items_.empty() && p_->parent_item_) { - Expects(p_->menu_ != nullptr); - [p_->parent_item_->p_->GetNative() setSubmenu:nullptr]; - p_->menu_ = nullptr; - } -} -} - -@implementation CruOsxMenuItemClickHandler { - cru::platform::gui::osx::details::OsxMenuItemPrivate* p_; -} - -- (id)init:(cru::platform::gui::osx::details::OsxMenuItemPrivate*)p { - p_ = p; - return self; -} - -- (void)handleClick { - if (p_->GetOnClickHandler()) { - p_->GetOnClickHandler()(); - } -} - -@end diff --git a/src/osx/gui/MenuPrivate.h b/src/osx/gui/MenuPrivate.h deleted file mode 100644 index d5269312..00000000 --- a/src/osx/gui/MenuPrivate.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once -#include "cru/osx/gui/Menu.h" - -#import <AppKit/NSMenu.h> -#import <AppKit/NSMenuItem.h> - -@interface CruOsxMenuItemClickHandler : NSObject -- init:(cru::platform::gui::osx::details::OsxMenuItemPrivate*)p; -- (void)handleClick; -@end - -namespace cru::platform::gui::osx { -namespace details { - -class OsxMenuItemPrivate { - friend OsxMenuItem; - - public: - explicit OsxMenuItemPrivate(OsxMenuItem* d); - - CRU_DELETE_COPY(OsxMenuItemPrivate) - CRU_DELETE_MOVE(OsxMenuItemPrivate) - - ~OsxMenuItemPrivate(); - - public: - NSMenuItem* GetNative() { return menu_item_; } - void SetParentMenu(OsxMenu* menu) { parent_menu_ = menu; } - void AttachToNative(NSMenuItem* native_menu_item, bool check_submenu); - - const std::function<void()> GetOnClickHandler() const { return on_click_handler_; } - - private: - OsxMenuItem* d_; - OsxMenu* parent_menu_ = nullptr; - NSMenuItem* menu_item_ = nullptr; - OsxMenu* sub_menu_ = nullptr; - std::function<void()> on_click_handler_; - CruOsxMenuItemClickHandler* handler_; -}; - -class OsxMenuPrivate { - friend OsxMenu; - - public: - explicit OsxMenuPrivate(OsxMenu* d); - - CRU_DELETE_COPY(OsxMenuPrivate) - CRU_DELETE_MOVE(OsxMenuPrivate) - - ~OsxMenuPrivate(); - - public: - void SetParentItem(OsxMenuItem* item) { parent_item_ = item; } - void AttachToNative(NSMenu* native_menu); - - private: - OsxMenu* d_; - OsxMenuItem* parent_item_ = nullptr; - NSMenu* menu_ = nullptr; - std::vector<OsxMenuItem*> items_; -}; -} // namespace details - -} // namespace cru::platform::gui::osx diff --git a/src/osx/gui/Resource.cpp b/src/osx/gui/Resource.cpp deleted file mode 100644 index a6be5d75..00000000 --- a/src/osx/gui/Resource.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "cru/osx/gui/Resource.h" - -namespace cru::platform::gui::osx { -OsxGuiResource::OsxGuiResource(IUiApplication* ui_application) - : ui_application_(ui_application) {} -} // namespace cru::platform::gui::osx diff --git a/src/osx/gui/UiApplication.mm b/src/osx/gui/UiApplication.mm deleted file mode 100644 index 43c49c5c..00000000 --- a/src/osx/gui/UiApplication.mm +++ /dev/null @@ -1,260 +0,0 @@ -#include "cru/osx/gui/UiApplication.h" - -#include "ClipboardPrivate.h" -#include "cru/common/log/Logger.h" -#include "cru/common/platform/osx/Convert.h" -#include "cru/osx/graphics/quartz/Factory.h" -#include "cru/osx/gui/Clipboard.h" -#include "cru/osx/gui/Cursor.h" -#include "cru/osx/gui/Menu.h" -#include "cru/osx/gui/Window.h" -#include "cru/platform/graphics/Factory.h" -#include "cru/platform/gui/Base.h" -#include "cru/platform/gui/UiApplication.h" -#include "cru/platform/gui/Window.h" - -#include <AppKit/NSApplication.h> -#include <Foundation/NSRunLoop.h> -#include <UniformTypeIdentifiers/UTType.h> - -#include <algorithm> -#include <iterator> -#include <memory> -#include <unordered_map> -#include <vector> - -@interface CruAppDelegate : NSObject <NSApplicationDelegate> -- (id)init:(cru::platform::gui::osx::details::OsxUiApplicationPrivate*)p; -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender; -- (void)applicationWillTerminate:(NSNotification*)notification; -@end - -namespace cru::platform::gui::osx { - -using cru::platform::osx::Convert; - -namespace details { -class OsxUiApplicationPrivate { - friend OsxUiApplication; - - public: - explicit OsxUiApplicationPrivate(OsxUiApplication* osx_ui_application) - : osx_ui_application_(osx_ui_application) { - app_delegate_ = [[CruAppDelegate alloc] init:this]; - } - - CRU_DELETE_COPY(OsxUiApplicationPrivate) - CRU_DELETE_MOVE(OsxUiApplicationPrivate) - - ~OsxUiApplicationPrivate() = default; - - void CallQuitHandlers(); - - private: - OsxUiApplication* osx_ui_application_; - CruAppDelegate* app_delegate_; - std::vector<std::function<void()>> quit_handlers_; - bool quit_on_all_window_closed_ = true; - - long long current_timer_id_ = 1; - std::unordered_map<long long, std::function<void()>> next_tick_; - std::unordered_map<long long, NSTimer*> timers_; - - std::vector<OsxWindow*> windows_; - - std::unique_ptr<OsxCursorManager> cursor_manager_; - - std::unique_ptr<OsxClipboard> clipboard_; - - std::unique_ptr<platform::graphics::osx::quartz::QuartzGraphicsFactory> quartz_graphics_factory_; -}; - -void OsxUiApplicationPrivate::CallQuitHandlers() { - for (const auto& handler : quit_handlers_) { - handler(); - } -} -} - -OsxUiApplication::OsxUiApplication() - : OsxGuiResource(this), p_(new details::OsxUiApplicationPrivate(this)) { - [NSApplication sharedApplication]; - - [NSApp setDelegate:p_->app_delegate_]; - p_->quartz_graphics_factory_ = std::make_unique<graphics::osx::quartz::QuartzGraphicsFactory>(); - p_->cursor_manager_ = std::make_unique<OsxCursorManager>(this); - p_->clipboard_ = std::make_unique<OsxClipboard>( - this, std::make_unique<details::OsxClipboardPrivate>([NSPasteboard generalPasteboard])); -} - -OsxUiApplication::~OsxUiApplication() {} - -int OsxUiApplication::Run() { - [NSApp run]; - return 0; -} - -void OsxUiApplication::RequestQuit(int quit_code) { - [NSApp terminate:[NSNumber numberWithInteger:quit_code]]; -} - -void OsxUiApplication::AddOnQuitHandler(std::function<void()> handler) { - p_->quit_handlers_.push_back(std::move(handler)); -} - -bool OsxUiApplication::IsQuitOnAllWindowClosed() { return p_->quit_on_all_window_closed_; } - -void OsxUiApplication::SetQuitOnAllWindowClosed(bool quit_on_all_window_closed) { - p_->quit_on_all_window_closed_ = quit_on_all_window_closed; -} - -long long OsxUiApplication::SetImmediate(std::function<void()> action) { - const long long id = p_->current_timer_id_++; - p_->next_tick_.emplace(id, std::move(action)); - - [[NSRunLoop mainRunLoop] performBlock:^{ - const auto i = p_->next_tick_.find(id); - if (i != p_->next_tick_.cend()) { - i->second(); - } - p_->next_tick_.erase(i); - }]; - - return id; -} - -long long OsxUiApplication::SetTimeout(std::chrono::milliseconds milliseconds, - std::function<void()> action) { - long long id = p_->current_timer_id_++; - p_->timers_.emplace(id, [NSTimer scheduledTimerWithTimeInterval:milliseconds.count() / 1000.0 - repeats:false - block:^(NSTimer* timer) { - action(); - p_->timers_.erase(id); - }]); - - return id; -} - -long long OsxUiApplication::SetInterval(std::chrono::milliseconds milliseconds, - std::function<void()> action) { - long long id = p_->current_timer_id_++; - p_->timers_.emplace(id, [NSTimer scheduledTimerWithTimeInterval:milliseconds.count() / 1000.0 - repeats:true - block:^(NSTimer* timer) { - action(); - }]); - - return id; -} - -void OsxUiApplication::CancelTimer(long long id) { - p_->next_tick_.erase(id); - auto i = p_->timers_.find(id); - if (i != p_->timers_.cend()) { - [i->second invalidate]; - p_->timers_.erase(i); - } -} - -std::vector<INativeWindow*> OsxUiApplication::GetAllWindow() { - std::vector<INativeWindow*> result; - std::transform(p_->windows_.cbegin(), p_->windows_.cend(), std::back_inserter(result), - [](OsxWindow* w) { return static_cast<INativeWindow*>(w); }); - return result; -} - -INativeWindow* OsxUiApplication::CreateWindow() { - auto window = new OsxWindow(this); - p_->windows_.push_back(window); - return window; -} - -ICursorManager* OsxUiApplication::GetCursorManager() { return p_->cursor_manager_.get(); } - -IClipboard* OsxUiApplication::GetClipboard() { return p_->clipboard_.get(); } - -IMenu* OsxUiApplication::GetApplicationMenu() { return OsxMenu::CreateOrGetApplicationMenu(this); } - -graphics::IGraphicsFactory* OsxUiApplication::GetGraphicsFactory() { - return p_->quartz_graphics_factory_.get(); -} - -std::optional<String> OsxUiApplication::ShowSaveDialog(SaveDialogOptions options) { - NSSavePanel* panel = [NSSavePanel savePanel]; - [panel setTitle:(NSString*)Convert(options.title)]; - [panel setPrompt:(NSString*)Convert(options.prompt)]; - [panel setMessage:(NSString*)Convert(options.message)]; - - NSMutableArray* allowed_content_types = [NSMutableArray array]; - - for (const auto& file_type : options.allowed_file_types) { - [allowed_content_types - addObject:[UTType typeWithFilenameExtension:(NSString*)Convert(file_type)]]; - } - - [panel setAllowedContentTypes:allowed_content_types]; - [panel setAllowsOtherFileTypes:options.allow_all_file_types]; - - auto model_result = [panel runModal]; - if (model_result == NSModalResponseOK) { - return Convert((CFStringRef)[[panel URL] path]); - } else { - return std::nullopt; - } -} - -std::optional<std::vector<String>> OsxUiApplication::ShowOpenDialog(OpenDialogOptions options) { - NSOpenPanel* panel = [NSOpenPanel openPanel]; - [panel setTitle:(NSString*)Convert(options.title)]; - [panel setPrompt:(NSString*)Convert(options.prompt)]; - [panel setMessage:(NSString*)Convert(options.message)]; - - NSMutableArray* allowed_content_types = [NSMutableArray array]; - - for (const auto& file_type : options.allowed_file_types) { - [allowed_content_types - addObject:[UTType typeWithFilenameExtension:(NSString*)Convert(file_type)]]; - } - - [panel setAllowedContentTypes:allowed_content_types]; - [panel setAllowsOtherFileTypes:options.allow_all_file_types]; - - [panel setCanChooseFiles:options.can_choose_files]; - [panel setCanChooseDirectories:options.can_choose_directories]; - [panel setAllowsMultipleSelection:options.allow_mulitple_selection]; - - auto model_result = [panel runModal]; - if (model_result == NSModalResponseOK) { - std::vector<String> result; - for (NSURL* url in [panel URLs]) { - result.push_back(Convert((CFStringRef)[url path])); - } - return result; - } else { - return std::nullopt; - } -} - -void OsxUiApplication::UnregisterWindow(OsxWindow* window) { - p_->windows_.erase( - std::remove(p_->windows_.begin(), p_->windows_.end(), static_cast<INativeWindow*>(window)), - p_->windows_.cend()); -} -} - -@implementation CruAppDelegate { - cru::platform::gui::osx::details::OsxUiApplicationPrivate* _p; -} - -- (id)init:(cru::platform::gui::osx::details::OsxUiApplicationPrivate*)p { - _p = p; - return self; -} -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender { - return NSApplicationTerminateReply::NSTerminateNow; -} -- (void)applicationWillTerminate:(NSNotification*)notification { - _p->CallQuitHandlers(); -} -@end diff --git a/src/osx/gui/Window.mm b/src/osx/gui/Window.mm deleted file mode 100644 index 8d15ef37..00000000 --- a/src/osx/gui/Window.mm +++ /dev/null @@ -1,800 +0,0 @@ -#include "cru/osx/gui/Window.h" -#include "WindowPrivate.h" - -#include "CursorPrivate.h" -#include "InputMethodPrivate.h" -#include "cru/common/Range.h" -#include "cru/common/log/Logger.h" -#include "cru/osx/Convert.h" -#include "cru/osx/graphics/quartz/Convert.h" -#include "cru/osx/graphics/quartz/Painter.h" -#include "cru/osx/gui/Cursor.h" -#include "cru/osx/gui/InputMethod.h" -#include "cru/osx/gui/Keyboard.h" -#include "cru/osx/gui/Resource.h" -#include "cru/osx/gui/UiApplication.h" -#include "cru/platform/Check.h" -#include "cru/platform/graphics/NullPainter.h" -#include "cru/platform/gui/TimerHelper.h" - -#include <AppKit/AppKit.h> -#include <Foundation/Foundation.h> - -#include <limits> -#include <memory> -#include <unordered_set> - -namespace { -constexpr int key_down_debug = 0; -} - -using cru::platform::osx::Convert; -using cru::platform::graphics::osx::quartz::Convert; - -namespace cru::platform::gui::osx { -namespace { -inline NSWindowStyleMask CalcWindowStyleMask(WindowStyleFlag flag) { - return flag & WindowStyleFlags::NoCaptionAndBorder - ? NSWindowStyleMaskBorderless - : NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | - NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable; -} -} - -namespace details { -OsxWindowPrivate::OsxWindowPrivate(OsxWindow* osx_window) : osx_window_(osx_window) { - window_delegate_ = [[CruWindowDelegate alloc] init:this]; - - content_rect_ = {100, 100, 400, 200}; - - input_method_context_ = std::make_unique<OsxInputMethodContext>(osx_window); -} - -OsxWindowPrivate::~OsxWindowPrivate() {} - -void OsxWindowPrivate::OnWindowWillClose() { - if (window_) destroy_event_.Raise(nullptr); - window_ = nil; - CGLayerRelease(draw_layer_); - draw_layer_ = nullptr; - - if (osx_window_->GetUiApplication()->IsQuitOnAllWindowClosed()) { - const auto& all_window = osx_window_->GetUiApplication()->GetAllWindow(); - - bool quit = true; - - for (auto window : all_window) { - auto w = CheckPlatform<OsxWindow>(window, osx_window_->GetPlatformId()); - if (w->p_->window_) { - quit = false; - break; - } - } - - if (quit) { - osx_window_->GetUiApplication()->RequestQuit(0); - } - } -} - -void OsxWindowPrivate::OnWindowDidExpose() { osx_window_->RequestRepaint(); } -void OsxWindowPrivate::OnWindowDidUpdate() {} -void OsxWindowPrivate::OnWindowDidMove() { content_rect_ = RetrieveContentRect(); } - -void OsxWindowPrivate::OnWindowDidResize() { - content_rect_ = RetrieveContentRect(); - - auto view = [window_ contentView]; - [view removeTrackingArea:[view trackingAreas][0]]; - auto tracking_area = [[NSTrackingArea alloc] - initWithRect:CGRectMake(0, 0, content_rect_.width, content_rect_.height) - options:(NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways) - owner:view - userInfo:nil]; - [view addTrackingArea:tracking_area]; - - CGLayerRelease(draw_layer_); - draw_layer_ = CreateLayer(Convert(content_rect_.GetSize())); - - resize_event_.Raise(osx_window_->GetClientSize()); - - osx_window_->RequestRepaint(); -} - -void OsxWindowPrivate::OnBecomeKeyWindow() { focus_event_.Raise(FocusChangeType::Gain); } - -void OsxWindowPrivate::OnResignKeyWindow() { focus_event_.Raise(FocusChangeType::Lose); } - -void OsxWindowPrivate::OnMouseEnterLeave(MouseEnterLeaveType type) { - mouse_enter_leave_event_.Raise(type); - if (type == MouseEnterLeaveType::Enter) { - mouse_in_ = true; - UpdateCursor(); - } else { - mouse_in_ = false; - } -} - -void OsxWindowPrivate::OnMouseMove(Point p) { mouse_move_event_.Raise(TransformMousePoint(p)); } - -void OsxWindowPrivate::OnMouseDown(MouseButton button, Point p, KeyModifier key_modifier) { - mouse_down_event_.Raise({button, TransformMousePoint(p), key_modifier}); -} - -void OsxWindowPrivate::OnMouseUp(MouseButton button, Point p, KeyModifier key_modifier) { - mouse_up_event_.Raise({button, TransformMousePoint(p), key_modifier}); -} - -void OsxWindowPrivate::OnMouseWheel(float delta, Point p, KeyModifier key_modifier, - bool horizontal) { - mouse_wheel_event_.Raise({delta, TransformMousePoint(p), key_modifier, horizontal}); -} - -void OsxWindowPrivate::OnKeyDown(KeyCode key, KeyModifier key_modifier) { - key_down_event_.Raise({key, key_modifier}); -} - -void OsxWindowPrivate::OnKeyUp(KeyCode key, KeyModifier key_modifier) { - key_up_event_.Raise({key, key_modifier}); -} - -CGLayerRef OsxWindowPrivate::CreateLayer(const CGSize& size) { - auto s = size; - if (s.width == 0) s.width = 1; - if (s.height == 0) s.height = 1; - - auto draw_layer = CGLayerCreateWithContext(nullptr, s, nullptr); - Ensures(draw_layer); - - return draw_layer; -} - -void OsxWindowPrivate::UpdateCursor() { - auto cursor = cursor_ == nullptr - ? std::dynamic_pointer_cast<OsxCursor>( - osx_window_->GetUiApplication()->GetCursorManager()->GetSystemCursor( - SystemCursorType::Arrow)) - : cursor_; - - [cursor->p_->ns_cursor_ set]; -} - -Point OsxWindowPrivate::TransformMousePoint(const Point& point) { - Point r = point; - r.y = content_rect_.height - r.y; - return r; -} - -void OsxWindowPrivate::CreateWindow() { - Expects(!window_); - - NSWindowStyleMask style_mask = CalcWindowStyleMask(style_flag_); - window_ = [[CruWindow alloc] init:this - contentRect:{0, 0, content_rect_.width, content_rect_.height} - style:style_mask]; - Ensures(window_); - - osx_window_->SetClientRect(content_rect_); - - [window_ setDelegate:window_delegate_]; - - if (parent_) { - auto parent = CheckPlatform<OsxWindow>(parent_, this->osx_window_->GetPlatformId()); - [window_ setParentWindow:parent->p_->window_]; - } - - NSView* content_view = [[CruView alloc] init:this - input_context_p:input_method_context_->p_.get() - frame:Rect(Point{}, content_rect_.GetSize())]; - - [window_ setContentView:content_view]; - - auto title_str = Convert(title_); - [window_ setTitle:(NSString*)title_str]; - CFRelease(title_str); - - draw_layer_ = CreateLayer(Convert(content_rect_.GetSize())); - - create_event_.Raise(nullptr); - - osx_window_->RequestRepaint(); -} - -Size OsxWindowPrivate::GetScreenSize() { - auto screen = window_ ? [window_ screen] : [NSScreen mainScreen]; - auto size = [screen frame].size; - return Convert(size); -} - -Rect OsxWindowPrivate::RetrieveContentRect() { - NSRect rect = [NSWindow contentRectForFrameRect:[window_ frame] - styleMask:CalcWindowStyleMask(style_flag_)]; - rect.origin.y = GetScreenSize().height - rect.origin.y - rect.size.height; - return cru::platform::graphics::osx::quartz::Convert(rect); -} - -} - -OsxWindow::OsxWindow(OsxUiApplication* ui_application) - : OsxGuiResource(ui_application), p_(new details::OsxWindowPrivate(this)) {} - -OsxWindow::~OsxWindow() { - if (p_->window_) { - [p_->window_ close]; - } - dynamic_cast<OsxUiApplication*>(GetUiApplication())->UnregisterWindow(this); -} - -void OsxWindow::Close() { - if (p_->window_) { - [p_->window_ close]; - } -} - -INativeWindow* OsxWindow::GetParent() { return p_->parent_; } - -void OsxWindow::SetParent(INativeWindow* parent) { - auto p = CheckPlatform<OsxWindow>(parent, GetPlatformId()); - - p_->parent_ = parent; - - if (p_->window_) { - [p_->window_ setParentWindow:p->p_->window_]; - } -} - -WindowStyleFlag OsxWindow::GetStyleFlag() { return p_->style_flag_; } - -void OsxWindow::SetStyleFlag(WindowStyleFlag flag) { - p_->style_flag_ = flag; - - if (p_->window_) { - [p_->window_ close]; - } -} - -String OsxWindow::GetTitle() { return p_->title_; } - -void OsxWindow::SetTitle(String title) { - p_->title_ = title; - - if (p_->window_) { - auto str = Convert(title); - [p_->window_ setTitle:(NSString*)str]; - CFRelease(str); - } -} - -WindowVisibilityType OsxWindow::GetVisibility() { - if (!p_->window_) return WindowVisibilityType::Hide; - if ([p_->window_ isMiniaturized]) return WindowVisibilityType::Minimize; - return [p_->window_ isVisible] ? WindowVisibilityType::Show : WindowVisibilityType::Hide; -} - -void OsxWindow::SetVisibility(WindowVisibilityType visibility) { - if (p_->window_) { - if (visibility == WindowVisibilityType::Show) { - [p_->window_ orderFront:nil]; - p_->visibility_change_event_.Raise(WindowVisibilityType::Show); - } else if (visibility == WindowVisibilityType::Hide) { - [p_->window_ orderOut:nil]; - p_->visibility_change_event_.Raise(WindowVisibilityType::Hide); - } else if (visibility == WindowVisibilityType::Minimize) { - [p_->window_ miniaturize:nil]; - } - } else { - if (visibility == WindowVisibilityType::Show) { - p_->CreateWindow(); - [p_->window_ orderFront:nil]; - p_->visibility_change_event_.Raise(WindowVisibilityType::Show); - } - } -} - -Size OsxWindow::GetClientSize() { return p_->content_rect_.GetSize(); } - -void OsxWindow::SetClientSize(const Size& size) { - if (p_->window_) { - auto rect = GetClientRect(); - rect.SetSize(size); - SetClientRect(rect); - } else { - p_->content_rect_.SetSize(size); - } -} - -Rect OsxWindow::GetClientRect() { return p_->content_rect_; } - -void OsxWindow::SetClientRect(const Rect& rect) { - if (p_->window_) { - auto r = Convert(rect); - r.origin.y = p_->GetScreenSize().height - r.origin.y - r.size.height; - r = [NSWindow frameRectForContentRect:r styleMask:CalcWindowStyleMask(p_->style_flag_)]; - [p_->window_ setFrame:r display:false]; - } else { - p_->content_rect_ = rect; - } -} - -Rect OsxWindow::GetWindowRect() { - auto r = Convert(p_->content_rect_); - r.origin.y = p_->GetScreenSize().height - r.origin.y - r.size.height; - r = [NSWindow frameRectForContentRect:r styleMask:CalcWindowStyleMask(p_->style_flag_)]; - r.origin.y = p_->GetScreenSize().height - r.origin.y - r.size.height; - return Convert(r); -} - -void OsxWindow::SetWindowRect(const Rect& rect) { - auto r = Convert(rect); - r.origin.y = p_->GetScreenSize().height - r.origin.y - r.size.height; - r = [NSWindow frameRectForContentRect:r styleMask:CalcWindowStyleMask(p_->style_flag_)]; - r.origin.y = p_->GetScreenSize().height - r.origin.y - r.size.height; - SetClientRect(Convert(r)); -} - -void OsxWindow::RequestRepaint() { - if (!p_->draw_timer_) { - p_->draw_timer_ = GetUiApplication()->SetImmediate([this] { - p_->paint_event_.Raise(nullptr); - p_->draw_timer_.Release(); - }); - } -} - -std::unique_ptr<graphics::IPainter> OsxWindow::BeginPaint() { - if (!p_->window_) { - return std::make_unique<graphics::NullPainter>(); - } - - CGContextRef cg_context = CGLayerGetContext(p_->draw_layer_); - - return std::make_unique<cru::platform::graphics::osx::quartz::QuartzCGContextPainter>( - GetUiApplication()->GetGraphicsFactory(), cg_context, false, GetClientSize(), - [this](graphics::osx::quartz::QuartzCGContextPainter*) { - [[p_->window_ contentView] setNeedsDisplay:YES]; - }); -} - -bool OsxWindow::RequestFocus() { - if (!p_->window_) return false; - [p_->window_ makeKeyWindow]; - return true; -} - -Point OsxWindow::GetMousePosition() { - auto p = [p_->window_ mouseLocationOutsideOfEventStream]; - return Point(p.x, p.y); -} - -bool OsxWindow::CaptureMouse() { return true; } - -bool OsxWindow::ReleaseMouse() { return true; } - -void OsxWindow::SetCursor(std::shared_ptr<ICursor> cursor) { - p_->cursor_ = CheckPlatform<OsxCursor>(cursor, GetPlatformId()); - p_->UpdateCursor(); -} - -void OsxWindow::SetToForeground() { - if (!p_->window_) return; - [p_->window_ makeMainWindow]; - [p_->window_ orderFrontRegardless]; -} - -IEvent<std::nullptr_t>* OsxWindow::CreateEvent() { return &p_->create_event_; } -IEvent<std::nullptr_t>* OsxWindow::DestroyEvent() { return &p_->destroy_event_; } -IEvent<std::nullptr_t>* OsxWindow::PaintEvent() { return &p_->paint_event_; } -IEvent<WindowVisibilityType>* OsxWindow::VisibilityChangeEvent() { - return &p_->visibility_change_event_; -} -IEvent<Size>* OsxWindow::ResizeEvent() { return &p_->resize_event_; } -IEvent<FocusChangeType>* OsxWindow::FocusEvent() { return &p_->focus_event_; } -IEvent<MouseEnterLeaveType>* OsxWindow::MouseEnterLeaveEvent() { - return &p_->mouse_enter_leave_event_; -} -IEvent<Point>* OsxWindow::MouseMoveEvent() { return &p_->mouse_move_event_; } -IEvent<NativeMouseButtonEventArgs>* OsxWindow::MouseDownEvent() { return &p_->mouse_down_event_; } -IEvent<NativeMouseButtonEventArgs>* OsxWindow::MouseUpEvent() { return &p_->mouse_up_event_; } -IEvent<NativeMouseWheelEventArgs>* OsxWindow::MouseWheelEvent() { return &p_->mouse_wheel_event_; } -IEvent<NativeKeyEventArgs>* OsxWindow::KeyDownEvent() { return &p_->key_down_event_; } -IEvent<NativeKeyEventArgs>* OsxWindow::KeyUpEvent() { return &p_->key_up_event_; } - -IInputMethodContext* OsxWindow::GetInputMethodContext() { return p_->input_method_context_.get(); } -} - -namespace { -cru::platform::gui::KeyModifier GetKeyModifier(NSEvent* event) { - cru::platform::gui::KeyModifier key_modifier; - if (event.modifierFlags & NSEventModifierFlagControl) - key_modifier |= cru::platform::gui::KeyModifiers::ctrl; - if (event.modifierFlags & NSEventModifierFlagOption) - key_modifier |= cru::platform::gui::KeyModifiers::alt; - if (event.modifierFlags & NSEventModifierFlagShift) - key_modifier |= cru::platform::gui::KeyModifiers::shift; - if (event.modifierFlags & NSEventModifierFlagCommand) - key_modifier |= cru::platform::gui::KeyModifiers::command; - return key_modifier; -} -} - -@implementation CruWindow { - cru::platform::gui::osx::details::OsxWindowPrivate* _p; -} - -- (instancetype)init:(cru::platform::gui::osx::details::OsxWindowPrivate*)p - contentRect:(NSRect)contentRect - style:(NSWindowStyleMask)style { - [super initWithContentRect:contentRect - styleMask:style - backing:NSBackingStoreBuffered - defer:false]; - _p = p; - - [self setAcceptsMouseMovedEvents:YES]; - - return self; -} - -- (BOOL)canBecomeMainWindow { - return YES; -} - -- (BOOL)canBecomeKeyWindow { - return YES; -} -@end - -@implementation CruView { - cru::platform::gui::osx::details::OsxWindowPrivate* _p; - cru::platform::gui::osx::details::OsxInputMethodContextPrivate* _input_context_p; - NSMutableAttributedString* _input_context_text; -} - -- (instancetype)init:(cru::platform::gui::osx::details::OsxWindowPrivate*)p - input_context_p: - (cru::platform::gui::osx::details::OsxInputMethodContextPrivate*)input_context_p - frame:(cru::platform::Rect)frame { - [super initWithFrame:cru::platform::graphics::osx::quartz::Convert(frame)]; - _p = p; - _input_context_p = input_context_p; - - auto tracking_area = [[NSTrackingArea alloc] - initWithRect:Convert(frame) - options:(NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways) - owner:self - userInfo:nil]; - [self addTrackingArea:tracking_area]; - - return self; -} - -- (void)drawRect:(NSRect)dirtyRect { - auto cg_context = [[NSGraphicsContext currentContext] CGContext]; - auto layer = _p->GetDrawLayer(); - Ensures(layer); - CGContextDrawLayerAtPoint(cg_context, CGPointMake(0, 0), layer); -} - -- (BOOL)acceptsFirstResponder { - return YES; -} - -- (BOOL)canBecomeKeyView { - return YES; -} - -- (void)mouseMoved:(NSEvent*)event { - _p->OnMouseMove(cru::platform::Point(event.locationInWindow.x, event.locationInWindow.y)); -} - -- (void)mouseDragged:(NSEvent*)event { - _p->OnMouseMove(cru::platform::Point(event.locationInWindow.x, event.locationInWindow.y)); -} - -- (void)rightMouseDragged:(NSEvent*)event { - _p->OnMouseMove(cru::platform::Point(event.locationInWindow.x, event.locationInWindow.y)); -} - -- (void)mouseEntered:(NSEvent*)event { - _p->OnMouseEnterLeave(cru::platform::gui::MouseEnterLeaveType::Enter); -} - -- (void)mouseExited:(NSEvent*)event { - _p->OnMouseEnterLeave(cru::platform::gui::MouseEnterLeaveType::Leave); -} - -- (void)mouseDown:(NSEvent*)event { - [[self window] makeKeyWindow]; - - auto key_modifier = GetKeyModifier(event); - cru::platform::Point p(event.locationInWindow.x, event.locationInWindow.y); - - _p->OnMouseDown(cru::platform::gui::mouse_buttons::left, p, key_modifier); -} - -- (void)mouseUp:(NSEvent*)event { - auto key_modifier = GetKeyModifier(event); - cru::platform::Point p(event.locationInWindow.x, event.locationInWindow.y); - - _p->OnMouseUp(cru::platform::gui::mouse_buttons::left, p, key_modifier); -} - -- (void)rightMouseDown:(NSEvent*)event { - auto key_modifier = GetKeyModifier(event); - cru::platform::Point p(event.locationInWindow.x, event.locationInWindow.y); - - _p->OnMouseDown(cru::platform::gui::mouse_buttons::right, p, key_modifier); -} - -- (void)rightMouseUp:(NSEvent*)event { - auto key_modifier = GetKeyModifier(event); - cru::platform::Point p(event.locationInWindow.x, event.locationInWindow.y); - - _p->OnMouseUp(cru::platform::gui::mouse_buttons::right, p, key_modifier); -} - -- (void)scrollWheel:(NSEvent*)event { - auto key_modifier = GetKeyModifier(event); - cru::platform::Point p(event.locationInWindow.x, event.locationInWindow.y); - - if (event.scrollingDeltaY) { - _p->OnMouseWheel(static_cast<float>(event.scrollingDeltaY), p, key_modifier, false); - } - - if (event.scrollingDeltaX) { - _p->OnMouseWheel(static_cast<float>(event.scrollingDeltaX), p, key_modifier, true); - } -} - -namespace { -using cru::platform::gui::KeyCode; -const std::unordered_set<KeyCode> input_context_handle_codes{ - KeyCode::A, - KeyCode::B, - KeyCode::C, - KeyCode::D, - KeyCode::E, - KeyCode::F, - KeyCode::G, - KeyCode::H, - KeyCode::I, - KeyCode::J, - KeyCode::K, - KeyCode::L, - KeyCode::M, - KeyCode::N, - KeyCode::O, - KeyCode::P, - KeyCode::Q, - KeyCode::R, - KeyCode::S, - KeyCode::T, - KeyCode::U, - KeyCode::V, - KeyCode::W, - KeyCode::X, - KeyCode::Y, - KeyCode::Z, - KeyCode::N0, - KeyCode::N1, - KeyCode::N2, - KeyCode::N3, - KeyCode::N4, - KeyCode::N5, - KeyCode::N6, - KeyCode::N7, - KeyCode::N8, - KeyCode::N9, - KeyCode::Comma, - KeyCode::Period, - KeyCode::Slash, - KeyCode::Semicolon, - KeyCode::Quote, - KeyCode::LeftSquareBracket, - KeyCode::RightSquareBracket, - KeyCode::BackSlash, - KeyCode::Minus, - KeyCode::Equal, - KeyCode::GraveAccent, -}; -} - -const std::unordered_set<KeyCode> input_context_handle_codes_when_has_text{ - KeyCode::Backspace, KeyCode::Space, KeyCode::Return, KeyCode::Left, - KeyCode::Right, KeyCode::Up, KeyCode::Down}; - -- (void)keyDown:(NSEvent*)event { - auto key_modifier = GetKeyModifier(event); - - bool handled = false; - - auto input_context = dynamic_cast<cru::platform::gui::osx::OsxInputMethodContext*>( - _p->GetWindow()->GetInputMethodContext()); - Ensures(input_context); - - auto c = cru::platform::gui::osx::KeyCodeFromOsxToCru(event.keyCode); - - if (input_context->IsEnabled()) { - if (input_context_handle_codes.count(c) && - !(key_modifier & ~cru::platform::gui::KeyModifiers::shift)) { - handled = [[self inputContext] handleEvent:event]; - } else if (input_context_handle_codes_when_has_text.count(c) && !key_modifier) { - if (!input_context->GetCompositionText().text.empty()) { - handled = [[self inputContext] handleEvent:event]; - } else { - if (c == KeyCode::Return) { - _input_context_p->RaiseTextEvent(u"\n"); - handled = true; - } else if (c == KeyCode::Space) { - _input_context_p->RaiseTextEvent(u" "); - handled = true; - } - } - } - } - - if (!handled) { - _p->OnKeyDown(c, key_modifier); - } -} - -- (void)keyUp:(NSEvent*)event { - // cru::CRU_LOG_DEBUG(u"CruView", u"Recieved key up."); - - auto key_modifier = GetKeyModifier(event); - auto c = cru::platform::gui::osx::KeyCodeFromOsxToCru(event.keyCode); - - _p->OnKeyUp(c, key_modifier); -} - -- (BOOL)hasMarkedText { - return _input_context_text != nil; -} - -- (NSRange)markedRange { - return _input_context_text == nil ? NSRange{NSNotFound, 0} - : NSRange{0, [_input_context_text length]}; -} - -- (NSRange)selectedRange { - return NSMakeRange(_input_context_p->GetSelectionRange().position, - _input_context_p->GetSelectionRange().count); -} - -- (void)setMarkedText:(id)string - selectedRange:(NSRange)selectedRange - replacementRange:(NSRange)replacementRange { - CFStringRef s; - if ([string isKindOfClass:[NSString class]]) { - s = (CFStringRef)string; - } else { - auto as = (CFAttributedStringRef)string; - s = CFAttributedStringGetString(as); - } - - auto ss = Convert(s); - - // cru::CRU_LOG_DEBUG(u"CruView", - // u"Received setMarkedText string: {}, selected range: ({}, {}), " - // u"replacement range: ({}, {}).", - // ss, selectedRange.location, selectedRange.length, replacementRange.location, - // replacementRange.length); - - if (_input_context_text == nil) { - _input_context_text = [[NSMutableAttributedString alloc] init]; - _input_context_p->RaiseCompositionStartEvent(); - } - - if (replacementRange.location == NSNotFound) replacementRange.location = 0; - - [_input_context_text - replaceCharactersInRange:NSMakeRange(0, [_input_context_text length]) - withAttributedString:[[NSAttributedString alloc] initWithString:(NSString*)s]]; - - cru::platform::gui::CompositionText composition_text; - composition_text.text = Convert((CFStringRef)[_input_context_text string]); - composition_text.selection.position = ss.IndexFromCodePointToCodeUnit(selectedRange.location); - composition_text.selection.count = - ss.IndexFromCodePointToCodeUnit(selectedRange.location + selectedRange.length) - - composition_text.selection.position; - _input_context_p->SetCompositionText(composition_text); - _input_context_p->RaiseCompositionEvent(); -} - -- (void)unmarkText { - _input_context_text = nil; - _input_context_p->RaiseCompositionEndEvent(); -} - -- (NSArray<NSAttributedStringKey>*)validAttributesForMarkedText { - return @[ - (NSString*)kCTUnderlineColorAttributeName, (NSString*)kCTUnderlineStyleAttributeName, - (NSString*)kCTForegroundColorAttributeName, (NSString*)kCTBackgroundColorAttributeName - ]; -} - -- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range - actualRange:(NSRangePointer)actualRange { - cru::Range r(range.location, range.length); - - r = r.CoerceInto(0, [_input_context_text length]); - - return [_input_context_text attributedSubstringFromRange:NSMakeRange(r.position, r.count)]; -} - -- (void)insertText:(id)string replacementRange:(NSRange)replacementRange { - CFStringRef s; - if ([string isKindOfClass:[NSString class]]) { - s = (CFStringRef)string; - } else { - auto as = (CFAttributedStringRef)string; - s = CFAttributedStringGetString(as); - } - - _input_context_text = nil; - _input_context_p->SetCompositionText(cru::platform::gui::CompositionText()); - cru::String ss = Convert(s); - - // cru::CRU_LOG_DEBUG(u"CruView", u"Finish composition: {}, replacement range: ({}, {})", ss, - // replacementRange.location, replacementRange.length); - - _input_context_p->RaiseCompositionEvent(); - _input_context_p->RaiseCompositionEndEvent(); - _input_context_p->RaiseTextEvent(ss); -} - -- (NSUInteger)characterIndexForPoint:(NSPoint)point { - return NSNotFound; -} - -- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)actualRange { - NSRect result; - result.origin.x = _input_context_p->GetCandidateWindowPosition().x; - result.origin.y = _input_context_p->GetCandidateWindowPosition().y; - result.size.height = 16; - result.size.width = 0; - return result; -} - -- (void)doCommandBySelector:(SEL)selector { - _input_context_p->PerformSel(selector); -} -@end - -@implementation CruWindowDelegate { - cru::platform::gui::osx::details::OsxWindowPrivate* _p; -} - -- (id)init:(cru::platform::gui::osx::details::OsxWindowPrivate*)p { - _p = p; - return self; -} - -- (void)windowWillClose:(NSNotification*)notification { - _p->OnWindowWillClose(); -} - -- (void)windowDidExpose:(NSNotification*)notification { - _p->OnWindowDidExpose(); -} - -- (void)windowDidUpdate:(NSNotification*)notification { - _p->OnWindowDidUpdate(); -} - -- (void)windowDidMove:(NSNotification*)notification { - _p->OnWindowDidMove(); -} - -- (void)windowDidResize:(NSNotification*)notification { - _p->OnWindowDidResize(); -} - -- (void)windowDidBecomeKey:(NSNotification*)notification { - _p->OnBecomeKeyWindow(); -} - -- (void)windowDidResignKey:(NSNotification*)notification { - _p->OnResignKeyWindow(); -} -@end diff --git a/src/osx/gui/WindowPrivate.h b/src/osx/gui/WindowPrivate.h deleted file mode 100644 index cdd34246..00000000 --- a/src/osx/gui/WindowPrivate.h +++ /dev/null @@ -1,118 +0,0 @@ -#pragma once -#include "cru/osx/gui/Window.h" - -#include "cru/common/Event.h" -#include "cru/osx/gui/Cursor.h" -#include "cru/platform/gui/TimerHelper.h" -#include "cru/platform/gui/Window.h" - -#import <AppKit/AppKit.h> - -@interface CruWindowDelegate : NSObject <NSWindowDelegate> -- (id)init:(cru::platform::gui::osx::details::OsxWindowPrivate*)p; -@end - -@interface CruWindow : NSWindow -- (instancetype)init:(cru::platform::gui::osx::details::OsxWindowPrivate*)p - contentRect:(NSRect)contentRect - style:(NSWindowStyleMask)style; -@end - -@interface CruView : NSView <NSTextInputClient> -- (instancetype)init:(cru::platform::gui::osx::details::OsxWindowPrivate*)p - input_context_p: - (cru::platform::gui::osx::details::OsxInputMethodContextPrivate*)input_context_p - frame:(cru::platform::Rect)frame; -@end - -namespace cru::platform::gui::osx { - -namespace details { -class OsxInputMethodContextPrivate; - -class OsxWindowPrivate { - friend OsxWindow; - friend OsxInputMethodContextPrivate; - - public: - explicit OsxWindowPrivate(OsxWindow* osx_window); - - CRU_DELETE_COPY(OsxWindowPrivate) - CRU_DELETE_MOVE(OsxWindowPrivate) - - ~OsxWindowPrivate(); - - public: - void OnMouseEnterLeave(MouseEnterLeaveType type); - void OnMouseMove(Point p); - void OnMouseDown(MouseButton button, Point p, KeyModifier key_modifier); - void OnMouseUp(MouseButton button, Point p, KeyModifier key_modifier); - void OnMouseWheel(float delta, Point p, KeyModifier key_modifier, bool horizontal); - void OnKeyDown(KeyCode key, KeyModifier key_modifier); - void OnKeyUp(KeyCode key, KeyModifier key_modifier); - - void OnWindowWillClose(); - void OnWindowDidExpose(); - void OnWindowDidUpdate(); - void OnWindowDidMove(); - void OnWindowDidResize(); - void OnBecomeKeyWindow(); - void OnResignKeyWindow(); - - CGLayerRef GetDrawLayer() { return draw_layer_; } - - OsxWindow* GetWindow() { return osx_window_; } - NSWindow* GetNSWindow() { return window_; } - - private: - Size GetScreenSize(); - - void CreateWindow(); - - void UpdateCursor(); - - Point TransformMousePoint(const Point& point); - - CGLayerRef CreateLayer(const CGSize& size); - - Rect RetrieveContentRect(); - - private: - OsxWindow* osx_window_; - - INativeWindow* parent_ = nullptr; - WindowStyleFlag style_flag_ = WindowStyleFlag{}; - - String title_; - - Rect content_rect_; - - NSWindow* window_ = nil; - CruWindowDelegate* window_delegate_ = nil; - - CGLayerRef draw_layer_ = nullptr; - - bool mouse_in_ = false; - - std::shared_ptr<OsxCursor> cursor_ = nullptr; - - std::unique_ptr<OsxInputMethodContext> input_method_context_; - - TimerAutoCanceler draw_timer_; - - Event<std::nullptr_t> create_event_; - Event<std::nullptr_t> destroy_event_; - Event<std::nullptr_t> paint_event_; - Event<WindowVisibilityType> visibility_change_event_; - Event<Size> resize_event_; - Event<FocusChangeType> focus_event_; - Event<MouseEnterLeaveType> mouse_enter_leave_event_; - Event<Point> mouse_move_event_; - Event<NativeMouseButtonEventArgs> mouse_down_event_; - Event<NativeMouseButtonEventArgs> mouse_up_event_; - Event<NativeMouseWheelEventArgs> mouse_wheel_event_; - Event<NativeKeyEventArgs> key_down_event_; - Event<NativeKeyEventArgs> key_up_event_; -}; -} // namespace details -} // namespace cru::platform::gui::osx |