Move os/ft/gfx libraries to laf

This commit is contained in:
David Capello 2018-08-09 16:36:11 -03:00
parent 5cb2d984f0
commit a6fab8d1d9
143 changed files with 14 additions and 15749 deletions

View File

@ -55,7 +55,6 @@ enable_testing()
# CMakeCache.txt)
option(WITH_WEBP_SUPPORT "Enable support to load/save .webp files" on)
option(WITH_GTK_FILE_DIALOG_SUPPORT "Enable support for the experimental native GTK File Dialog" off)
option(WITH_DESKTOP_INTEGRATION "Enable desktop integration modules" off)
option(WITH_QT_THUMBNAILER "Enable kde5/qt5 thumnailer" off)
@ -92,7 +91,7 @@ else()
endif()
# Check valid gtk + libpng combination
if(WITH_GTK_FILE_DIALOG_SUPPORT)
if(LAF_OS_WITH_GTK)
if(NOT USE_SHARED_LIBPNG)
message(FATAL_ERROR "Cannot compile with gtk and static libpng, set USE_SHARED_LIBPNG=ON")
endif()

View File

@ -8,8 +8,8 @@ function(find_tests dir dependencies)
# Add gtest include directory so we can #include <gtest/gtest.h> in tests source code
include_directories(${CMAKE_SOURCE_DIR}/third_party/gtest/include)
# See if the test is linked with "os-lib" library.
list(FIND dependencies os-lib link_with_os)
# See if the test is linked with "laf-os" library.
list(FIND dependencies laf-os link_with_os)
if(link_with_os)
set(extra_definitions -DLINKED_WITH_OS_LIBRARY)
endif()

2
laf

@ -1 +1 @@
Subproject commit 2068f653224edfbfafc00a40a1d72a8e022d00d8
Subproject commit f2a95de10e51b0dffdc3a14199fa489baf086c22

View File

@ -102,12 +102,9 @@ add_subdirectory(filters)
add_subdirectory(fixmath)
add_subdirectory(flic)
add_subdirectory(gen)
add_subdirectory(gfx)
add_subdirectory(net)
add_subdirectory(render)
add_subdirectory(dio)
add_subdirectory(ft)
add_subdirectory(os)
add_subdirectory(ui)
if(ENABLE_SCRIPTING)
@ -207,7 +204,6 @@ install(DIRECTORY ../data
if(ENABLE_TESTS)
include(FindTests)
find_tests(gfx gfx-lib)
find_tests(doc doc-lib)
find_tests(render render-lib)
find_tests(ui ui-lib)

View File

@ -575,10 +575,11 @@ target_link_libraries(app-lib
filters-lib
fixmath-lib
flic-lib
gfx-lib
laf-gfx
net-lib
render-lib
os-lib
laf-ft
laf-os
ui-lib
undo
${CMARK_LIBRARIES}

View File

@ -12,6 +12,7 @@
#include "app/color_utils.h"
#include "app/modules/palettes.h"
#include "base/debug.h"
#include "doc/image.h"
#include "doc/palette.h"
#include "doc/primitives.h"
@ -80,7 +81,7 @@ Color Color::fromGray(int g, int a)
// static
Color Color::fromIndex(int index)
{
assert(index >= 0);
ASSERT(index >= 0);
Color color(Color::IndexType);
color.m_value.index = index;

View File

@ -70,7 +70,7 @@ add_library(doc-lib
# TODO Remove 'os' as dependency and move conversion_to_surface.cpp/h files
# to other library/layer (render-lib? new conversion-lib?)
target_link_libraries(doc-lib
os-lib
gfx-lib
laf-os
laf-gfx
fixmath-lib
laf-base)

View File

@ -1,11 +0,0 @@
# Aseprite FreeType Wrapper
# Copyright (C) 2017 David Capello
add_library(ft-lib
lib.cpp
stream.cpp)
target_link_libraries(ft-lib
laf-base
${FREETYPE_LIBRARIES}
${HARFBUZZ_LIBRARIES})

View File

@ -1,20 +0,0 @@
Copyright (c) 2016-2017 David Capello
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,4 +0,0 @@
# Aseprite FreeType Wrapper
*Copyright (C) 2016-2017 David Capello*
> Distributed under [MIT license](LICENSE.txt)

View File

@ -1,175 +0,0 @@
// Aseprite FreeType Wrapper
// Copyright (c) 2016-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef FT_ALGORITHM_H_INCLUDED
#define FT_ALGORITHM_H_INCLUDED
#pragma once
#include "base/string.h"
#include "ft/freetype_headers.h"
#include "ft/hb_shaper.h"
#include "gfx/rect.h"
namespace ft {
template<typename FaceFT>
class DefaultShaper {
public:
typedef typename FaceFT::Glyph Glyph;
DefaultShaper(FaceFT& face) : m_face(face) {
}
bool initialize(const base::utf8_const_iterator& it,
const base::utf8_const_iterator& end) {
m_begin = m_it = it;
m_end = end;
return (m_it != end);
}
bool nextChar() {
++m_it;
return (m_it != m_end);
}
int unicodeChar() const {
return *m_it;
}
int charIndex() {
return m_it - m_begin;
}
unsigned int glyphIndex() {
return m_face.cache().getGlyphIndex(m_face, unicodeChar());
}
void glyphOffsetXY(Glyph* glyph) {
// Do nothing
}
void glyphAdvanceXY(const Glyph* glyph, double& x, double& y) {
x += glyph->ft_glyph->advance.x / double(1 << 16);
y += glyph->ft_glyph->advance.y / double(1 << 16);
}
private:
FaceFT& m_face;
base::utf8_const_iterator m_begin, m_end, m_it;
};
template<typename FaceFT,
typename Shaper = HBShaper<FaceFT> >
class ForEachGlyph {
public:
typedef typename FaceFT::Glyph Glyph;
ForEachGlyph(FaceFT& face)
: m_face(face)
, m_shaper(face)
, m_glyph(nullptr)
, m_useKerning(FT_HAS_KERNING((FT_Face)face) ? true: false)
, m_prevGlyph(0)
, m_x(0.0), m_y(0.0) {
}
~ForEachGlyph() {
unloadGlyph();
}
int unicodeChar() { return m_shaper.unicodeChar(); }
int charIndex() { return m_shaper.charIndex(); }
const Glyph* glyph() const { return m_glyph; }
bool initialize(const base::utf8_const_iterator& it,
const base::utf8_const_iterator& end) {
bool res = m_shaper.initialize(it, end);
if (res)
prepareGlyph();
return res;
}
bool nextChar() {
m_prevGlyph = m_shaper.glyphIndex();
if (m_shaper.nextChar()) {
prepareGlyph();
return true;
}
else
return false;
}
private:
void prepareGlyph() {
FT_UInt glyphIndex = m_shaper.glyphIndex();
double initialX = m_x;
if (m_useKerning && m_prevGlyph && glyphIndex) {
FT_Vector kerning;
FT_Get_Kerning(m_face, m_prevGlyph, glyphIndex,
FT_KERNING_DEFAULT, &kerning);
m_x += kerning.x / 64.0;
}
unloadGlyph();
// Load new glyph
m_glyph = m_face.cache().loadGlyph(m_face, glyphIndex, m_face.antialias());
if (m_glyph) {
m_glyph->bitmap = &FT_BitmapGlyph(m_glyph->ft_glyph)->bitmap;
m_glyph->x = m_x
+ m_glyph->bearingX;
m_glyph->y = m_y
+ m_face.height()
+ m_face.descender() // descender is negative
- m_glyph->bearingY;
m_shaper.glyphOffsetXY(m_glyph);
m_shaper.glyphAdvanceXY(m_glyph, m_x, m_y);
m_glyph->startX = initialX;
m_glyph->endX = m_x;
}
}
void unloadGlyph() {
if (m_glyph) {
m_face.cache().doneGlyph(m_glyph);
m_glyph = nullptr;
}
}
private:
FaceFT& m_face;
Shaper m_shaper;
Glyph* m_glyph;
bool m_useKerning;
FT_UInt m_prevGlyph;
double m_x, m_y;
};
template<typename FaceFT>
gfx::Rect calc_text_bounds(FaceFT& face, const std::string& str) {
gfx::Rect bounds(0, 0, 0, 0);
ForEachGlyph<FaceFT> feg(face);
if (feg.initialize(base::utf8_const_iterator(str.begin()),
base::utf8_const_iterator(str.end()))) {
do {
if (auto glyph = feg.glyph())
bounds |= gfx::Rect(int(glyph->x),
int(glyph->y),
glyph->bitmap->width,
glyph->bitmap->rows);
} while (feg.nextChar());
}
return bounds;
}
} // namespace ft
#endif

View File

@ -1,202 +0,0 @@
// Aseprite FreeType Wrapper
// Copyright (c) 2016-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef FT_FACE_H_INCLUDED
#define FT_FACE_H_INCLUDED
#pragma once
#include "base/debug.h"
#include "base/disable_copying.h"
#include "ft/freetype_headers.h"
#include <map>
namespace ft {
struct Glyph {
FT_UInt glyph_index;
FT_Glyph ft_glyph;
FT_Bitmap* bitmap;
double startX;
double endX;
double bearingX;
double bearingY;
double x;
double y;
};
template<typename Cache>
class FaceFT {
public:
typedef ft::Glyph Glyph;
FaceFT(FT_Face face) : m_face(face) {
}
~FaceFT() {
if (m_face)
FT_Done_Face(m_face);
}
operator FT_Face() { return m_face; }
FT_Face operator->() { return m_face; }
bool isValid() const {
return (m_face != nullptr);
}
bool antialias() const {
return m_antialias;
}
void setAntialias(bool antialias) {
m_antialias = antialias;
m_cache.invalidate();
}
void setSize(int size) {
FT_Set_Pixel_Sizes(m_face, size, size);
m_cache.invalidate();
}
double height() const {
FT_Size_Metrics* metrics = &m_face->size->metrics;
double em_size = 1.0 * m_face->units_per_EM;
double y_scale = metrics->y_ppem / em_size;
return int(m_face->height * y_scale) - 1;
}
double ascender() const {
FT_Size_Metrics* metrics = &m_face->size->metrics;
double em_size = 1.0 * m_face->units_per_EM;
double y_scale = metrics->y_ppem / em_size;
return int(m_face->ascender * y_scale);
}
double descender() const {
FT_Size_Metrics* metrics = &m_face->size->metrics;
double em_size = 1.0 * m_face->units_per_EM;
double y_scale = metrics->y_ppem / em_size;
return int(m_face->descender * y_scale);
}
bool hasCodePoint(int codepoint) const {
if (m_face) {
codepoint = FT_Get_Char_Index(m_face, codepoint);
return (codepoint != 0);
}
else
return false;
}
Cache& cache() { return m_cache; }
protected:
FT_Face m_face;
bool m_antialias;
Cache m_cache;
private:
DISABLE_COPYING(FaceFT);
};
class NoCache {
public:
void invalidate() {
// Do nothing
}
FT_UInt getGlyphIndex(FT_Face face, int charCode) {
return FT_Get_Char_Index(face, charCode);
}
Glyph* loadGlyph(FT_Face face, FT_UInt glyphIndex, bool antialias) {
FT_Error err = FT_Load_Glyph(
face, glyphIndex,
FT_LOAD_RENDER |
(antialias ? FT_LOAD_TARGET_NORMAL:
FT_LOAD_TARGET_MONO));
if (err)
return nullptr;
FT_Glyph ft_glyph;
err = FT_Get_Glyph(face->glyph, &ft_glyph);
if (err)
return nullptr;
if (ft_glyph->format != FT_GLYPH_FORMAT_BITMAP) {
err = FT_Glyph_To_Bitmap(&ft_glyph, FT_RENDER_MODE_NORMAL, 0, 1);
if (!err) {
FT_Done_Glyph(ft_glyph);
return nullptr;
}
}
m_glyph.ft_glyph = ft_glyph;
m_glyph.bearingX = face->glyph->metrics.horiBearingX / 64.0;
m_glyph.bearingY = face->glyph->metrics.horiBearingY / 64.0;
return &m_glyph;
}
void doneGlyph(Glyph* glyph) {
ASSERT(glyph);
FT_Done_Glyph(glyph->ft_glyph);
}
private:
Glyph m_glyph;
};
class SimpleCache : public NoCache {
public:
~SimpleCache() {
invalidate();
}
void invalidate() {
for (auto& it : m_glyphMap) {
FT_Done_Glyph(it.second->ft_glyph);
delete it.second;
}
m_glyphMap.clear();
}
Glyph* loadGlyph(FT_Face face, FT_UInt glyphIndex, bool antialias) {
auto it = m_glyphMap.find(glyphIndex);
if (it != m_glyphMap.end())
return it->second;
Glyph* glyph = NoCache::loadGlyph(face, glyphIndex, antialias);
if (!glyph)
return nullptr;
FT_Glyph new_ft_glyph = nullptr;
FT_Glyph_Copy(glyph->ft_glyph, &new_ft_glyph);
if (!new_ft_glyph)
return nullptr;
Glyph* newGlyph = new Glyph(*glyph);
newGlyph->ft_glyph = new_ft_glyph;
m_glyphMap[glyphIndex] = newGlyph;
FT_Done_Glyph(glyph->ft_glyph);
return newGlyph;
}
void doneGlyph(Glyph* glyph) {
// Do nothing
}
private:
std::map<FT_UInt, Glyph*> m_glyphMap;
};
} // namespace ft
#endif

View File

@ -1,15 +0,0 @@
// Aseprite FreeType Wrapper
// Copyright (c) 2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef FT_FREETYPE_HEADERS_H_INCLUDED
#define FT_FREETYPE_HEADERS_H_INCLUDED
#pragma once
#include <ft2build.h>
#include FT_GLYPH_H
#include FT_FREETYPE_H
#endif

View File

@ -1,44 +0,0 @@
// Aseprite FreeType Wrapper
// Copyright (c) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef FT_HB_FACE_H_INCLUDED
#define FT_HB_FACE_H_INCLUDED
#pragma once
#include "base/string.h"
#include "ft/face.h"
#include <hb.h>
#include <hb-ft.h>
namespace ft {
template<typename FaceFT>
class HBFace : public FaceFT {
public:
HBFace(FT_Face face) : FaceFT(face) {
m_font = (face ? hb_ft_font_create((FT_Face)face, nullptr): nullptr);
m_buffer = (face ? hb_buffer_create(): nullptr);
}
~HBFace() {
if (m_buffer) hb_buffer_destroy(m_buffer);
if (m_font) hb_font_destroy(m_font);
}
hb_font_t* font() const { return m_font; }
hb_buffer_t* buffer() const { return m_buffer; }
private:
hb_buffer_t* m_buffer;
hb_font_t* m_font;
};
typedef HBFace<FaceFT<SimpleCache> > Face;
} // namespace ft
#endif

View File

@ -1,90 +0,0 @@
// Aseprite FreeType Wrapper
// Copyright (c) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef FT_HB_SHAPER_H_INCLUDED
#define FT_HB_SHAPER_H_INCLUDED
#pragma once
#include "ft/hb_face.h"
#include <vector>
namespace ft {
template<typename HBFace>
class HBShaper {
public:
HBShaper(HBFace& face)
: m_face(face)
, m_unicodeFuncs(hb_buffer_get_unicode_funcs(face.buffer())) {
}
bool initialize(const base::utf8_const_iterator& begin,
const base::utf8_const_iterator& end) {
m_index = 0;
if (begin == end)
return false;
hb_buffer_t* buf = m_face.buffer();
hb_buffer_reset(buf);
for (auto it=begin; it!=end; ++it)
hb_buffer_add(buf, *it, it - begin);
// Just in case we're compiling with an old harfbuzz version
#ifdef HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS
hb_buffer_set_cluster_level(buf, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
#endif
hb_buffer_set_content_type(buf, HB_BUFFER_CONTENT_TYPE_UNICODE);
hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
hb_buffer_guess_segment_properties(buf);
hb_shape(m_face.font(), buf, nullptr, 0);
m_glyphInfo = hb_buffer_get_glyph_infos(buf, &m_glyphCount);
m_glyphPos = hb_buffer_get_glyph_positions(buf, &m_glyphCount);
return (m_glyphCount > 0);
}
bool nextChar() {
++m_index;
return (m_index < m_glyphCount);
}
int unicodeChar() const {
return m_glyphInfo[m_index].codepoint;
}
int charIndex() {
return m_glyphInfo[m_index].cluster;
}
unsigned int glyphIndex() const {
return m_glyphInfo[m_index].codepoint;
}
void glyphOffsetXY(Glyph* glyph) {
glyph->x += m_glyphPos[m_index].x_offset / 64.0;
glyph->y += m_glyphPos[m_index].y_offset / 64.0;
}
void glyphAdvanceXY(const Glyph* glyph, double& x, double& y) {
x += m_glyphPos[m_index].x_advance / 64.0;
y += m_glyphPos[m_index].y_advance / 64.0;
}
private:
HBFace& m_face;
hb_glyph_info_t* m_glyphInfo;
hb_glyph_position_t* m_glyphPos;
unsigned int m_glyphCount;
unsigned int m_index;
hb_unicode_funcs_t* m_unicodeFuncs;
};
} // namespace ft
#endif

View File

@ -1,45 +0,0 @@
// Aseprite FreeType Wrapper
// Copyright (c) 2016-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#include "ft/lib.h"
#include "base/log.h"
#include "ft/stream.h"
#include <iostream>
namespace ft {
Lib::Lib()
: m_ft(nullptr)
{
FT_Init_FreeType(&m_ft);
}
Lib::~Lib()
{
if (m_ft)
FT_Done_FreeType(m_ft);
}
FT_Face Lib::open(const std::string& filename)
{
FT_Stream stream = ft::open_stream(filename);
FT_Open_Args args;
memset(&args, 0, sizeof(args));
args.flags = FT_OPEN_STREAM;
args.stream = stream;
LOG(VERBOSE) << "FT: Loading font '" << filename << "'\n";
FT_Face face = nullptr;
FT_Error err = FT_Open_Face(m_ft, &args, 0, &face);
if (!err)
FT_Select_Charmap(face, FT_ENCODING_UNICODE);
return face;
}
} // namespace ft

View File

@ -1,35 +0,0 @@
// Aseprite FreeType Wrapper
// Copyright (c) 2016-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef FT_LIB_H_INCLUDED
#define FT_LIB_H_INCLUDED
#pragma once
#include "base/disable_copying.h"
#include "ft/freetype_headers.h"
#include <string>
namespace ft {
class Lib {
public:
Lib();
~Lib();
operator FT_Library() { return m_ft; }
FT_Face open(const std::string& filename);
private:
FT_Library m_ft;
DISABLE_COPYING(Lib);
};
} // namespace ft
#endif

View File

@ -1,75 +0,0 @@
// Aseprite FreeType Wrapper
// Copyright (c) 2016-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#include "ft/stream.h"
#include "base/file_handle.h"
#include <ft2build.h>
#define STREAM_FILE(stream) ((FILE*)stream->descriptor.pointer)
namespace ft {
static void ft_stream_close(FT_Stream stream)
{
fclose(STREAM_FILE(stream));
free(stream);
}
static unsigned long ft_stream_io(FT_Stream stream,
unsigned long offset,
unsigned char* buffer,
unsigned long count)
{
if (!count && offset > stream->size)
return 1;
FILE* file = STREAM_FILE(stream);
if (stream->pos != offset)
fseek(file, (long)offset, SEEK_SET);
return (unsigned long)fread(buffer, 1, count, file);
}
FT_Stream open_stream(const std::string& utf8Filename)
{
FT_Stream stream = nullptr;
stream = (FT_Stream)malloc(sizeof(*stream));
if(!stream)
return nullptr;
memset(stream, 0, sizeof(*stream));
TRACE("FT: Loading font %s... ", utf8Filename.c_str());
FILE* file = base::open_file_raw(utf8Filename, "rb");
if (!file) {
free(stream);
TRACE("FAIL\n");
return nullptr;
}
fseek(file, 0, SEEK_END);
stream->size = (unsigned long)ftell(file);
if (!stream->size) {
fclose(file);
free(stream);
TRACE("FAIL\n");
return nullptr;
}
fseek(file, 0, SEEK_SET);
stream->descriptor.pointer = file;
stream->base = nullptr;
stream->pos = 0;
stream->read = ft_stream_io;
stream->close = ft_stream_close;
TRACE("OK\n");
return stream;
}
} // namespace ft

View File

@ -1,21 +0,0 @@
// Aseprite FreeType Wrapper
// Copyright (c) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef FT_STREAM_H_INCLUDED
#define FT_STREAM_H_INCLUDED
#pragma once
#include "ft/freetype_headers.h"
#include <string>
namespace ft {
FT_Stream open_stream(const std::string& utf8Filename);
} // namespace ft
#endif

View File

@ -1,13 +0,0 @@
# Aseprite
# Copyright (C) 2001-2017 David Capello
add_library(gfx-lib
hsl.cpp
hsv.cpp
packing_rects.cpp
region.cpp
rgb.cpp)
target_link_libraries(gfx-lib
laf-base
${PIXMAN_LIBRARY})

View File

@ -1,20 +0,0 @@
Copyright (c) 2001-2016 David Capello
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,6 +0,0 @@
# Aseprite Gfx Library
*Copyright (C) 2001-2016 David Capello*
> Distributed under [MIT license](LICENSE.txt)
The `gfx::Region` class depends on pixman library.

View File

@ -1,205 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2013, 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef GFX_BORDER_H_INCLUDED
#define GFX_BORDER_H_INCLUDED
#pragma once
namespace gfx {
template<typename T>
class SizeT;
template<typename T>
class BorderT
{
public:
BorderT() :
m_left(0),
m_top(0),
m_right(0),
m_bottom(0) {
}
BorderT(const T& left, const T& top, const T& right, const T& bottom) :
m_left(left),
m_top(top),
m_right(right),
m_bottom(bottom) {
}
explicit BorderT(const T& allSides) :
m_left(allSides),
m_top(allSides),
m_right(allSides),
m_bottom(allSides) {
}
T left() const { return m_left; };
T top() const { return m_top; };
T right() const { return m_right; };
T bottom() const { return m_bottom; };
T width() const { return m_left + m_right; };
T height() const { return m_top + m_bottom; };
void left(const T& left) { m_left = left; }
void top(const T& top) { m_top = top; }
void right(const T& right) { m_right = right; }
void bottom(const T& bottom) { m_bottom = bottom; }
SizeT<T> size() const {
return SizeT<T>(m_left + m_right, m_top + m_bottom);
}
const BorderT& operator+=(const BorderT& br) {
m_left += br.m_left;
m_top += br.m_top;
m_right += br.m_right;
m_bottom += br.m_bottom;
return *this;
}
const BorderT& operator-=(const BorderT& br) {
m_left -= br.m_left;
m_top -= br.m_top;
m_right -= br.m_right;
m_bottom -= br.m_bottom;
return *this;
}
const BorderT& operator*=(const BorderT& br) {
m_left *= br.m_left;
m_top *= br.m_top;
m_right *= br.m_right;
m_bottom *= br.m_bottom;
return *this;
}
const BorderT& operator/=(const BorderT& br) {
m_left /= br.m_left;
m_top /= br.m_top;
m_right /= br.m_right;
m_bottom /= br.m_bottom;
return *this;
}
const BorderT& operator+=(const T& value) {
m_left += value;
m_top += value;
m_right += value;
m_bottom += value;
return *this;
}
const BorderT& operator-=(const T& value) {
m_left -= value;
m_top -= value;
m_right -= value;
m_bottom -= value;
return *this;
}
const BorderT& operator*=(const T& value) {
m_left *= value;
m_top *= value;
m_right *= value;
m_bottom *= value;
return *this;
}
const BorderT& operator/=(const T& value) {
m_left /= value;
m_top /= value;
m_right /= value;
m_bottom /= value;
return *this;
}
BorderT operator+(const BorderT& br) const {
return BorderT(m_left + br.left(),
m_top + br.top(),
m_right + br.right(),
m_bottom + br.bottom());
}
BorderT operator-(const BorderT& br) const {
return BorderT(m_left - br.left(),
m_top - br.top(),
m_right - br.right(),
m_bottom - br.bottom());
}
BorderT operator*(const BorderT& br) const {
return BorderT(m_left * br.left(),
m_top * br.top(),
m_right * br.right(),
m_bottom * br.bottom());
}
BorderT operator/(const BorderT& br) const {
return BorderT(m_left / br.left(),
m_top / br.top(),
m_right / br.right(),
m_bottom / br.bottom());
}
BorderT operator+(const T& value) const {
return BorderT(m_left + value,
m_top + value,
m_right + value,
m_bottom + value);
}
BorderT operator-(const T& value) const {
return BorderT(m_left - value,
m_top - value,
m_right - value,
m_bottom - value);
}
BorderT operator*(const T& value) const {
return BorderT(m_left * value,
m_top * value,
m_right * value,
m_bottom * value);
}
BorderT operator/(const T& value) const {
return BorderT(m_left / value,
m_top / value,
m_right / value,
m_bottom / value);
}
BorderT operator-() const {
return BorderT(-m_left, -m_top, -m_right, -m_bottom);
}
bool operator==(const BorderT& br) const {
return
m_left == br.m_left && m_top == br.m_top &&
m_right == br.m_right && m_bottom == br.m_bottom;
}
bool operator!=(const BorderT& br) const {
return
m_left != br.m_left || m_top != br.m_top ||
m_right != br.m_right || m_bottom != br.m_bottom;
}
private:
T m_left;
T m_top;
T m_right;
T m_bottom;
};
typedef BorderT<int> Border;
} // namespace gfx
#endif

View File

@ -1,138 +0,0 @@
// Aseprite Gfx Library
// Copyright (c) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef GFX_CLIP_H_INCLUDED
#define GFX_CLIP_H_INCLUDED
#pragma once
#include "gfx/point.h"
#include "gfx/rect.h"
#include "gfx/size.h"
namespace gfx {
template<typename T>
class ClipT {
public:
PointT<T> dst;
PointT<T> src;
SizeT<T> size;
ClipT()
: dst(0, 0)
, src(0, 0)
, size(0, 0) {
}
ClipT(T w, T h)
: dst(0, 0)
, src(0, 0)
, size(w, h) {
}
ClipT(T dst_x, T dst_y, T src_x, T src_y, T w, T h)
: dst(dst_x, dst_y)
, src(src_x, src_y)
, size(w, h) {
}
ClipT(T dst_x, T dst_y, const RectT<T>& srcBounds)
: dst(dst_x, dst_y)
, src(srcBounds.x, srcBounds.y)
, size(srcBounds.w, srcBounds.h) {
}
ClipT(const PointT<T>& dst, const PointT<T>& src, const SizeT<T>& size)
: dst(dst)
, src(src)
, size(size) {
}
ClipT(const PointT<T>& dst, const RectT<T>& srcBounds)
: dst(dst)
, src(srcBounds.x, srcBounds.y)
, size(srcBounds.w, srcBounds.h) {
}
ClipT(const RectT<T>& bounds)
: dst(bounds.x, bounds.y)
, src(bounds.x, bounds.y)
, size(bounds.w, bounds.h) {
}
template<typename T2>
ClipT(const ClipT<T2>& other)
: dst(other.dst)
, src(other.src)
, size(other.size) {
}
RectT<T> dstBounds() const { return RectT<T>(dst, size); }
RectT<T> srcBounds() const { return RectT<T>(src, size); }
bool operator==(const ClipT<T>& other) const {
return (dst == other.dst &&
src == other.src &&
size == other.size);
}
bool clip(
// Available area
T avail_dst_w,
T avail_dst_h,
T avail_src_w,
T avail_src_h) {
// Clip srcBounds
if (src.x < T(0)) {
size.w += src.x;
dst.x -= src.x;
src.x = T(0);
}
if (src.y < T(0)) {
size.h += src.y;
dst.y -= src.y;
src.y = T(0);
}
if (src.x + size.w > avail_src_w)
size.w -= src.x + size.w - avail_src_w;
if (src.y + size.h > avail_src_h)
size.h -= src.y + size.h - avail_src_h;
// Clip dstBounds
if (dst.x < T(0)) {
size.w += dst.x;
src.x -= dst.x;
dst.x = T(0);
}
if (dst.y < T(0)) {
size.h += dst.y;
src.y -= dst.y;
dst.y = T(0);
}
if (dst.x + size.w > avail_dst_w)
size.w -= dst.x + size.w - avail_dst_w;
if (dst.y + size.h > avail_dst_h)
size.h -= dst.y + size.h - avail_dst_h;
return (size.w > T(0) && size.h > T(0));
}
};
typedef ClipT<int> Clip;
typedef ClipT<double> ClipF;
} // namespace gfx
#endif

View File

@ -1,104 +0,0 @@
// Aseprite Document Library
// Copyright (c) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gtest/gtest.h>
#include "gfx/clip.h"
using namespace gfx;
namespace gfx {
inline std::ostream& operator<<(std::ostream& os, const Clip& area)
{
return os << "("
<< area.dst.x << ", "
<< area.dst.y << ", "
<< area.src.x << ", "
<< area.src.y << ", "
<< area.size.w << ", "
<< area.size.h << ")";
}
}
TEST(ScaledClip, WithoutClip)
{
Clip area;
area = Clip(0, 0, 0, 0, 16, 16);
EXPECT_TRUE(area.clip(16, 16, 16, 16));
EXPECT_EQ(Clip(0, 0, 0, 0, 16, 16), area);
area = Clip(2, 2, 0, 0, 16, 16);
EXPECT_TRUE(area.clip(32, 32, 16, 16));
EXPECT_EQ(Clip(2, 2, 0, 0, 16, 16), area);
}
TEST(ScaledClip, FullyClipped)
{
Clip area;
area = Clip(32, 32, 0, 0, 16, 16);
EXPECT_FALSE(area.clip(32, 32, 16, 16));
area = Clip(-16, -16, 0, 0, 16, 16);
EXPECT_FALSE(area.clip(32, 32, 16, 16));
area = Clip(0, 0, 16, 16, 16, 16);
EXPECT_FALSE(area.clip(32, 32, 16, 16));
}
TEST(ScaledClip, WithoutZoomWithClip)
{
Clip area;
area = Clip(2, 3, 1, -1, 4, 3);
EXPECT_TRUE(area.clip(30, 29, 16, 16));
EXPECT_EQ(Clip(2, 4, 1, 0, 4, 2), area);
area = Clip(0, 0, -1, -4, 8, 5);
EXPECT_TRUE(area.clip(3, 32, 8, 8));
EXPECT_EQ(Clip(1, 4, 0, 0, 2, 1), area);
}
TEST(ScaledClip, Zoom)
{
Clip area;
area = Clip(0, 0, 0, 0, 32, 32);
EXPECT_TRUE(area.clip(32, 32, 16, 16));
EXPECT_EQ(Clip(0, 0, 0, 0, 16, 16), area);
area = Clip(0, 0, 1, 2, 32, 32);
EXPECT_TRUE(area.clip(32, 32, 32, 32));
EXPECT_EQ(Clip(0, 0, 1, 2, 31, 30), area);
// X:
// -1 0 1 2 3 4 5
// [ ]
// a[a a b] b c c c DST
// a a[a b b]b c c c SRC
//
// Y:
// -1 0 1 2 3
// [ ]
// a[a a]b b b DST
// [a a]a b b b c c SRC
area = Clip(-1, 1, 1, -1, 4, 4);
EXPECT_TRUE(area.clip(6, 4, 9, 9));
EXPECT_EQ(Clip(0, 2, 2, 0, 3, 2), area);
}
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,41 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef GFX_COLOR_H_INCLUDED
#define GFX_COLOR_H_INCLUDED
#pragma once
#include "base/ints.h"
namespace gfx {
typedef uint32_t Color;
typedef uint8_t ColorComponent;
static const int ColorRShift = 0;
static const int ColorGShift = 8;
static const int ColorBShift = 16;
static const int ColorAShift = 24;
static const Color ColorNone = Color(0);
inline Color rgba(ColorComponent r, ColorComponent g, ColorComponent b, ColorComponent a = 255) {
return Color((r << ColorRShift) |
(g << ColorGShift) |
(b << ColorBShift) |
(a << ColorAShift));
}
inline ColorComponent getr(Color c) { return (c >> ColorRShift) & 0xff; }
inline ColorComponent getg(Color c) { return (c >> ColorGShift) & 0xff; }
inline ColorComponent getb(Color c) { return (c >> ColorBShift) & 0xff; }
inline ColorComponent geta(Color c) { return (c >> ColorAShift) & 0xff; }
inline bool is_transparent(Color c) { return geta(c) == 0; }
} // namespace gfx
#endif // GFX_COLOR_H_INCLUDED

View File

@ -1,29 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef GFX_FWD_H_INCLUDED
#define GFX_FWD_H_INCLUDED
#pragma once
namespace gfx {
template<typename T> class BorderT;
template<typename T> class ClipT;
template<typename T> class PointT;
template<typename T> class RectT;
template<typename T> class SizeT;
typedef BorderT<int> Border;
typedef ClipT<int> Clip;
typedef PointT<int> Point;
typedef RectT<int> Rect;
typedef SizeT<int> Size;
class Region;
} // namespace gfx
#endif

View File

@ -1,88 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gfx/hsl.h"
#include "gfx/rgb.h"
#include <cmath>
namespace gfx {
using namespace std;
Hsl::Hsl(double hue, double saturation, double lightness)
: m_hue(hue)
, m_saturation(MID(0.0, saturation, 1.0))
, m_lightness(MID(0.0, lightness, 1.0))
{
while (m_hue < 0.0)
m_hue += 360.0;
m_hue = std::fmod(m_hue, 360.0);
}
Hsl::Hsl(const Rgb& rgb)
{
int M = rgb.maxComponent();
int m = rgb.minComponent();
int c = M - m;
double chroma = double(c) / 255.0;
double hue_prime = 0.0;
double h, s, l;
double r, g, b;
l = double((M + m) / 255.0) / 2.0;
if (c == 0) {
h = 0.0; // Undefined Hue because max == min
s = 0.0;
}
else {
r = double(rgb.red()) / 255.0;
g = double(rgb.green()) / 255.0;
b = double(rgb.blue()) / 255.0;
s = chroma / (1-std::fabs(2.0*l-1.0));
if (M == rgb.red()) {
hue_prime = (g - b) / chroma;
while (hue_prime < 0.0)
hue_prime += 6.0;
hue_prime = std::fmod(hue_prime, 6.0);
}
else if (M == rgb.green()) {
hue_prime = ((b - r) / chroma) + 2.0;
}
else if (M == rgb.blue()) {
hue_prime = ((r - g) / chroma) + 4.0;
}
h = hue_prime * 60.0;
}
m_hue = h;
m_saturation = s;
m_lightness = l;
}
int Hsl::hueInt() const
{
return int(std::floor(m_hue + 0.5));
}
int Hsl::saturationInt() const
{
return int(std::floor(m_saturation*100.0 + 0.5));
}
int Hsl::lightnessInt() const
{
return int(std::floor(m_lightness*100.0 + 0.5));
}
} // namespace gfx

View File

@ -1,81 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef GFX_HSL_H_INCLUDED
#define GFX_HSL_H_INCLUDED
#pragma once
#include "base/base.h" // MID
namespace gfx {
class Rgb;
class Hsl {
public:
Hsl()
: m_hue(0.0)
, m_saturation(0.0)
, m_lightness(0.0)
{ }
Hsl(double hue, double saturation, double lightness);
Hsl(const Hsl& hsl)
: m_hue(hsl.hue())
, m_saturation(hsl.saturation())
, m_lightness(hsl.lightness())
{ }
// RGB to HSL conversion
explicit Hsl(const Rgb& rgb);
// Returns color's hue, a value from 0 to 360
double hue() const { return m_hue; }
// Returns color's saturation, a value from 0 to 100
double saturation() const { return m_saturation; }
// Returns color's lightness, a value from 0 to 100
double lightness() const { return m_lightness; }
// Integer getters, hue=[0,360), saturation=[0,100], value=[0,100]
int hueInt() const;
int saturationInt() const;
int lightnessInt() const;
void hue(double hue) {
m_hue = MID(0.0, hue, 360.0);
}
void saturation(double saturation) {
m_saturation = MID(0.0, saturation, 1.0);
}
void lightness(double lightness) {
m_lightness = MID(0.0, lightness, 1.0);
}
// The comparison is done through the integer value of each component.
bool operator==(const Hsl& other) const {
return (hueInt() == other.hueInt() &&
saturationInt() == other.saturationInt() &&
lightnessInt() == other.lightnessInt());
}
bool operator!=(const Hsl& other) const {
return !operator==(other);
}
private:
double m_hue;
double m_saturation;
double m_lightness;
};
} // namespace gfx
#endif

View File

@ -1,89 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gfx/hsv.h"
#include "gfx/rgb.h"
#include <cmath>
namespace gfx {
using namespace std;
Hsv::Hsv(double hue, double saturation, double value)
: m_hue(hue)
, m_saturation(MID(0.0, saturation, 1.0))
, m_value(MID(0.0, value, 1.0))
{
while (m_hue < 0.0)
m_hue += 360.0;
m_hue = std::fmod(m_hue, 360.0);
}
// Reference: http://en.wikipedia.org/wiki/HSL_and_HSV
Hsv::Hsv(const Rgb& rgb)
{
int M = rgb.maxComponent();
int m = rgb.minComponent();
int c = M - m;
double chroma = double(c) / 255.0;
double hue_prime = 0.0;
double h, s, v;
double r, g, b;
v = double(M) / 255.0;
if (c == 0) {
h = 0.0; // Undefined Hue because max == min
s = 0.0;
}
else {
r = double(rgb.red()) / 255.0;
g = double(rgb.green()) / 255.0;
b = double(rgb.blue()) / 255.0;
s = chroma / v;
if (M == rgb.red()) {
hue_prime = (g - b) / chroma;
while (hue_prime < 0.0)
hue_prime += 6.0;
hue_prime = std::fmod(hue_prime, 6.0);
}
else if (M == rgb.green()) {
hue_prime = ((b - r) / chroma) + 2.0;
}
else if (M == rgb.blue()) {
hue_prime = ((r - g) / chroma) + 4.0;
}
h = hue_prime * 60.0;
}
m_hue = h;
m_saturation = s;
m_value = v;
}
int Hsv::hueInt() const
{
return int(std::floor(m_hue + 0.5));
}
int Hsv::saturationInt() const
{
return int(std::floor(m_saturation*100.0 + 0.5));
}
int Hsv::valueInt() const
{
return int(std::floor(m_value*100.0 + 0.5));
}
} // namespace gfx

View File

@ -1,81 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef GFX_HSV_H_INCLUDED
#define GFX_HSV_H_INCLUDED
#pragma once
#include "base/base.h" // MID
namespace gfx {
class Rgb;
class Hsv {
public:
Hsv()
: m_hue(0.0)
, m_saturation(0.0)
, m_value(0.0)
{ }
Hsv(double hue, double saturation, double value);
Hsv(const Hsv& hsv)
: m_hue(hsv.hue())
, m_saturation(hsv.saturation())
, m_value(hsv.value())
{ }
// RGB to HSV conversion
explicit Hsv(const Rgb& rgb);
// Returns color's hue, a value from 0 to 360
double hue() const { return m_hue; }
// Returns color's saturation, a value from 0 to 100
double saturation() const { return m_saturation; }
// Returns color's brightness, a value from 0 to 100
double value() const { return m_value; }
// Integer getters, hue=[0,360), saturation=[0,100], value=[0,100]
int hueInt() const;
int saturationInt() const;
int valueInt() const;
void hue(double hue) {
m_hue = MID(0.0, hue, 360.0);
}
void saturation(double saturation) {
m_saturation = MID(0.0, saturation, 1.0);
}
void value(double value) {
m_value = MID(0.0, value, 1.0);
}
// The comparison is done through the integer value of each component.
bool operator==(const Hsv& other) const {
return (hueInt() == other.hueInt() &&
saturationInt() == other.saturationInt() &&
valueInt() == other.valueInt());
}
bool operator!=(const Hsv& other) const {
return !operator==(other);
}
private:
double m_hue;
double m_saturation;
double m_value;
};
} // namespace gfx
#endif

View File

@ -1,66 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2013 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gtest/gtest.h>
#include "gfx/hsv.h"
#include "gfx/rgb.h"
using namespace gfx;
using namespace std;
namespace gfx {
ostream& operator<<(ostream& os, const Hsv& hsv)
{
return os << "("
<< hsv.hueInt() << ", "
<< hsv.saturationInt() << ", "
<< hsv.valueInt() << "); real: ("
<< hsv.hue() << ", "
<< hsv.saturation() << ", "
<< hsv.value() << ")";
}
}
TEST(Hsv, Ctor)
{
EXPECT_EQ(35.0, Hsv(35.0, 0.50, 0.75).hue());
EXPECT_EQ(0.50, Hsv(35.0, 0.50, 0.75).saturation());
EXPECT_EQ(0.75, Hsv(35.0, 0.50, 0.75).value());
EXPECT_EQ(35, Hsv(35.0, 0.50, 0.75).hueInt());
EXPECT_EQ(50, Hsv(35.0, 0.50, 0.75).saturationInt());
EXPECT_EQ(75, Hsv(35.0, 0.50, 0.75).valueInt());
EXPECT_EQ(Hsv(0, 0, 0), Hsv());
}
TEST(Hsv, FromRgb)
{
EXPECT_EQ(Hsv( 0.0, 0.00, 0.00), Hsv(Rgb( 0, 0, 0)));
EXPECT_EQ(Hsv( 0.0, 1.00, 0.01), Hsv(Rgb( 3, 0, 0)));
EXPECT_EQ(Hsv( 0.0, 1.00, 0.99), Hsv(Rgb(252, 0, 0)));
EXPECT_EQ(Hsv( 0.0, 1.00, 1.00), Hsv(Rgb(255, 0, 0)));
EXPECT_EQ(Hsv( 60.0, 1.00, 0.75), Hsv(Rgb(191, 191, 0)));
EXPECT_EQ(Hsv(120.0, 1.00, 0.50), Hsv(Rgb( 0, 128, 0)));
EXPECT_EQ(Hsv(120.0, 1.00, 1.00), Hsv(Rgb( 0, 255, 0)));
EXPECT_EQ(Hsv(180.0, 0.50, 1.00), Hsv(Rgb(128, 255, 255)));
EXPECT_EQ(Hsv(240.0, 0.50, 1.00), Hsv(Rgb(128, 128, 255)));
EXPECT_EQ(Hsv(240.0, 1.00, 1.00), Hsv(Rgb( 0, 0, 255)));
EXPECT_EQ(Hsv(300.0, 0.66, 0.75), Hsv(Rgb(191, 64, 191)));
EXPECT_EQ(Hsv(360.0, 1.00, 0.99), Hsv(Rgb(252, 0, 0)));
EXPECT_EQ(Hsv(360.0, 1.00, 1.00), Hsv(Rgb(255, 0, 0)));
}
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,98 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2014 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gfx/packing_rects.h"
#include "gfx/region.h"
#include "gfx/size.h"
namespace gfx {
void PackingRects::add(const Size& sz)
{
m_rects.push_back(Rect(sz));
}
void PackingRects::add(const Rect& rc)
{
m_rects.push_back(rc);
}
Size PackingRects::bestFit()
{
Size size(0, 0);
// Calculate the amount of pixels that we need, the texture cannot
// be smaller than that.
int neededArea = 0;
for (const auto& rc : m_rects) {
neededArea += rc.w * rc.h;
}
int w = 1;
int h = 1;
int z = 0;
bool fit = false;
while (true) {
if (w*h >= neededArea) {
fit = pack(Size(w, h));
if (fit) {
size = Size(w, h);
break;
}
}
if ((++z) & 1)
w *= 2;
else
h *= 2;
}
return size;
}
static bool by_area(const Rect* a, const Rect* b) {
return a->w*a->h > b->w*b->h;
}
bool PackingRects::pack(const Size& size)
{
m_bounds = Rect(size);
// We cannot sort m_rects because we want to
std::vector<Rect*> rectPtrs(m_rects.size());
int i = 0;
for (auto& rc : m_rects)
rectPtrs[i++] = &rc;
std::sort(rectPtrs.begin(), rectPtrs.end(), by_area);
gfx::Region rgn(m_bounds);
for (auto rcPtr : rectPtrs) {
gfx::Rect& rc = *rcPtr;
for (int v=0; v<=m_bounds.h-rc.h; ++v) {
for (int u=0; u<=m_bounds.w-rc.w; ++u) {
gfx::Rect possible(u, v, rc.w, rc.h);
Region::Overlap overlap = rgn.contains(possible);
if (overlap == Region::In) {
rc = possible;
rgn.createSubtraction(rgn, gfx::Region(rc));
goto next_rc;
}
}
}
return false; // There is not enough room for "rc"
next_rc:;
}
return true;
}
} // namespace gfx

View File

@ -1,53 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef GFX_TEXTURE_SIZE_H_INCLUDED
#define GFX_TEXTURE_SIZE_H_INCLUDED
#pragma once
#include "gfx/fwd.h"
#include "gfx/rect.h"
#include <vector>
namespace gfx {
// TODO add support for rotations
class PackingRects {
public:
typedef std::vector<Rect> Rects;
typedef Rects::const_iterator const_iterator;
// Iterate over all given rectangles (in the same order they where
// given in addSize() calls).
const_iterator begin() const { return m_rects.begin(); }
const_iterator end() const { return m_rects.end(); }
std::size_t size() const { return m_rects.size(); }
const Rect& operator[](int i) const { return m_rects[i]; }
// Adds a new rectangle.
void add(const Size& sz);
void add(const Rect& rc);
// Returns the best size for the texture.
Size bestFit();
// Rearrange all given rectangles to best fit a texture size.
// Returns true if all rectangles were correctly arranged or false
// if there is not enough space.
bool pack(const Size& size);
// Returns the bounds of the packed area.
const Rect& bounds() const { return m_bounds; }
private:
Rect m_bounds;
Rects m_rects;
};
} // namespace gfx
#endif

View File

@ -1,100 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2014 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gtest/gtest.h>
#include "gfx/packing_rects.h"
#include "gfx/rect_io.h"
#include "gfx/size.h"
using namespace gfx;
TEST(PackingRects, Simple)
{
PackingRects pr;
pr.add(Size(256, 128));
EXPECT_FALSE(pr.pack(Size(256, 120)));
EXPECT_TRUE(pr.pack(Size(256, 128)));
EXPECT_EQ(Rect(0, 0, 256, 128), pr[0]);
EXPECT_EQ(Rect(0, 0, 256, 128), pr.bounds());
}
TEST(PackingRects, SimpleTwoRects)
{
PackingRects pr;
pr.add(Size(256, 128));
pr.add(Size(256, 120));
EXPECT_TRUE(pr.pack(Size(256, 256)));
EXPECT_EQ(Rect(0, 0, 256, 256), pr.bounds());
EXPECT_EQ(Rect(0, 0, 256, 128), pr[0]);
EXPECT_EQ(Rect(0, 128, 256, 120), pr[1]);
}
TEST(PackingRects, BestFit)
{
PackingRects pr;
pr.add(Size(10, 12));
pr.bestFit();
EXPECT_EQ(Rect(0, 0, 16, 16), pr.bounds());
}
TEST(PackingRects, BestFitTwoRects)
{
PackingRects pr;
pr.add(Size(256, 128));
pr.add(Size(256, 127));
pr.bestFit();
EXPECT_EQ(Rect(0, 0, 256, 256), pr.bounds());
EXPECT_EQ(Rect(0, 0, 256, 128), pr[0]);
EXPECT_EQ(Rect(0, 128, 256, 127), pr[1]);
}
TEST(PackingRects, BestFit6Frames100x100)
{
PackingRects pr;
pr.add(Size(100, 100));
pr.add(Size(100, 100));
pr.add(Size(100, 100));
pr.add(Size(100, 100));
pr.add(Size(100, 100));
pr.add(Size(100, 100));
pr.bestFit();
EXPECT_EQ(Rect(0, 0, 512, 256), pr.bounds());
EXPECT_EQ(Rect(0, 0, 100, 100), pr[0]);
EXPECT_EQ(Rect(100, 0, 100, 100), pr[1]);
EXPECT_EQ(Rect(200, 0, 100, 100), pr[2]);
EXPECT_EQ(Rect(300, 0, 100, 100), pr[3]);
EXPECT_EQ(Rect(400, 0, 100, 100), pr[4]);
EXPECT_EQ(Rect(0, 100, 100, 100), pr[5]);
}
TEST(PackingRects, KeepSameRectsOrder)
{
PackingRects pr;
pr.add(Size(10, 10));
pr.add(Size(20, 20));
pr.add(Size(30, 30));
pr.bestFit();
EXPECT_EQ(Rect(0, 0, 64, 32), pr.bounds());
EXPECT_EQ(Rect(50, 0, 10, 10), pr[0]);
EXPECT_EQ(Rect(30, 0, 20, 20), pr[1]);
EXPECT_EQ(Rect(0, 0, 30, 30), pr[2]);
}
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,125 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef GFX_POINT_H_INCLUDED
#define GFX_POINT_H_INCLUDED
#pragma once
namespace gfx {
template<typename T>
class SizeT;
// A 2D coordinate in the screen.
template<typename T>
class PointT
{
public:
T x, y;
PointT() : x(0), y(0) {
}
PointT(const T& x, const T& y) : x(x), y(y) {
}
PointT(const PointT& point) : x(point.x), y(point.y) {
}
template<typename T2>
explicit PointT(const PointT<T2>& point) : x(static_cast<T>(point.x)),
y(static_cast<T>(point.y)) {
}
explicit PointT(const SizeT<T>& size) : x(size.w), y(size.h) {
}
const PointT& operator=(const PointT& pt) {
x = pt.x;
y = pt.y;
return *this;
}
const PointT& operator+=(const PointT& pt) {
x += pt.x;
y += pt.y;
return *this;
}
const PointT& operator-=(const PointT& pt) {
x -= pt.x;
y -= pt.y;
return *this;
}
const PointT& operator+=(const T& value) {
x += value;
y += value;
return *this;
}
const PointT& operator-=(const T& value) {
x -= value;
y -= value;
return *this;
}
const PointT& operator*=(const T& value) {
x *= value;
y *= value;
return *this;
}
const PointT& operator/=(const T& value) {
x /= value;
y /= value;
return *this;
}
PointT operator+(const PointT& pt) const {
return PointT(x+pt.x, y+pt.y);
}
PointT operator-(const PointT& pt) const {
return PointT(x-pt.x, y-pt.y);
}
PointT operator+(const T& value) const {
return PointT(x+value, y+value);
}
PointT operator-(const T& value) const {
return PointT(x-value, y-value);
}
PointT operator*(const T& value) const {
return PointT(x*value, y*value);
}
PointT operator/(const T& value) const {
return PointT(x/value, y/value);
}
PointT operator-() const {
return PointT(-x, -y);
}
bool operator==(const PointT& pt) const {
return x == pt.x && y == pt.y;
}
bool operator!=(const PointT& pt) const {
return x != pt.x || y != pt.y;
}
};
typedef PointT<int> Point;
typedef PointT<double> PointF;
} // namespace gfx
#endif

View File

@ -1,365 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef GFX_RECT_H_INCLUDED
#define GFX_RECT_H_INCLUDED
#pragma once
namespace gfx {
template<typename T> class PointT;
template<typename T> class SizeT;
template<typename T> class BorderT;
// A rectangle.
template<typename T>
class RectT
{
public:
T x, y, w, h;
T x2() const { return x+w; }
T y2() const { return y+h; }
// Creates a new empty rectangle with the origin in 0,0.
RectT() : x(0), y(0), w(0), h(0) {
}
// Creates a new rectangle with the specified size with the origin in 0,0.
RectT(const T& w, const T& h) :
x(0), y(0),
w(w), h(h) {
}
// Creates a new rectangle with the specified size with the origin in 0,0.
explicit RectT(const SizeT<T>& size) :
x(0), y(0),
w(size.w), h(size.h) {
}
RectT(const RectT<T>& rect) :
x(rect.x), y(rect.y),
w(rect.w), h(rect.h) {
}
template<typename T2>
RectT(const RectT<T2>& rect) :
x(static_cast<T>(rect.x)), y(static_cast<T>(rect.y)),
w(static_cast<T>(rect.w)), h(static_cast<T>(rect.h)) {
}
RectT(const PointT<T>& point, const SizeT<T>& size) :
x(point.x), y(point.y),
w(size.w), h(size.h) {
}
// Creates a new rectangle with the origin in point1 and size
// equal to point2-point1.
//
// If a coordinate of point1 is greater than point2, the coordinates
// are swapped. The resulting rectangle will be:
//
// x = min(point1.x, point2.x)
// y = min(point1.y, point2.y)
// w = max(point1.x, point2.x) - x
// h = max(point1.x, point2.x) - y
//
// See that point2 isn't included in the rectangle, it's like the
// point returned by point2() member function.
RectT(const PointT<T>& point1, const PointT<T>& point2) {
PointT<T> leftTop = point1;
PointT<T> rightBottom = point2;
T t;
if (leftTop.x > rightBottom.x) {
t = leftTop.x;
leftTop.x = rightBottom.x;
rightBottom.x = t;
}
if (leftTop.y > rightBottom.y) {
t = leftTop.y;
leftTop.y = rightBottom.y;
rightBottom.y = t;
}
this->x = leftTop.x;
this->y = leftTop.y;
this->w = rightBottom.x - leftTop.x;
this->h = rightBottom.y - leftTop.y;
}
RectT(const T& x, const T& y, const T& w, const T& h) : x(x), y(y), w(w), h(h) {
}
// Verifies if the width and/or height of the rectangle are less or
// equal than zero.
bool isEmpty() const {
return (w <= 0 || h <= 0);
}
// Returns the middle point of the rectangle (x+w/2, y+h/2).
PointT<T> center() const {
return PointT<T>(x+w/2, y+h/2);
}
// Returns the point in the upper-left corner (that is inside the
// rectangle).
PointT<T> origin() const {
return PointT<T>(x, y);
}
// Returns point in the lower-right corner that is outside the
// rectangle (x+w, y+h).
PointT<T> point2() const {
return PointT<T>(x+w, y+h);
}
SizeT<T> size() const {
return SizeT<T>(w, h);
}
RectT& setOrigin(const PointT<T>& pt) {
x = pt.x;
y = pt.y;
return *this;
}
RectT& setSize(const SizeT<T>& sz) {
w = sz.w;
h = sz.h;
return *this;
}
// Moves the rectangle origin in the specified delta.
RectT& offset(const T& dx, const T& dy) {
x += dx;
y += dy;
return *this;
}
RectT& offset(const PointT<T>& delta) {
x += delta.x;
y += delta.y;
return *this;
}
RectT& inflate(const T& delta) {
w += delta;
h += delta;
return *this;
}
RectT& inflate(const T& dw, const T& dh) {
w += dw;
h += dh;
return *this;
}
RectT& inflate(const SizeT<T>& delta) {
w += delta.w;
h += delta.h;
return *this;
}
RectT& enlarge(const T& unit) {
x -= unit;
y -= unit;
w += unit<<1;
h += unit<<1;
return *this;
}
RectT& enlarge(const BorderT<T>& br) {
x -= br.left();
y -= br.top();
w += br.left() + br.right();
h += br.top() + br.bottom();
return *this;
}
RectT& enlargeXW(const T& unit) {
x -= unit;
w += unit<<1;
return *this;
}
RectT& enlargeYH(const T& unit) {
y -= unit;
h += unit<<1;
return *this;
}
RectT& shrink(const T& unit) {
x += unit;
y += unit;
w -= unit<<1;
h -= unit<<1;
return *this;
}
RectT& shrink(const BorderT<T>& br) {
x += br.left();
y += br.top();
w -= br.left() + br.right();
h -= br.top() + br.bottom();
return *this;
}
// Returns true if this rectangle encloses the pt point.
bool contains(const PointT<T>& pt) const {
return
pt.x >= x && pt.x < x+w &&
pt.y >= y && pt.y < y+h;
}
bool contains(const T& u, const T& v) const {
return
u >= x && u < x+w &&
v >= y && v < y+h;
}
// Returns true if this rectangle entirely contains the rc rectangle.
bool contains(const RectT& rc) const {
if (isEmpty() || rc.isEmpty())
return false;
return
rc.x >= x && rc.x+rc.w <= x+w &&
rc.y >= y && rc.y+rc.h <= y+h;
}
// Returns true if the intersection between this rectangle with rc
// rectangle is not empty.
bool intersects(const RectT& rc) const {
if (isEmpty() || rc.isEmpty())
return false;
return
rc.x < x+w && rc.x+rc.w > x &&
rc.y < y+h && rc.y+rc.h > y;
}
// Returns the union rectangle between this and rc rectangle.
RectT createUnion(const RectT& rc) const {
if (isEmpty())
return rc;
else if (rc.isEmpty())
return *this;
else
return RectT(PointT<T>(x < rc.x ? x: rc.x,
y < rc.y ? y: rc.y),
PointT<T>(x+w > rc.x+rc.w ? x+w: rc.x+rc.w,
y+h > rc.y+rc.h ? y+h: rc.y+rc.h));
}
// Returns the intersection rectangle between this and rc rectangles.
RectT createIntersection(const RectT& rc) const {
if (intersects(rc))
return RectT(PointT<T>(x > rc.x ? x: rc.x,
y > rc.y ? y: rc.y),
PointT<T>(x+w < rc.x+rc.w ? x+w: rc.x+rc.w,
y+h < rc.y+rc.h ? y+h: rc.y+rc.h));
else
return RectT();
}
const RectT& operator+=(const BorderT<T>& br) {
enlarge(br);
return *this;
}
const RectT& operator-=(const BorderT<T>& br) {
shrink(br);
return *this;
}
RectT& operator*=(const int factor) {
x *= factor;
y *= factor;
w *= factor;
h *= factor;
return *this;
}
RectT& operator/=(const int factor) {
x /= factor;
y /= factor;
w /= factor;
h /= factor;
return *this;
}
RectT& operator*=(const SizeT<T>& size) {
x *= size.w;
y *= size.h;
w *= size.w;
h *= size.h;
return *this;
}
RectT& operator/=(const SizeT<T>& size) {
x /= size.w;
y /= size.h;
w /= size.w;
h /= size.h;
return *this;
}
const RectT& operator|=(const RectT& rc) {
return *this = createUnion(rc);
}
const RectT& operator&=(const RectT& rc) {
return *this = createIntersection(rc);
}
RectT operator+(const BorderT<T>& br) const {
return RectT(*this).enlarge(br);
}
RectT operator-(const BorderT<T>& br) const {
return RectT(*this).shrink(br);
}
RectT operator|(const RectT& other) const {
return createUnion(other);
}
RectT operator&(const RectT& other) const {
return createIntersection(other);
}
RectT operator*(const SizeT<T>& size) const {
return RectT(x*size.w, y*size.h,
w*size.w, h*size.h);
}
RectT operator/(const SizeT<T>& size) const {
return RectT(x/size.w, y/size.h,
w/size.w, h/size.h);
}
bool operator==(const RectT& rc) const {
return
x == rc.x && w == rc.w &&
y == rc.y && h == rc.h;
}
bool operator!=(const RectT& rc) const {
return
x != rc.x || w != rc.w ||
y != rc.y || h != rc.h;
}
};
typedef RectT<int> Rect;
typedef RectT<double> RectF;
} // namespace gfx
#endif

View File

@ -1,42 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef GFX_RECT_IO_H_INCLUDED
#define GFX_RECT_IO_H_INCLUDED
#pragma once
#include "gfx/rect.h"
#include <iosfwd>
namespace gfx {
inline std::ostream& operator<<(std::ostream& os, const Rect& rect) {
return os << "("
<< rect.x << ", "
<< rect.y << ", "
<< rect.w << ", "
<< rect.h << ")";
}
inline std::istream& operator>>(std::istream& in, Rect& rect) {
while (in && in.get() != '(')
;
if (!in)
return in;
char chr;
in >> rect.x >> chr
>> rect.y >> chr
>> rect.w >> chr
>> rect.h >> chr;
return in;
}
}
#endif

View File

@ -1,54 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2013 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gtest/gtest.h>
#include "gfx/border.h"
#include "gfx/rect.h"
#include "gfx/rect_io.h"
#include "gfx/size.h"
using namespace std;
using namespace gfx;
TEST(Rect, Ctor)
{
EXPECT_EQ(Rect(0, 0, 0, 0), Rect());
EXPECT_EQ(10, Rect(10, 20, 30, 40).x);
EXPECT_EQ(20, Rect(10, 20, 30, 40).y);
EXPECT_EQ(30, Rect(10, 20, 30, 40).w);
EXPECT_EQ(40, Rect(10, 20, 30, 40).h);
}
TEST(Rect, Inflate)
{
EXPECT_EQ(Rect(10, 20, 31, 42), Rect(10, 20, 30, 40).inflate(1, 2));
EXPECT_EQ(Rect(10, 20, 31, 42), Rect(10, 20, 30, 40).inflate(Size(1, 2)));
}
TEST(Rect, Enlarge)
{
EXPECT_EQ(Rect(9, 19, 32, 42), Rect(10, 20, 30, 40).enlarge(1));
EXPECT_EQ(Rect(9, 18, 34, 46), Rect(10, 20, 30, 40).enlarge(Border(1, 2, 3, 4)));
EXPECT_EQ(Rect(9, 18, 34, 46), Rect(10, 20, 30, 40) + Border(1, 2, 3, 4));
}
TEST(Rect, Shrink)
{
EXPECT_EQ(Rect(11, 21, 28, 38), Rect(10, 20, 30, 40).shrink(1));
EXPECT_EQ(Rect(11, 22, 26, 34), Rect(10, 20, 30, 40).shrink(Border(1, 2, 3, 4)));
EXPECT_EQ(Rect(11, 22, 26, 34), Rect(10, 20, 30, 40) - Border(1, 2, 3, 4));
}
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,176 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2013, 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "pixman.h"
#include "gfx/point.h"
#include "gfx/region.h"
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
namespace gfx {
inline Rect to_rect(const pixman_box32& extends)
{
return Rect(
extends.x1, extends.y1,
extends.x2 - extends.x1,
extends.y2 - extends.y1);
}
Region::Region()
{
pixman_region32_init(&m_region);
}
Region::Region(const Region& copy)
{
pixman_region32_init(&m_region);
pixman_region32_copy(&m_region, &copy.m_region);
}
Region::Region(const Rect& rect)
{
if (!rect.isEmpty())
pixman_region32_init_rect(&m_region, rect.x, rect.y, rect.w, rect.h);
else
pixman_region32_init(&m_region);
}
Region::~Region()
{
pixman_region32_fini(&m_region);
}
Region& Region::operator=(const Rect& rect)
{
if (!rect.isEmpty()) {
pixman_box32 box = { rect.x, rect.y, rect.x2(), rect.y2() };
pixman_region32_reset(&m_region, &box);
}
else
pixman_region32_clear(&m_region);
return *this;
}
Region& Region::operator=(const Region& copy)
{
pixman_region32_copy(&m_region, &copy.m_region);
return *this;
}
Region::iterator Region::begin()
{
iterator it;
it.m_ptr = pixman_region32_rectangles(&m_region, NULL);
return it;
}
Region::iterator Region::end()
{
iterator it;
it.m_ptr = pixman_region32_rectangles(&m_region, NULL) + size();
return it;
}
Region::const_iterator Region::begin() const
{
const_iterator it;
it.m_ptr = pixman_region32_rectangles(&m_region, NULL);
return it;
}
Region::const_iterator Region::end() const
{
const_iterator it;
it.m_ptr = pixman_region32_rectangles(&m_region, NULL) + size();
return it;
}
bool Region::isEmpty() const
{
return pixman_region32_not_empty(&m_region) ? false: true;
}
Rect Region::bounds() const
{
return to_rect(*pixman_region32_extents(&m_region));
}
std::size_t Region::size() const
{
return pixman_region32_n_rects(&m_region);
}
void Region::clear()
{
pixman_region32_clear(&m_region);
}
void Region::offset(int dx, int dy)
{
pixman_region32_translate(&m_region, dx, dy);
}
void Region::offset(const PointT<int>& delta)
{
pixman_region32_translate(&m_region, delta.x, delta.y);
}
Region& Region::createIntersection(const Region& a, const Region& b)
{
pixman_region32_intersect(&m_region, &a.m_region, &b.m_region);
return *this;
}
Region& Region::createUnion(const Region& a, const Region& b)
{
pixman_region32_union(&m_region, &a.m_region, &b.m_region);
return *this;
}
Region& Region::createSubtraction(const Region& a, const Region& b)
{
pixman_region32_subtract(&m_region, &a.m_region, &b.m_region);
return *this;
}
bool Region::contains(const PointT<int>& pt) const
{
return pixman_region32_contains_point(&m_region, pt.x, pt.y, NULL) ? true: false;
}
Region::Overlap Region::contains(const Rect& rect) const
{
static_assert(
int(Out) == int(PIXMAN_REGION_OUT) &&
int(In) == int(PIXMAN_REGION_IN) &&
int(Part) == int(PIXMAN_REGION_PART), "Pixman constants have changed");
pixman_box32 box = { rect.x, rect.y, rect.x2(), rect.y2() };
return (Region::Overlap)pixman_region32_contains_rectangle(&m_region, &box);
}
Rect Region::operator[](int i)
{
assert(i >= 0 && i < (int)size());
return to_rect(pixman_region32_rectangles(&m_region, NULL)[i]);
}
const Rect Region::operator[](int i) const
{
assert(i >= 0 && i < (int)size());
return to_rect(pixman_region32_rectangles(&m_region, NULL)[i]);
}
} // namespace gfx

View File

@ -1,115 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef GFX_REGION_H_INCLUDED
#define GFX_REGION_H_INCLUDED
#pragma once
#include "gfx/rect.h"
#include <vector>
#include <iterator>
namespace gfx {
template<typename T> class PointT;
class Region;
namespace details {
#ifdef PIXMAN_VERSION_MAJOR
typedef struct pixman_box32 Box;
typedef struct pixman_region32 Region;
#else
struct Box {
int32_t x1, y1, x2, y2;
};
struct Region {
Box extents;
void* data;
};
#endif
template<typename T>
class RegionIterator : public std::iterator<std::forward_iterator_tag, T> {
public:
typedef typename std::iterator<std::forward_iterator_tag, T>::reference reference;
RegionIterator() : m_ptr(NULL) { }
RegionIterator(const RegionIterator& o) : m_ptr(o.m_ptr) { }
template<typename T2>
RegionIterator(const RegionIterator<T2>& o) : m_ptr(o.m_ptr) { }
RegionIterator& operator=(const RegionIterator& o) { m_ptr = o.m_ptr; return *this; }
RegionIterator& operator++() { ++m_ptr; return *this; }
RegionIterator operator++(int) { RegionIterator o(*this); ++m_ptr; return o; }
bool operator==(const RegionIterator& o) const { return m_ptr == o.m_ptr; }
bool operator!=(const RegionIterator& o) const { return m_ptr != o.m_ptr; }
reference operator*() {
m_rect.x = m_ptr->x1;
m_rect.y = m_ptr->y1;
m_rect.w = m_ptr->x2 - m_ptr->x1;
m_rect.h = m_ptr->y2 - m_ptr->y1;
return m_rect;
}
private:
Box* m_ptr;
mutable Rect m_rect;
template<typename> friend class RegionIterator;
friend class ::gfx::Region;
};
} // namespace details
class Region {
public:
enum Overlap { Out, In, Part };
typedef details::RegionIterator<Rect> iterator;
typedef details::RegionIterator<const Rect> const_iterator;
Region();
Region(const Region& copy);
explicit Region(const Rect& rect);
Region& operator=(const Rect& rect);
Region& operator=(const Region& copy);
~Region();
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
bool isEmpty() const;
Rect bounds() const;
std::size_t size() const;
void clear();
void offset(int dx, int dy);
void offset(const PointT<int>& delta);
Region& createIntersection(const Region& a, const Region& b);
Region& createUnion(const Region& a, const Region& b);
Region& createSubtraction(const Region& a, const Region& b);
bool contains(const PointT<int>& pt) const;
Overlap contains(const Rect& rect) const;
Rect operator[](int i);
const Rect operator[](int i) const;
Region& operator+=(const Region& b) { return createUnion(*this, b); }
Region& operator|=(const Region& b) { return createUnion(*this, b); }
Region& operator&=(const Region& b) { return createIntersection(*this, b); }
Region& operator-=(const Region& b) { return createSubtraction(*this, b); }
private:
mutable details::Region m_region;
};
} // namespace gfx
#endif

View File

@ -1,119 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gtest/gtest.h>
#include "gfx/point.h"
#include "gfx/rect_io.h"
#include "gfx/region.h"
using namespace std;
using namespace gfx;
ostream& operator<<(ostream& os, const Region& rgn)
{
os << "{";
for (Region::const_iterator it=rgn.begin(), end=rgn.end();
it != end; ) {
os << *it;
++it;
if (it != end)
os << ", ";
}
os << "}";
return os;
}
TEST(Region, Ctor)
{
EXPECT_EQ(0, Region().size());
EXPECT_TRUE(Region(Rect(0, 0, 0, 0)).isEmpty());
EXPECT_TRUE(Region().isEmpty());
ASSERT_EQ(0, Region(Rect(0, 0, 0, 0)).size());
ASSERT_EQ(1, Region(Rect(0, 0, 1, 1)).size());
EXPECT_EQ(Rect(2, 3, 4, 5), Region(Rect(2, 3, 4, 5))[0]);
}
TEST(Region, Equal)
{
Region a;
a = Rect(2, 3, 4, 5);
EXPECT_EQ(Rect(2, 3, 4, 5), a.bounds());
EXPECT_EQ(Rect(2, 3, 4, 5), a[0]);
EXPECT_FALSE(a.isEmpty());
a = Rect(6, 7, 8, 9);
EXPECT_EQ(Rect(6, 7, 8, 9), a.bounds());
EXPECT_EQ(Rect(6, 7, 8, 9), a[0]);
Region b;
b = a;
EXPECT_EQ(Rect(6, 7, 8, 9), b[0]);
b = Rect(0, 0, 0, 0);
EXPECT_TRUE(b.isEmpty());
}
TEST(Region, Clear)
{
Region a(Rect(2, 3, 4, 5));
EXPECT_FALSE(a.isEmpty());
a.clear();
EXPECT_TRUE(a.isEmpty());
}
TEST(Region, Union)
{
Region a(Rect(2, 3, 4, 5));
Region b(Rect(6, 3, 4, 5));
EXPECT_EQ(Rect(2, 3, 8, 5), Region().createUnion(a, b).bounds());
EXPECT_EQ(Rect(2, 3, 8, 5), Region().createUnion(b, a).bounds());
ASSERT_EQ(1, Region().createUnion(a, b).size());
ASSERT_EQ(1, Region().createUnion(b, a).size());
EXPECT_EQ(Rect(2, 3, 8, 5), Region().createUnion(a, b)[0]);
EXPECT_EQ(Rect(2, 3, 8, 5), Region().createUnion(b, a)[0]);
}
TEST(Region, ContainsPoint)
{
Region a(Rect(2, 3, 4, 5));
EXPECT_TRUE(a.contains(Point(2, 3)));
EXPECT_FALSE(a.contains(Point(2-1, 3-1)));
EXPECT_FALSE(a.contains(Point(2+4, 3)));
EXPECT_FALSE(a.contains(Point(2, 3+5)));
EXPECT_FALSE(a.contains(Point(2+4, 3+5)));
EXPECT_TRUE(a.contains(Point(2+4-1, 3)));
EXPECT_TRUE(a.contains(Point(2, 3+5-1)));
EXPECT_TRUE(a.contains(Point(2+4-1, 3+5-1)));
}
TEST(Region, Iterators)
{
Region a;
a.createUnion(a, Region(Rect(0, 0, 32, 64)));
a.createUnion(a, Region(Rect(0, 0, 64, 32)));
int c = 0;
for (Region::iterator it=a.begin(), end=a.end(); it!=end; ++it) {
++c;
}
EXPECT_EQ(2, c);
c = 0;
for (Region::const_iterator it=a.begin(), end=a.end(); it!=end; ++it) {
++c;
}
EXPECT_EQ(2, c);
}
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,134 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#include "gfx/rgb.h"
#include "gfx/hsl.h"
#include "gfx/hsv.h"
#include <cmath>
namespace gfx {
using namespace std;
// Reference: http://en.wikipedia.org/wiki/HSL_and_HSV
Rgb::Rgb(const Hsv& hsv)
{
double chroma = hsv.value() * hsv.saturation();
double hue_prime = hsv.hue() / 60.0;
double x = chroma * (1.0 - std::fabs(std::fmod(hue_prime, 2.0) - 1.0));
double r, g, b;
r = g = b = 0.0;
switch (int(hue_prime)) {
case 6:
case 0:
r = chroma;
g = x;
break;
case 1:
r = x;
g = chroma;
break;
case 2:
g = chroma;
b = x;
break;
case 3:
g = x;
b = chroma;
break;
case 4:
b = chroma;
r = x;
break;
case 5:
b = x;
r = chroma;
break;
}
double m = hsv.value() - chroma;
r += m;
g += m;
b += m;
m_red = int(r*255.0+0.5);
m_green = int(g*255.0+0.5);
m_blue = int(b*255.0+0.5);
}
Rgb::Rgb(const Hsl& hsl)
{
double chroma = (1.0 - std::fabs(2.0*hsl.lightness() - 1.0)) * hsl.saturation();
double hue_prime = hsl.hue() / 60.0;
double x = chroma * (1.0 - std::fabs(std::fmod(hue_prime, 2.0) - 1.0));
double r, g, b;
r = g = b = 0.0;
switch (int(hue_prime)) {
case 6:
case 0:
r = chroma;
g = x;
break;
case 1:
r = x;
g = chroma;
break;
case 2:
g = chroma;
b = x;
break;
case 3:
g = x;
b = chroma;
break;
case 4:
b = chroma;
r = x;
break;
case 5:
b = x;
r = chroma;
break;
}
double m = hsl.lightness() - chroma/2.0;
r += m;
g += m;
b += m;
m_red = int(r*255.0+0.5);
m_green = int(g*255.0+0.5);
m_blue = int(b*255.0+0.5);
}
int Rgb::maxComponent() const
{
if (m_red > m_green)
return (m_red > m_blue) ? m_red: m_blue;
else
return (m_green > m_blue) ? m_green: m_blue;
}
int Rgb::minComponent() const
{
if (m_red < m_green)
return (m_red < m_blue) ? m_red: m_blue;
else
return (m_green < m_blue) ? m_green: m_blue;
}
} // namespace gfx

View File

@ -1,94 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef GFX_RGB_H_INCLUDED
#define GFX_RGB_H_INCLUDED
#pragma once
#include <cassert>
namespace gfx {
class Hsv;
class Hsl;
class Rgb {
public:
Rgb()
: m_red(0)
, m_green(0)
, m_blue(0)
{ }
Rgb(int red, int green, int blue)
: m_red(red)
, m_green(green)
, m_blue(blue)
{
assert(red >= 0 && red <= 255);
assert(green >= 0 && green <= 255);
assert(blue >= 0 && blue <= 255);
}
Rgb(const Rgb& rgb)
: m_red(rgb.red())
, m_green(rgb.green())
, m_blue(rgb.blue())
{ }
// Conversions
explicit Rgb(const Hsv& hsv);
explicit Rgb(const Hsl& hsl);
int red() const {
return m_red;
}
int green() const {
return m_green;
}
int blue() const {
return m_blue;
}
int maxComponent() const;
int minComponent() const;
void red(int red) {
assert(red >= 0 && red <= 255);
m_red = red;
}
void green(int green) {
assert(green >= 0 && green <= 255);
m_green = green;
}
void blue(int blue) {
assert(blue >= 0 && blue <= 255);
m_blue = blue;
}
bool operator==(const Rgb& other) const {
return (m_red == other.m_red &&
m_green == other.m_green &&
m_blue == other.m_blue);
}
bool operator!=(const Rgb& other) const {
return !operator==(other);
}
private:
int m_red;
int m_green;
int m_blue;
};
} // namespace gfx
#endif

View File

@ -1,94 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2013 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gtest/gtest.h>
#include "gfx/rgb.h"
#include "gfx/hsv.h"
using namespace gfx;
using namespace std;
namespace gfx {
ostream& operator<<(ostream& os, const Rgb& rgb) {
return os << "("
<< rgb.red() << ", "
<< rgb.green() << ", "
<< rgb.blue() << ")";
}
}
TEST(Rgb, Ctor)
{
EXPECT_EQ(1, Rgb(1, 2, 3).red());
EXPECT_EQ(2, Rgb(1, 2, 3).green());
EXPECT_EQ(3, Rgb(1, 2, 3).blue());
EXPECT_EQ(Rgb(0, 0, 0), Rgb());
}
TEST(Rgb, Equal)
{
EXPECT_TRUE(Rgb(1, 2, 3) == Rgb(1, 2, 3));
EXPECT_FALSE(Rgb(1, 2, 3) != Rgb(1, 2, 3));
EXPECT_FALSE(Rgb(1, 2, 3) == Rgb(1, 3, 2));
EXPECT_FALSE(Rgb(0, 0, 0) == Rgb(0, 0, 1));
EXPECT_FALSE(Rgb(0, 0, 0) == Rgb(0, 1, 0));
EXPECT_FALSE(Rgb(0, 0, 0) == Rgb(1, 0, 0));
}
TEST(Rgb, MaxComponent)
{
EXPECT_EQ(3, Rgb(1, 2, 3).maxComponent());
EXPECT_EQ(3, Rgb(1, 3, 2).maxComponent());
EXPECT_EQ(3, Rgb(2, 1, 3).maxComponent());
EXPECT_EQ(3, Rgb(2, 3, 1).maxComponent());
EXPECT_EQ(3, Rgb(3, 1, 2).maxComponent());
EXPECT_EQ(3, Rgb(3, 2, 1).maxComponent());
}
TEST(Rgb, MinComponent)
{
EXPECT_EQ(1, Rgb(1, 2, 3).minComponent());
EXPECT_EQ(1, Rgb(1, 3, 2).minComponent());
EXPECT_EQ(1, Rgb(2, 1, 3).minComponent());
EXPECT_EQ(1, Rgb(2, 3, 1).minComponent());
EXPECT_EQ(1, Rgb(3, 1, 2).minComponent());
EXPECT_EQ(1, Rgb(3, 2, 1).minComponent());
}
TEST(Rgb, FromHsv)
{
for (double hue = 0.0; hue <= 360.0; hue += 10.0) {
EXPECT_EQ(Rgb(255, 255, 255), Rgb(Hsv(hue, 0.000, 1.000)));
EXPECT_EQ(Rgb(128, 128, 128), Rgb(Hsv(hue, 0.000, 0.500)));
EXPECT_EQ(Rgb( 0, 0, 0), Rgb(Hsv(hue, 0.000, 0.000)));
}
EXPECT_EQ(Rgb( 3, 0, 0), Rgb(Hsv( 0.0, 1.000, 0.010)));
EXPECT_EQ(Rgb(252, 0, 0), Rgb(Hsv( 0.0, 1.000, 0.990)));
EXPECT_EQ(Rgb(255, 0, 0), Rgb(Hsv( 0.0, 1.000, 1.000)));
EXPECT_EQ(Rgb(191, 191, 0), Rgb(Hsv( 60.0, 1.000, 0.750)));
EXPECT_EQ(Rgb( 0, 128, 0), Rgb(Hsv(120.0, 1.000, 0.500)));
EXPECT_EQ(Rgb( 0, 255, 0), Rgb(Hsv(120.0, 1.000, 1.000)));
EXPECT_EQ(Rgb(128, 255, 255), Rgb(Hsv(180.0, 0.500, 1.000)));
EXPECT_EQ(Rgb(128, 128, 255), Rgb(Hsv(240.0, 0.500, 1.000)));
EXPECT_EQ(Rgb( 0, 0, 255), Rgb(Hsv(240.0, 1.000, 1.000)));
EXPECT_EQ(Rgb(191, 64, 191), Rgb(Hsv(300.0, 0.667, 0.750)));
EXPECT_EQ(Rgb(252, 0, 0), Rgb(Hsv(360.0, 1.000, 0.990)));
EXPECT_EQ(Rgb(255, 0, 0), Rgb(Hsv(360.0, 1.000, 1.000)));
}
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -1,145 +0,0 @@
// Aseprite Gfx Library
// Copyright (C) 2001-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef GFX_SIZE_H_INCLUDED
#define GFX_SIZE_H_INCLUDED
#pragma once
#include <algorithm>
namespace gfx {
template<typename T>
class PointT;
// A 2D size.
template<typename T>
class SizeT
{
public:
T w, h;
SizeT() : w(0), h(0) {
}
SizeT(const T& w, const T& h) : w(w), h(h) {
}
SizeT(const SizeT& size) : w(size.w), h(size.h) {
}
template<typename T2>
explicit SizeT(const SizeT<T2>& size) : w(static_cast<T>(size.w)),
h(static_cast<T>(size.h)) {
}
explicit SizeT(const PointT<T>& point) : w(point.x), h(point.y) {
}
SizeT createUnion(const SizeT& sz) const {
return SizeT(std::max(w, sz.w),
std::max(h, sz.h));
}
SizeT createIntersection(const SizeT& sz) const {
return SizeT(std::min(w, sz.w),
std::min(h, sz.h));
}
const SizeT& operator=(const SizeT& sz) {
w = sz.w;
h = sz.h;
return *this;
}
const SizeT& operator+=(const SizeT& sz) {
w += sz.w;
h += sz.h;
return *this;
}
const SizeT& operator-=(const SizeT& sz) {
w -= sz.w;
h -= sz.h;
return *this;
}
const SizeT& operator+=(const T& value) {
w += value;
h += value;
return *this;
}
const SizeT& operator-=(const T& value) {
w -= value;
h -= value;
return *this;
}
const SizeT& operator*=(const T& value) {
w *= value;
h *= value;
return *this;
}
const SizeT& operator/=(const T& value) {
w /= value;
h /= value;
return *this;
}
const SizeT& operator|=(const SizeT& sz) {
return *this = createUnion(sz);
}
const SizeT& operator&=(const SizeT& sz) {
return *this = createIntersection(sz);
}
SizeT operator+(const SizeT& sz) const {
return SizeT(w+sz.w, h+sz.h);
}
SizeT operator-(const SizeT& sz) const {
return SizeT(w-sz.w, h-sz.h);
}
SizeT operator+(const T& value) const {
return SizeT(w+value, h+value);
}
SizeT operator-(const T& value) const {
return SizeT(w-value, h-value);
}
SizeT operator*(const T& value) const {
return SizeT(w*value, h*value);
}
SizeT operator/(const T& value) const {
return SizeT(w/value, h/value);
}
SizeT operator-() const {
return SizeT(-w, -h);
}
bool operator==(const SizeT& sz) const {
return w == sz.w && h == sz.h;
}
bool operator!=(const SizeT& sz) const {
return w != sz.w || h != sz.h;
}
};
typedef SizeT<int> Size;
typedef SizeT<double> SizeF;
} // namespace gfx
#endif

View File

@ -1,175 +0,0 @@
# LAF OS
# Copyright (C) 2012-2018 David Capello
# TODO the following variables should be available through options
# in this file instead of the main Aseprite CMakeLists.txt:
# - USE_NONE_BACKEND
# - USE_SKIA_BACKEND
# - WITH_GTK_FILE_DIALOG_SUPPORT
set(OS_SOURCES
common/freetype_font.cpp
draw_text.cpp
system.cpp)
######################################################################
# Skia backend
if(USE_SKIA_BACKEND)
set(SKIA_DIR "" CACHE PATH "Skia source code directory")
add_definitions(
-DSK_INTERNAL
-DSK_GAMMA_SRGB
-DSK_GAMMA_APPLY_TO_A8
-DSK_SCALAR_TO_FLOAT_EXCLUDED
-DSK_ALLOW_STATIC_GLOBAL_INITIALIZERS=1
-DSK_SUPPORT_OPENCL=0
-DSK_FORCE_DISTANCE_FIELD_TEXT=0
-DGR_GL_FUNCTION_TYPE=__stdcall
# TODO change this to 1
-DSK_SUPPORT_GPU=0)
if(WIN32)
add_definitions(-DSK_BUILD_FOR_WIN32)
elseif(APPLE)
add_definitions(-DSK_BUILD_FOR_MAC)
add_definitions(-Wno-ignored-attributes -Wno-unused-result)
# Use Automatic Reference Counting
add_definitions(-fobjc-arc)
else()
add_definitions(-DSK_SAMPLES_FOR_X)
endif()
if(NOT SKIA_DIR)
set(SKIA_OUT_DIR "" CACHE PATH "Skia output directory")
else()
if(CMAKE_BUILD_TYPE STREQUAL Debug)
set(SKIA_OUT_DIR "${SKIA_DIR}/out/Debug" CACHE PATH "Skia output directory")
else()
set(SKIA_OUT_DIR "${SKIA_DIR}/out/Release" CACHE PATH "Skia output directory")
endif()
endif()
find_library(SKIA_LIBRARY skia PATH "${SKIA_OUT_DIR}")
if(WIN32)
find_library(SKIA_OPENGL_LIBRARY opengl32)
else()
find_library(SKIA_OPENGL_LIBRARY opengl NAMES GL)
endif()
find_path(SKIA_CONFIG_INCLUDE_DIR SkUserConfig.h HINTS "${SKIA_DIR}/include/config")
find_path(SKIA_CORE_INCLUDE_DIR SkCanvas.h HINTS "${SKIA_DIR}/include/core")
find_path(SKIA_UTILS_INCLUDE_DIR SkRandom.h HINTS "${SKIA_DIR}/include/utils")
find_path(SKIA_CODEC_INCLUDE_DIR SkCodec.h HINTS "${SKIA_DIR}/include/codec")
find_path(SKIA_EFFECTS_INCLUDE_DIR SkImageSource.h HINTS "${SKIA_DIR}/include/effects")
find_path(SKIA_GPU_INCLUDE_DIR GrContext.h HINTS "${SKIA_DIR}/include/gpu")
find_path(SKIA_GPU2_INCLUDE_DIR gl/GrGLDefines.h HINTS "${SKIA_DIR}/src/gpu")
find_path(SKIA_ANGLE_INCLUDE_DIR angle_gl.h HINTS "${SKIA_DIR}/third_party/externals/angle2/include")
include_directories(
${SKIA_CONFIG_INCLUDE_DIR}
${SKIA_CORE_INCLUDE_DIR}
${SKIA_PORTS_INCLUDE_DIR}
${SKIA_UTILS_INCLUDE_DIR}
${SKIA_CODEC_INCLUDE_DIR}
${SKIA_GPU_INCLUDE_DIR}
${SKIA_GPU2_INCLUDE_DIR})
if(WIN32)
include_directories(${SKIA_ANGLE_INCLUDE_DIR})
endif()
set(SKIA_LIBRARIES
${SKIA_LIBRARY}
${SKIA_OPENGL_LIBRARY}
CACHE INTERNAL "Skia libraries")
list(APPEND OS_SOURCES
skia/skia_display.cpp
skia/skia_surface.cpp
skia/os.cpp)
if(WIN32)
list(APPEND OS_SOURCES
skia/skia_window_win.cpp
win/keys.cpp
win/pen.cpp
win/winapi.cpp
win/window.cpp
win/window_dde.cpp)
elseif(APPLE)
list(APPEND OS_SOURCES
osx/app.mm
osx/app_delegate.mm
osx/event_queue.mm
osx/keys.mm
osx/view.mm
osx/window.mm
skia/skia_window_osx.mm)
else()
list(APPEND OS_SOURCES
skia/skia_window_x11.cpp
x11/event_queue.cpp
x11/keys.cpp
x11/window.cpp
x11/x11.cpp)
endif()
endif()
######################################################################
# None backend
if(USE_NONE_BACKEND)
list(APPEND OS_SOURCES
none/os.cpp)
endif()
######################################################################
if(WIN32)
list(APPEND OS_SOURCES
win/native_dialogs.cpp)
endif()
if(APPLE)
list(APPEND OS_SOURCES
osx/logger.mm
osx/menus.mm
osx/native_dialogs.mm)
endif()
if(WITH_GTK_FILE_DIALOG_SUPPORT AND UNIX AND NOT APPLE AND NOT BEOS)
# Find gtkmm library
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK gtk+-3.0)
include_directories(${GTK_INCLUDE_DIRS})
link_directories(${GTK_LIBRARY_DIRS})
add_definitions(-DASEPRITE_WITH_GTK_FILE_DIALOG_SUPPORT)
list(APPEND OS_SOURCES
gtk/native_dialogs.cpp)
endif()
add_library(os-lib ${OS_SOURCES})
target_link_libraries(os-lib
ft-lib
gfx-lib
laf-base
${FREETYPE_LIBRARIES})
if(USE_SKIA_BACKEND)
target_link_libraries(os-lib
${SKIA_LIBRARIES}
${X11_LIBRARIES})
if(UNIX AND NOT APPLE)
target_link_libraries(os-lib fontconfig Xcursor)
endif()
endif()
if(WITH_GTK_FILE_DIALOG_SUPPORT)
target_link_libraries(os-lib
${GTKMM_LIBRARIES})
endif()

View File

@ -1,20 +0,0 @@
Copyright (c) 2012-2018 David Capello
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,8 +0,0 @@
# LAF OS Library
`os` is an abstraction layer to access in different way the Operating
System graphics interface. We have our own implementation to create
windows and handle mouse/keyboard input. The graphics are rendered
using the [Skia](https://skia.org/) library.
* Minimum Windows platform: Windows Vista

View File

@ -1,23 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_CAPABILITIES_H_INCLUDED
#define OS_CAPABILITIES_H_INCLUDED
#pragma once
namespace os {
enum class Capabilities {
MultipleDisplays = 1,
CanResizeDisplay = 2,
DisplayScale = 4,
CustomNativeMouseCursor = 8,
GpuAccelerationSwitch = 16
};
} // namespace os
#endif

View File

@ -1,53 +0,0 @@
// LAF OS Library
// Copyright (C) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_COMMON_FILE_DIALOG_H
#define OS_COMMON_FILE_DIALOG_H
#pragma once
#include "os/native_dialogs.h"
namespace os {
class CommonFileDialog : public FileDialog {
public:
CommonFileDialog()
: m_type(Type::OpenFile) {
}
void dispose() override {
delete this;
}
void setType(const Type type) override {
m_type = type;
}
void setTitle(const std::string& title) override {
m_title = title;
}
void setDefaultExtension(const std::string& extension) override {
m_defExtension = extension;
}
void addFilter(const std::string& extension, const std::string& description) override {
if (m_defExtension.empty())
m_defExtension = extension;
m_filters.push_back(std::make_pair(extension, description));
}
protected:
Type m_type;
std::string m_title;
std::string m_defExtension;
std::vector<std::pair<std::string, std::string>> m_filters;
};
} // namespace os
#endif

View File

@ -1,90 +0,0 @@
// LAF OS Library
// Copyright (C) 2016-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "os/common/freetype_font.h"
#include "base/string.h"
#include "ft/algorithm.h"
#include "gfx/point.h"
#include "gfx/size.h"
namespace os {
FreeTypeFont::FreeTypeFont(ft::Lib& lib,
const char* filename,
const int height)
: m_face(lib.open(filename))
{
if (m_face.isValid())
m_face.setSize(height);
}
FreeTypeFont::~FreeTypeFont()
{
}
bool FreeTypeFont::isValid() const
{
return m_face.isValid();
}
void FreeTypeFont::dispose()
{
delete this;
}
FontType FreeTypeFont::type()
{
return FontType::kTrueType;
}
int FreeTypeFont::height() const
{
return int(m_face.height());
}
int FreeTypeFont::textLength(const std::string& str) const
{
return ft::calc_text_bounds(m_face, str).w;
}
bool FreeTypeFont::isScalable() const
{
return true;
}
void FreeTypeFont::setSize(int size)
{
m_face.setSize(size);
}
void FreeTypeFont::setAntialias(bool antialias)
{
m_face.setAntialias(antialias);
}
bool FreeTypeFont::hasCodePoint(int codepoint) const
{
return m_face.hasCodePoint(codepoint);
}
FreeTypeFont* load_free_type_font(ft::Lib& lib,
const char* filename,
const int height)
{
FreeTypeFont* font = new FreeTypeFont(lib, filename, height);
if (!font->isValid()) {
delete font;
font = nullptr;
}
return font;
}
} // namespace os

View File

@ -1,49 +0,0 @@
// LAF OS Library
// Copyright (C) 2016-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_COMMON_FREETYPE_FONT_H_INCLUDED
#define OS_COMMON_FREETYPE_FONT_H_INCLUDED
#pragma once
#include "ft/hb_face.h"
#include "ft/lib.h"
#include "os/font.h"
namespace os {
class Font;
class FreeTypeFont : public Font {
public:
typedef ft::Face Face;
FreeTypeFont(ft::Lib& lib,
const char* filename,
const int height);
~FreeTypeFont();
bool isValid() const;
void dispose() override;
FontType type() override;
int height() const override;
int textLength(const std::string& str) const override;
bool isScalable() const override;
void setSize(int size) override;
void setAntialias(bool antialias) override;
bool hasCodePoint(int codepoint) const override;
Face& face() { return m_face; }
private:
mutable Face m_face;
};
FreeTypeFont* load_free_type_font(ft::Lib& lib,
const char* filename,
const int height);
} // namespace os
#endif

View File

@ -1,97 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_COMMON_GENERIC_SURFACE_H
#define OS_COMMON_GENERIC_SURFACE_H
#pragma once
#include "gfx/clip.h"
#include "gfx/color.h"
#include "os/surface.h"
namespace os {
namespace {
#define MUL_UN8(a, b, t) \
((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8))
inline gfx::Color blend(const gfx::Color backdrop, gfx::Color src)
{
if (gfx::geta(backdrop) == 0)
return src;
else if (gfx::geta(src) == 0)
return backdrop;
int Br, Bg, Bb, Ba;
int Sr, Sg, Sb, Sa;
int Rr, Rg, Rb, Ra;
Br = gfx::getr(backdrop);
Bg = gfx::getg(backdrop);
Bb = gfx::getb(backdrop);
Ba = gfx::geta(backdrop);
Sr = gfx::getr(src);
Sg = gfx::getg(src);
Sb = gfx::getb(src);
Sa = gfx::geta(src);
int t;
Ra = Ba + Sa - MUL_UN8(Ba, Sa, t);
Rr = Br + (Sr-Br) * Sa / Ra;
Rg = Bg + (Sg-Bg) * Sa / Ra;
Rb = Bb + (Sb-Bb) * Sa / Ra;
return gfx::rgba(Rr, Rg, Rb, Ra);
}
} // anoynmous namespace
template<typename Base>
class GenericDrawColoredRgbaSurface : public Base {
public:
void drawColoredRgbaSurface(const Surface* src, gfx::Color fg, gfx::Color bg, const gfx::Clip& clipbase) override {
gfx::Clip clip(clipbase);
if (!clip.clip(this->width(),
this->height(),
src->width(), src->height()))
return;
SurfaceFormatData format;
src->getFormat(&format);
ASSERT(format.format == kRgbaSurfaceFormat);
ASSERT(format.bitsPerPixel == 32);
for (int v=0; v<clip.size.h; ++v) {
const uint32_t* ptr = (const uint32_t*)src->getData(
clip.src.x, clip.src.y+v);
for (int u=0; u<clip.size.w; ++u) {
gfx::Color dstColor = this->getPixel(clip.dst.x+u, clip.dst.y+v);
if (gfx::geta(bg) > 0)
dstColor = blend(dstColor, bg);
uint32_t src = (((*ptr) & format.alphaMask) >> format.alphaShift);
if (src > 0) {
src = gfx::rgba(gfx::getr(fg),
gfx::getg(fg),
gfx::getb(fg), src);
dstColor = blend(dstColor, src);
}
this->putPixel(dstColor, clip.dst.x+u, clip.dst.y+v);
++ptr;
}
}
}
};
} // namespace os
#endif

View File

@ -1,138 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_SPRITE_SHEET_FONT_H
#define OS_SPRITE_SHEET_FONT_H
#pragma once
#include "base/debug.h"
#include "base/string.h"
#include "gfx/rect.h"
#include "os/font.h"
#include "os/surface.h"
#include <vector>
namespace os {
class SpriteSheetFont : public Font {
public:
SpriteSheetFont() : m_sheet(nullptr) {
}
~SpriteSheetFont() {
ASSERT(m_sheet);
m_sheet->dispose();
}
void dispose() override {
delete this;
}
FontType type() override {
return FontType::kSpriteSheet;
}
int height() const override {
return getCharBounds(' ').h;
}
int textLength(const std::string& str) const override {
base::utf8_const_iterator it(str.begin()), end(str.end());
int x = 0;
while (it != end) {
x += getCharBounds(*it).w;
++it;
}
return x;
}
bool isScalable() const override {
return false;
}
void setSize(int size) override {
// Do nothing
}
void setAntialias(bool antialias) override {
// Do nothing
}
bool hasCodePoint(int codepoint) const override {
codepoint -= (int)' ';
return (codepoint >= 0 && codepoint < (int)m_chars.size());
}
Surface* getSurfaceSheet() const {
return m_sheet;
}
gfx::Rect getCharBounds(int chr) const {
chr -= (int)' ';
if (chr >= 0 && chr < (int)m_chars.size())
return m_chars[chr];
else if (chr != 128)
return getCharBounds(128);
else
return gfx::Rect();
}
static Font* fromSurface(Surface* sur) {
SpriteSheetFont* font = new SpriteSheetFont;
font->m_sheet = sur;
SurfaceLock lock(sur);
gfx::Rect bounds(0, 0, 1, 1);
while (font->findChar(sur, sur->width(), sur->height(), bounds)) {
font->m_chars.push_back(bounds);
bounds.x += bounds.w;
}
return font;
}
private:
bool findChar(const Surface* sur, int width, int height, gfx::Rect& bounds) {
gfx::Color keyColor = sur->getPixel(0, 0);
while (sur->getPixel(bounds.x, bounds.y) == keyColor) {
bounds.x++;
if (bounds.x >= width) {
bounds.x = 0;
bounds.y += bounds.h;
bounds.h = 1;
if (bounds.y >= height)
return false;
}
}
bounds.w = 0;
while ((bounds.x+bounds.w < width) &&
(sur->getPixel(bounds.x+bounds.w, bounds.y) != keyColor)) {
bounds.w++;
}
bounds.h = 0;
while ((bounds.y+bounds.h < height) &&
(sur->getPixel(bounds.x, bounds.y+bounds.h) != keyColor)) {
bounds.h++;
}
return !bounds.isEmpty();
}
private:
Surface* m_sheet;
std::vector<gfx::Rect> m_chars;
};
} // namespace os
#endif

View File

@ -1,139 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_COMMON_SYSTEM_H
#define OS_COMMON_SYSTEM_H
#pragma once
#ifdef _WIN32
#include "os/win/native_dialogs.h"
#elif defined(__APPLE__)
#include "os/osx/menus.h"
#include "os/osx/native_dialogs.h"
#elif defined(ASEPRITE_WITH_GTK_FILE_DIALOG_SUPPORT) && defined(__linux__)
#include "os/gtk/native_dialogs.h"
#else
#include "os/native_dialogs.h"
#endif
#include "ft/lib.h"
#include "os/common/freetype_font.h"
#include "os/common/sprite_sheet_font.h"
#include "os/menus.h"
#include "os/system.h"
#include <memory>
namespace os {
#ifdef __APPLE__
Logger* getOsxLogger();
#endif
class CommonSystem : public System {
public:
CommonSystem()
: m_nativeDialogs(nullptr)
, m_menus(nullptr) {
#ifdef _WIN32
m_useWintabAPI = true;
#endif
}
~CommonSystem() {
delete m_nativeDialogs;
delete m_menus;
}
void dispose() override {
delete this;
}
void useWintabAPI(bool state) override {
#ifdef _WIN32
m_useWintabAPI = state;
#endif
}
#ifdef _WIN32
bool useWintabAPI() const {
return m_useWintabAPI;
}
#endif
Logger* logger() override {
#ifdef __APPLE__
return getOsxLogger();
#else
return nullptr;
#endif
}
Menus* menus() override {
#ifdef __APPLE__
if (!m_menus)
m_menus = new MenusOSX();
#endif
return m_menus;
}
NativeDialogs* nativeDialogs() override {
#ifdef _WIN32
if (!m_nativeDialogs)
m_nativeDialogs = new NativeDialogsWin32();
#elif defined(__APPLE__)
if (!m_nativeDialogs)
m_nativeDialogs = new NativeDialogsOSX();
#elif defined(ASEPRITE_WITH_GTK_FILE_DIALOG_SUPPORT) && defined(__linux__)
if (!m_nativeDialogs)
m_nativeDialogs = new NativeDialogsGTK();
#endif
return m_nativeDialogs;
}
Font* loadSpriteSheetFont(const char* filename, int scale) override {
Surface* sheet = loadRgbaSurface(filename);
Font* font = nullptr;
if (sheet) {
sheet->applyScale(scale);
font = SpriteSheetFont::fromSurface(sheet);
}
return font;
}
Font* loadTrueTypeFont(const char* filename, int height) override {
if (!m_ft)
m_ft.reset(new ft::Lib());
return load_free_type_font(*m_ft.get(), filename, height);
}
KeyModifiers keyModifiers() override {
return
(KeyModifiers)
((isKeyPressed(kKeyLShift) ||
isKeyPressed(kKeyRShift) ? kKeyShiftModifier: 0) |
(isKeyPressed(kKeyLControl) ||
isKeyPressed(kKeyRControl) ? kKeyCtrlModifier: 0) |
(isKeyPressed(kKeyAlt) ? kKeyAltModifier: 0) |
(isKeyPressed(kKeyAltGr) ? (kKeyCtrlModifier | kKeyAltModifier): 0) |
(isKeyPressed(kKeyCommand) ? kKeyCmdModifier: 0) |
(isKeyPressed(kKeySpace) ? kKeySpaceModifier: 0) |
(isKeyPressed(kKeyLWin) ||
isKeyPressed(kKeyRWin) ? kKeyWinModifier: 0));
}
private:
#ifdef _WIN32
bool m_useWintabAPI;
#endif
NativeDialogs* m_nativeDialogs;
Menus* m_menus;
std::unique_ptr<ft::Lib> m_ft;
};
} // namespace os
#endif

View File

@ -1,86 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_DISPLAY_H_INCLUDED
#define OS_DISPLAY_H_INCLUDED
#pragma once
#include "gfx/point.h"
#include "os/display_handle.h"
#include "os/native_cursor.h"
#include "os/surface_list.h"
#include <string>
namespace os {
class Surface;
// A display or window to show graphics.
class Display {
public:
virtual ~Display() { }
virtual void dispose() = 0;
// Returns the real and current display's size (without scale applied).
virtual int width() const = 0;
virtual int height() const = 0;
// Returns the display when it was not maximized.
virtual int originalWidth() const = 0;
virtual int originalHeight() const = 0;
// Returns the current display scale. Each pixel in the internal
// display surface, is represented by SCALExSCALE pixels on the
// screen.
virtual int scale() const = 0;
// Changes the scale.
// The available surface size will be (Display::width() / scale,
// Display::height() / scale)
virtual void setScale(int scale) = 0;
// Returns the main surface to draw into this display.
// You must not dispose this surface.
virtual Surface* getSurface() = 0;
// Flips all graphics in the surface to the real display.
virtual void flip(const gfx::Rect& bounds) = 0;
virtual void maximize() = 0;
virtual bool isMaximized() const = 0;
virtual bool isMinimized() const = 0;
virtual void setTitleBar(const std::string& title) = 0;
virtual void setIcons(const SurfaceList& icons) = 0;
virtual NativeCursor nativeMouseCursor() = 0;
virtual bool setNativeMouseCursor(NativeCursor cursor) = 0;
virtual bool setNativeMouseCursor(const os::Surface* cursor,
const gfx::Point& focus,
const int scale) = 0;
virtual void setMousePosition(const gfx::Point& position) = 0;
virtual void captureMouse() = 0;
virtual void releaseMouse() = 0;
// Set/get the specific information to restore the exact same
// window position (e.g. in the same monitor).
virtual std::string getLayout() = 0;
virtual void setLayout(const std::string& layout) = 0;
// For Windows 8/10 only in tablet devices: Set to true if you
// want to interpret one finger as the mouse movement and two
// fingers as pan/scroll (true by default). If you want to pan
// with one finger, call this function with false.
virtual void setInterpretOneFingerGestureAsMouseMovement(bool state) = 0;
// Returns the HWND on Windows.
virtual DisplayHandle nativeHandle() = 0;
};
} // namespace os
#endif

View File

@ -1,17 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_DISPLAY_HANDLE_H_INCLUDED
#define OS_DISPLAY_HANDLE_H_INCLUDED
#pragma once
namespace os {
typedef void* DisplayHandle;
} // namespace os
#endif

View File

@ -1,228 +0,0 @@
// LAF OS Library
// Copyright (C) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "os/draw_text.h"
#include "ft/algorithm.h"
#include "ft/hb_shaper.h"
#include "gfx/clip.h"
#include "os/common/freetype_font.h"
#include "os/common/generic_surface.h"
#include "os/common/sprite_sheet_font.h"
namespace os {
gfx::Rect draw_text(Surface* surface, Font* font,
const base::utf8_const_iterator& begin,
const base::utf8_const_iterator& end,
gfx::Color fg, gfx::Color bg,
int x, int y,
DrawTextDelegate* delegate)
{
base::utf8_const_iterator it = begin;
gfx::Rect textBounds;
retry:;
// Check if this font is enough to draw the given string or we will
// need the fallback for some special Unicode chars
if (font->fallback()) {
// TODO compose unicode characters and check those codepoints, the
// same in the drawing code of sprite sheet font
for (auto it=begin; it!=end; ++it) {
uint32_t code = *it;
if (code && !font->hasCodePoint(code)) {
Font* newFont = font->fallback();
// Search a valid fallback
while (newFont && !newFont->hasCodePoint(code))
newFont = newFont->fallback();
if (!newFont)
break;
y += font->height()/2 - newFont->height()/2;
font = newFont;
goto retry;
}
}
}
switch (font->type()) {
case FontType::kSpriteSheet: {
SpriteSheetFont* ssFont = static_cast<SpriteSheetFont*>(font);
Surface* sheet = ssFont->getSurfaceSheet();
if (surface) {
sheet->lock();
surface->lock();
}
while (it != end) {
int chr = *it;
if (delegate) {
int i = it-begin;
delegate->preProcessChar(i, chr, fg, bg);
}
gfx::Rect charBounds = ssFont->getCharBounds(chr);
gfx::Rect outCharBounds(x, y, charBounds.w, charBounds.h);
if (delegate && !delegate->preDrawChar(outCharBounds))
break;
if (!charBounds.isEmpty()) {
if (surface)
surface->drawColoredRgbaSurface(sheet, fg, bg, gfx::Clip(x, y, charBounds));
}
textBounds |= outCharBounds;
if (delegate)
delegate->postDrawChar(outCharBounds);
x += charBounds.w;
++it;
}
if (surface) {
surface->unlock();
sheet->unlock();
}
break;
}
case FontType::kTrueType: {
FreeTypeFont* ttFont = static_cast<FreeTypeFont*>(font);
bool antialias = ttFont->face().antialias();
int fg_alpha = gfx::geta(fg);
gfx::Rect clipBounds;
os::SurfaceFormatData fd;
if (surface) {
clipBounds = surface->getClipBounds();
surface->getFormat(&fd);
surface->lock();
}
ft::ForEachGlyph<FreeTypeFont::Face> feg(ttFont->face());
if (feg.initialize(it, end)) {
do {
if (delegate) {
delegate->preProcessChar(feg.charIndex(),
feg.unicodeChar(), fg, bg);
}
auto glyph = feg.glyph();
if (!glyph)
continue;
gfx::Rect origDstBounds(
x + int(glyph->startX),
y + int(glyph->y),
int(glyph->endX) - int(glyph->startX),
int(glyph->bitmap->rows) ? int(glyph->bitmap->rows): 1);
if (delegate && !delegate->preDrawChar(origDstBounds))
break;
origDstBounds.x = x + int(glyph->x);
origDstBounds.w = int(glyph->bitmap->width);
origDstBounds.h = int(glyph->bitmap->rows);
gfx::Rect dstBounds = origDstBounds;
if (surface)
dstBounds &= clipBounds;
if (surface && !dstBounds.isEmpty()) {
int clippedRows = dstBounds.y - origDstBounds.y;
int dst_y = dstBounds.y;
int t;
for (int v=0; v<dstBounds.h; ++v, ++dst_y) {
int bit = 0;
const uint8_t* p = glyph->bitmap->buffer
+ (v+clippedRows)*glyph->bitmap->pitch;
int dst_x = dstBounds.x;
uint32_t* dst_address =
(uint32_t*)surface->getData(dst_x, dst_y);
// Skip first clipped pixels
for (int u=0; u<dstBounds.x-origDstBounds.x; ++u) {
if (antialias) {
++p;
}
else {
if (bit == 8) {
bit = 0;
++p;
}
}
}
for (int u=0; u<dstBounds.w; ++u, ++dst_x) {
ASSERT(clipBounds.contains(gfx::Point(dst_x, dst_y)));
int alpha;
if (antialias) {
alpha = *(p++);
}
else {
alpha = ((*p) & (1 << (7 - (bit++))) ? 255: 0);
if (bit == 8) {
bit = 0;
++p;
}
}
uint32_t backdrop = *dst_address;
gfx::Color backdropColor =
gfx::rgba(
((backdrop & fd.redMask) >> fd.redShift),
((backdrop & fd.greenMask) >> fd.greenShift),
((backdrop & fd.blueMask) >> fd.blueShift),
((backdrop & fd.alphaMask) >> fd.alphaShift));
gfx::Color output = gfx::rgba(gfx::getr(fg),
gfx::getg(fg),
gfx::getb(fg),
MUL_UN8(fg_alpha, alpha, t));
if (gfx::geta(bg) > 0)
output = blend(blend(backdropColor, bg), output);
else
output = blend(backdropColor, output);
*dst_address =
((gfx::getr(output) << fd.redShift ) & fd.redMask ) |
((gfx::getg(output) << fd.greenShift) & fd.greenMask) |
((gfx::getb(output) << fd.blueShift ) & fd.blueMask ) |
((gfx::geta(output) << fd.alphaShift) & fd.alphaMask);
++dst_address;
}
}
}
if (!origDstBounds.w) origDstBounds.w = 1;
if (!origDstBounds.h) origDstBounds.h = 1;
textBounds |= origDstBounds;
if (delegate)
delegate->postDrawChar(origDstBounds);
} while (feg.nextChar());
}
if (surface)
surface->unlock();
break;
}
}
return textBounds;
}
} // namespace os

View File

@ -1,54 +0,0 @@
// LAF OS Library
// Copyright (C) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_DRAW_TEXT_H_INCLUDED
#define OS_DRAW_TEXT_H_INCLUDED
#pragma once
#include "base/string.h"
#include "gfx/color.h"
#include "gfx/fwd.h"
namespace os {
class Font;
class Surface;
class SurfaceLock;
class DrawTextDelegate {
public:
virtual ~DrawTextDelegate() { }
// This is called before drawing the character.
virtual void preProcessChar(const int index,
const int codepoint,
gfx::Color& fg, gfx::Color& bg) {
// Do nothing
}
virtual bool preDrawChar(const gfx::Rect& charBounds) {
// Returns false if the process should stop here.
return true;
}
virtual void postDrawChar(const gfx::Rect& charBounds) {
// Do nothing
}
};
// The surface can be nullptr just to process the string
// (e.g. measure how much space will use the text without drawing
// it).
gfx::Rect draw_text(Surface* surface, Font* font,
const base::utf8_const_iterator& begin,
const base::utf8_const_iterator& end,
gfx::Color fg, gfx::Color bg,
int x, int y,
DrawTextDelegate* delegate);
} // namespace os
#endif

View File

@ -1,17 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2014 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_ERROR_H_INCLUDED
#define OS_ERROR_H_INCLUDED
#pragma once
namespace os {
void error_message(const char* msg);
} // namespace os
#endif

View File

@ -1,135 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_EVENT_H_INCLUDED
#define OS_EVENT_H_INCLUDED
#pragma once
#include "base/paths.h"
#include "gfx/point.h"
#include "gfx/size.h"
#include "os/keys.h"
#include "os/pointer_type.h"
#pragma push_macro("None")
#undef None // Undefine the X11 None macro
namespace os {
class Display;
class Event {
public:
enum Type {
None,
CloseDisplay,
ResizeDisplay,
DropFiles,
MouseEnter,
MouseLeave,
MouseMove,
MouseDown,
MouseUp,
MouseWheel,
MouseDoubleClick,
KeyDown,
KeyUp,
TouchMagnify,
};
enum MouseButton {
NoneButton,
LeftButton,
RightButton,
MiddleButton,
X1Button,
X2Button,
};
Event() : m_type(None),
m_display(nullptr),
m_scancode(kKeyNil),
m_modifiers(kKeyUninitializedModifier),
m_unicodeChar(0),
m_isDead(false),
m_repeat(0),
m_preciseWheel(false),
m_pointerType(PointerType::Unknown),
m_button(NoneButton),
m_magnification(0.0),
m_pressure(0.0) {
}
Type type() const { return m_type; }
Display* display() const { return m_display; }
const base::paths& files() const { return m_files; }
// TODO Rename this to virtualKey(), which is the real
// meaning. Then we need another kind of "scan code" with the
// position in the keyboard, which might be useful to identify
// keys by its position (e.g. WASD keys in other keyboard
// layouts).
KeyScancode scancode() const { return m_scancode; }
KeyModifiers modifiers() const { return m_modifiers; }
int unicodeChar() const { return m_unicodeChar; }
bool isDeadKey() const { return m_isDead; }
int repeat() const { return m_repeat; }
gfx::Point position() const { return m_position; }
gfx::Point wheelDelta() const { return m_wheelDelta; }
// We suppose that if we are receiving precise scrolling deltas,
// it means that the user is using a touch-like surface (trackpad,
// magic mouse scrolling, touch wacom tablet, etc.)
bool preciseWheel() const { return m_preciseWheel; }
PointerType pointerType() const { return m_pointerType; }
MouseButton button() const { return m_button; }
double magnification() const { return m_magnification; }
double pressure() const { return m_pressure; }
void setType(Type type) { m_type = type; }
void setDisplay(Display* display) { m_display = display; }
void setFiles(const base::paths& files) { m_files = files; }
void setScancode(KeyScancode scancode) { m_scancode = scancode; }
void setModifiers(KeyModifiers modifiers) { m_modifiers = modifiers; }
void setUnicodeChar(int unicodeChar) { m_unicodeChar = unicodeChar; }
void setDeadKey(bool state) { m_isDead = state; }
void setRepeat(int repeat) { m_repeat = repeat; }
void setPosition(const gfx::Point& pos) { m_position = pos; }
void setWheelDelta(const gfx::Point& delta) { m_wheelDelta = delta; }
void setPreciseWheel(bool precise) { m_preciseWheel = precise; }
void setPointerType(PointerType pointerType) { m_pointerType = pointerType; }
void setButton(MouseButton button) { m_button = button; }
void setMagnification(double magnification) { m_magnification = magnification; }
void setPressure(double pressure) { m_pressure = pressure; }
private:
Type m_type;
Display* m_display;
base::paths m_files;
KeyScancode m_scancode;
KeyModifiers m_modifiers;
int m_unicodeChar;
bool m_isDead;
int m_repeat; // repeat=0 means the first time the key is pressed
gfx::Point m_position;
gfx::Point m_wheelDelta;
bool m_preciseWheel;
PointerType m_pointerType;
MouseButton m_button;
// For TouchMagnify event
double m_magnification;
// Pressure of stylus used in mouse-like events
double m_pressure;
};
} // namespace os
#pragma pop_macro("None")
#endif

View File

@ -1,34 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_EVENT_QUEUE_H_INCLUDED
#define OS_EVENT_QUEUE_H_INCLUDED
#pragma once
namespace os {
class Event;
class EventQueue {
public:
virtual ~EventQueue() { }
virtual void getEvent(Event& ev, bool canWait) = 0;
virtual void queueEvent(const Event& ev) = 0;
// On MacOS X we need the EventQueue before the creation of the
// System. E.g. when we double-click a file an Event to open that
// file is queued in application:openFile:, code which is executed
// before the user's main() code.
static EventQueue* instance();
};
inline void queue_event(const Event& ev) {
EventQueue::instance()->queueEvent(ev);
}
} // namespace os
#endif

View File

@ -1,47 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_FONT_H_INCLUDED
#define OS_FONT_H_INCLUDED
#pragma once
#include <string>
namespace os {
enum class FontType {
kUnknown,
kSpriteSheet,
kTrueType,
};
class Font {
public:
Font() : m_fallback(nullptr) { }
virtual ~Font() { }
virtual void dispose() = 0;
virtual FontType type() = 0;
virtual int height() const = 0;
virtual int textLength(const std::string& str) const = 0;
virtual bool isScalable() const = 0;
virtual void setSize(int size) = 0;
virtual void setAntialias(bool antialias) = 0;
virtual bool hasCodePoint(int codepoint) const = 0;
os::Font* fallback() const {
return m_fallback;
}
void setFallback(os::Font* font) {
m_fallback = font;
}
private:
os::Font* m_fallback;
};
} // namespace os
#endif

View File

@ -1,25 +0,0 @@
// LAF OS Library
// Copyright (C) 2015-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_GL_CONTEXT_INCLUDED
#define OS_GL_CONTEXT_INCLUDED
#pragma once
namespace os {
class GLContext {
public:
virtual ~GLContext() { }
virtual bool createGLContext() = 0;
virtual void destroyGLContext() = 0;
virtual int getStencilBits() = 0;
virtual int getSampleCount() = 0;
virtual void swapBuffers() { }
};
} // namespace os
#endif

View File

@ -1,83 +0,0 @@
// LAF OS Library
// Copyright (C) 2015-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_GL_CONTEXT_CGL_INCLUDED
#define OS_GL_CONTEXT_CGL_INCLUDED
#pragma once
#include "os/gl/gl_context.h"
#include <OpenGL/OpenGL.h>
#include <dlfcn.h>
namespace os {
class GLContextCGL : public GLContext {
public:
GLContextCGL()
: m_glctx(nullptr)
, m_stencilBits(0)
, m_sampleCount(0) {
}
~GLContextCGL() {
destroyGLContext();
}
bool createGLContext() override {
CGLPixelFormatAttribute attributes[] = {
kCGLPFAOpenGLProfile,
(CGLPixelFormatAttribute)kCGLOGLPVersion_3_2_Core,
kCGLPFAAccelerated,
kCGLPFADoubleBuffer,
(CGLPixelFormatAttribute)0
};
CGLPixelFormatObj format;
GLint npix;
CGLChoosePixelFormat(attributes, &format, &npix);
if (!format)
return false;
CGLDescribePixelFormat(format, 0, kCGLPFASamples, &m_sampleCount);
CGLDescribePixelFormat(format, 0, kCGLPFAStencilSize, &m_stencilBits);
CGLCreateContext(format, nullptr, &m_glctx);
CGLReleasePixelFormat(format);
if (!m_glctx)
return false;
CGLSetCurrentContext(m_glctx);
return true;
}
void destroyGLContext() override {
if (m_glctx) {
CGLReleaseContext(m_glctx);
m_glctx = nullptr;
}
}
int getStencilBits() override {
return m_stencilBits;
}
int getSampleCount() override {
return m_sampleCount;
}
CGLContextObj cglContext() {
return m_glctx;
}
private:
CGLContextObj m_glctx;
int m_stencilBits;
int m_sampleCount;
};
} // namespace os
#endif

View File

@ -1,165 +0,0 @@
// LAF OS Library
// Copyright (C) 2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_GL_CONTEXT_EGL_INCLUDED
#define OS_GL_CONTEXT_EGL_INCLUDED
#pragma once
#include "os/gl/gl_context.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
namespace os {
class GLContextEGL : public GLContext {
public:
GLContextEGL(void* nativeDisplay)
: m_nativeDisplay(nativeDisplay)
, m_context(EGL_NO_CONTEXT)
, m_display(EGL_NO_DISPLAY)
, m_surface(EGL_NO_SURFACE)
{
}
~GLContextEGL() {
destroyGLContext();
}
bool createGLContext() override {
m_display = getD3DEGLDisplay((HDC)GetDC((HWND)m_nativeDisplay));
if (m_display == EGL_NO_DISPLAY) {
LOG("OS: Cannot create EGL display");
return false;
}
EGLint majorVersion;
EGLint minorVersion;
if (!eglInitialize(m_display, &majorVersion, &minorVersion))
return false;
static const EGLint configAttribs[] = {
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_NONE
};
EGLConfig surfaceConfig;
EGLint numConfigs;
if (!eglChooseConfig(m_display, configAttribs, &surfaceConfig, 1, &numConfigs))
return false;
static const EGLint surfaceAttribs[] = {
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_NONE
};
m_surface = eglCreateWindowSurface(
m_display,
surfaceConfig,
(EGLNativeWindowType)m_nativeDisplay,
surfaceAttribs);
if (m_surface == EGL_NO_SURFACE)
return false;
static const EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
m_context = eglCreateContext(m_display, surfaceConfig,
EGL_NO_CONTEXT,
contextAttribs);
if (m_context == EGL_NO_CONTEXT)
return false;
if (!eglMakeCurrent(m_display, m_surface, m_surface, m_context))
return false;
eglGetConfigAttrib(m_display, surfaceConfig, EGL_STENCIL_SIZE, &m_stencilBits);
eglGetConfigAttrib(m_display, surfaceConfig, EGL_SAMPLES, &m_sampleCount);
return true;
}
void destroyGLContext() override {
if (m_display != EGL_NO_DISPLAY) {
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (m_surface != EGL_NO_SURFACE) {
eglDestroySurface(m_display, m_surface);
m_surface = EGL_NO_SURFACE;
}
if (m_context != EGL_NO_CONTEXT) {
eglDestroyContext(m_display, m_context);
m_context = EGL_NO_CONTEXT;
}
eglTerminate(m_display);
m_display = EGL_NO_DISPLAY;
}
}
int getStencilBits() override {
return m_stencilBits;
}
int getSampleCount() override {
return m_sampleCount;
}
void swapBuffers() override {
eglSwapBuffers(m_display, m_surface);
}
private:
static void* getD3DEGLDisplay(void* nativeDisplay) {
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
eglGetPlatformDisplayEXT =
(PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
if (!eglGetPlatformDisplayEXT)
return eglGetDisplay(static_cast<EGLNativeDisplayType>(nativeDisplay));
EGLint attribs[3][3] = {
{
EGL_PLATFORM_ANGLE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
EGL_NONE
},
{
EGL_PLATFORM_ANGLE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE,
EGL_NONE
},
{
EGL_PLATFORM_ANGLE_TYPE_ANGLE,
EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE,
EGL_NONE
}
};
EGLDisplay display = EGL_NO_DISPLAY;
for (int i=0; i<3 && display == EGL_NO_DISPLAY; ++i) {
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
nativeDisplay, attribs[i]);
}
return display;
}
void* m_nativeDisplay;
void* m_context;
void* m_display;
void* m_surface;
EGLint m_stencilBits;
EGLint m_sampleCount;
};
} // namespace os
#endif

View File

@ -1,92 +0,0 @@
// LAF OS Library
// Copyright (C) 2015-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_GL_CONTEXT_WGL_INCLUDED
#define OS_GL_CONTEXT_WGL_INCLUDED
#pragma once
#include "os/gl/gl_context.h"
#include <windows.h>
namespace os {
class GLContextWGL : public GLContext {
public:
GLContextWGL(HWND hwnd)
: m_hwnd(hwnd)
, m_glrc(nullptr) {
}
~GLContextWGL() {
destroyGLContext();
}
bool createGLContext() override {
HDC hdc = GetDC(m_hwnd);
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL, // support OpenGL
PFD_TYPE_RGBA, // RGBA type
24, // 24-bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
8, // 8-bit alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
0, // no z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int pixelFormat = ChoosePixelFormat(hdc, &pfd);
SetPixelFormat(hdc, pixelFormat, &pfd);
m_glrc = wglCreateContext(hdc);
if (!m_glrc) {
ReleaseDC(m_hwnd, hdc);
return false;
}
wglMakeCurrent(hdc, m_glrc);
ReleaseDC(m_hwnd, hdc);
return true;
}
void destroyGLContext() override {
if (m_glrc) {
wglMakeCurrent(nullptr, nullptr);
wglDeleteContext(m_glrc);
m_glrc = nullptr;
}
}
int getStencilBits() override {
HDC hdc = GetDC(m_hwnd);
int pixelFormat = GetPixelFormat(hdc);
PIXELFORMATDESCRIPTOR pfd;
DescribePixelFormat(hdc, pixelFormat, sizeof(pfd), &pfd);
ReleaseDC(m_hwnd, hdc);
return pfd.cStencilBits;
}
int getSampleCount() override {
return 0;
}
private:
HWND m_hwnd;
HGLRC m_glrc;
};
} // namespace os
#endif

View File

@ -1,258 +0,0 @@
// LAF OS Library
// Copyright (C) 2017-2018 David Capello
// Copyright (C) 2016 Gabriel Rauter
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "os/gtk/native_dialogs.h"
#include "base/fs.h"
#include "base/string.h"
#include "os/common/file_dialog.h"
#include "os/display.h"
#include "os/error.h"
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
namespace os {
class FileDialogGTK : public CommonFileDialog {
public:
FileDialogGTK() {
}
std::string fileName() override {
return m_filename;
}
void getMultipleFileNames(base::paths& output) override {
output = m_filenames;
}
void setFileName(const std::string& filename) override {
m_filename = base::get_file_name(filename);
m_initialDir = base::get_file_path(filename);
}
bool show(Display* parent) override {
static std::string s_lastUsedDir;
if (s_lastUsedDir.empty())
s_lastUsedDir = g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP);
const char* okLabel;
GtkFileChooserAction action;
switch (m_type) {
case Type::OpenFile:
case Type::OpenFiles:
action = GTK_FILE_CHOOSER_ACTION_OPEN;
okLabel = "_Open";
break;
case Type::OpenFolder:
action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
okLabel = "_Open Folder";
break;
case Type::SaveFile:
action = GTK_FILE_CHOOSER_ACTION_SAVE;
okLabel = "_Save";
break;
}
// GtkWindow* gtkParent = nullptr;
GtkWidget* dialog = gtk_file_chooser_dialog_new(
m_title.c_str(),
nullptr,
action,
"_Cancel", GTK_RESPONSE_CANCEL,
okLabel, GTK_RESPONSE_ACCEPT,
nullptr);
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
GtkFileChooser* chooser = GTK_FILE_CHOOSER(dialog);
m_chooser = chooser;
if (m_type == Type::SaveFile)
gtk_file_chooser_set_do_overwrite_confirmation(chooser, TRUE);
else if (m_type == Type::OpenFiles)
gtk_file_chooser_set_select_multiple(chooser, true);
if (m_type != Type::OpenFolder) {
setupFilters(base::get_file_extension(m_filename));
setupPreview();
}
if (m_initialDir.empty())
gtk_file_chooser_set_current_folder(chooser, s_lastUsedDir.c_str());
else
gtk_file_chooser_set_current_folder(chooser, m_initialDir.c_str());
if (!m_filename.empty()) {
std::string fn = m_filename;
// Add default extension
if (m_type == Type::SaveFile && base::get_file_extension(fn).empty()) {
fn.push_back('.');
fn += m_defExtension;
}
gtk_file_chooser_set_current_name(chooser, fn.c_str());
}
// Setup the "parent" display as the parent of the dialog (we've
// to convert a X11 Window into a GdkWindow to do this).
GdkWindow* gdkParentWindow = nullptr;
if (parent) {
GdkWindow* gdkWindow = gtk_widget_get_root_window(dialog);
gdkParentWindow =
gdk_x11_window_foreign_new_for_display(
gdk_window_get_display(gdkWindow),
(::Window)parent->nativeHandle());
gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
gdk_window_set_transient_for(gdkWindow, gdkParentWindow);
}
else {
gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
}
// Show the dialog
gint res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
s_lastUsedDir = gtk_file_chooser_get_current_folder(chooser);
m_filename = gtk_file_chooser_get_filename(chooser);
if (m_type == Type::OpenFiles) {
GSList* list = gtk_file_chooser_get_filenames(chooser);
g_slist_foreach(
list,
[](void* fn, void* userdata){
auto self = (FileDialogGTK*)userdata;
self->m_filenames.push_back((char*)fn);
g_free(fn);
}, this);
g_slist_free(list);
}
}
gtk_widget_destroy(dialog);
if (gdkParentWindow)
g_object_unref(gdkParentWindow);
// Pump gtk+ events to finally hide the dialog from the screen
while (gtk_events_pending())
gtk_main_iteration();
return (res == GTK_RESPONSE_ACCEPT);
}
private:
void setupFilters(const std::string& fnExtension) {
// Filter for all known formats
GtkFileFilter* gtkFilter = gtk_file_filter_new();
gtk_file_filter_set_name(gtkFilter, "All formats");
for (const auto& filter : m_filters) {
const std::string& ext = filter.first;
std::string pat = "*." + ext;
gtk_file_filter_add_pattern(gtkFilter, pat.c_str());
}
gtk_file_chooser_add_filter(m_chooser, gtkFilter);
// One filter for each format
for (const auto& filter : m_filters) {
const std::string& ext = filter.first;
const std::string& desc = filter.second;
std::string pat = "*." + ext;
gtkFilter = gtk_file_filter_new();
gtk_file_filter_set_name(gtkFilter, desc.c_str());
gtk_file_filter_add_pattern(gtkFilter, pat.c_str());
gtk_file_chooser_add_filter(m_chooser, gtkFilter);
if (base::utf8_icmp(ext, fnExtension) == 0)
gtk_file_chooser_set_filter(m_chooser, gtkFilter);
}
// One filter for all files
gtkFilter = gtk_file_filter_new();
gtk_file_filter_set_name(gtkFilter, "All files");
gtk_file_filter_add_pattern(gtkFilter, "*");
gtk_file_chooser_add_filter(m_chooser, gtkFilter);
}
void setupPreview() {
m_preview = gtk_image_new();
gtk_file_chooser_set_use_preview_label(m_chooser, false);
gtk_file_chooser_set_preview_widget(m_chooser, m_preview);
g_signal_connect(
m_chooser, "update-preview",
G_CALLBACK(&FileDialogGTK::s_onUpdatePreview), this);
}
static void s_onUpdatePreview(GtkFileChooser* chooser, gpointer userData) {
((FileDialogGTK*)userData)->onUpdatePreview();
}
void onUpdatePreview() {
// Disable preview because we don't know if we will be able to
// load/generate the preview successfully.
gtk_file_chooser_set_preview_widget_active(m_chooser, false);
const char* fn = gtk_file_chooser_get_filename(m_chooser);
if (fn && base::is_file(fn)) {
GError* err = nullptr;
GdkPixbuf* previewPixbuf =
gdk_pixbuf_new_from_file_at_scale(fn, 256, 256, true, &err);
if (previewPixbuf) {
gtk_image_set_from_pixbuf(GTK_IMAGE(m_preview), previewPixbuf);
g_object_unref(previewPixbuf);
// Now we can enable the preview panel as the preview was
// generated.
gtk_file_chooser_set_preview_widget_active(m_chooser, true);
}
if (err)
g_error_free(err);
}
}
std::string m_filename;
std::string m_initialDir;
base::paths m_filenames;
GtkFileChooser* m_chooser;
GtkWidget* m_preview;
};
NativeDialogsGTK::NativeDialogsGTK()
: m_gtkApp(nullptr)
{
}
NativeDialogsGTK::~NativeDialogsGTK()
{
if (m_gtkApp) {
g_object_unref(m_gtkApp);
m_gtkApp = nullptr;
}
}
FileDialog* NativeDialogsGTK::createFileDialog()
{
if (!m_gtkApp) {
int argc = 0;
char** argv = nullptr;
gtk_init(&argc, &argv);
m_gtkApp = gtk_application_new(nullptr, G_APPLICATION_FLAGS_NONE);
}
return new FileDialogGTK;
}
} // namespace os

View File

@ -1,29 +0,0 @@
// LAF OS Library
// Copyright (C) 2017 David Capello
// Copyright (C) 2016 Gabriel Rauter
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_GTK_NATIVE_DIALOGS_H_INCLUDED
#define OS_GTK_NATIVE_DIALOGS_H_INCLUDED
#pragma once
#include "os/native_dialogs.h"
extern "C" struct _GtkApplication;
namespace os {
class NativeDialogsGTK : public NativeDialogs {
public:
NativeDialogsGTK();
~NativeDialogsGTK();
FileDialog* createFileDialog() override;
private:
_GtkApplication* m_gtkApp;
};
} // namespace os
#endif

View File

@ -1,165 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_KEYS_H_INCLUDED
#define OS_KEYS_H_INCLUDED
#pragma once
namespace os {
enum KeyModifiers {
kKeyNoneModifier = 0,
kKeyShiftModifier = 1,
kKeyCtrlModifier = 2,
kKeyAltModifier = 4,
kKeyCmdModifier = 8,
kKeySpaceModifier = 16,
kKeyWinModifier = 32,
kKeyUninitializedModifier = 64,
};
// TODO These are virtual key code (not scancodes), we should rename
// it to KeyCodes or use Unicode directly as on macOS (some
// special keys like F1, arrow keys, etc. have a special
// unicode value).
enum KeyScancode {
kKeyNil = 0,
kKeyA = 1,
kKeyB = 2,
kKeyC = 3,
kKeyD = 4,
kKeyE = 5,
kKeyF = 6,
kKeyG = 7,
kKeyH = 8,
kKeyI = 9,
kKeyJ = 10,
kKeyK = 11,
kKeyL = 12,
kKeyM = 13,
kKeyN = 14,
kKeyO = 15,
kKeyP = 16,
kKeyQ = 17,
kKeyR = 18,
kKeyS = 19,
kKeyT = 20,
kKeyU = 21,
kKeyV = 22,
kKeyW = 23,
kKeyX = 24,
kKeyY = 25,
kKeyZ = 26,
kKey0 = 27,
kKey1 = 28,
kKey2 = 29,
kKey3 = 30,
kKey4 = 31,
kKey5 = 32,
kKey6 = 33,
kKey7 = 34,
kKey8 = 35,
kKey9 = 36,
kKey0Pad = 37,
kKey1Pad = 38,
kKey2Pad = 39,
kKey3Pad = 40,
kKey4Pad = 41,
kKey5Pad = 42,
kKey6Pad = 43,
kKey7Pad = 44,
kKey8Pad = 45,
kKey9Pad = 46,
kKeyF1 = 47,
kKeyF2 = 48,
kKeyF3 = 49,
kKeyF4 = 50,
kKeyF5 = 51,
kKeyF6 = 52,
kKeyF7 = 53,
kKeyF8 = 54,
kKeyF9 = 55,
kKeyF10 = 56,
kKeyF11 = 57,
kKeyF12 = 58,
kKeyEsc = 59,
kKeyTilde = 60,
kKeyMinus = 61,
kKeyEquals = 62,
kKeyBackspace = 63,
kKeyTab = 64,
kKeyOpenbrace = 65,
kKeyClosebrace = 66,
kKeyEnter = 67,
kKeyColon = 68,
kKeyQuote = 69,
kKeyBackslash = 70,
kKeyBackslash2 = 71,
kKeyComma = 72,
kKeyStop = 73,
kKeySlash = 74,
kKeySpace = 75,
kKeyInsert = 76,
kKeyDel = 77,
kKeyHome = 78,
kKeyEnd = 79,
kKeyPageUp = 80,
kKeyPageDown = 81,
kKeyLeft = 82,
kKeyRight = 83,
kKeyUp = 84,
kKeyDown = 85,
kKeySlashPad = 86,
kKeyAsterisk = 87,
kKeyMinusPad = 88,
kKeyPlusPad = 89,
kKeyDelPad = 90,
kKeyEnterPad = 91,
kKeyPrtscr = 92,
kKeyPause = 93,
kKeyAbntC1 = 94,
kKeyYen = 95,
kKeyKana = 96,
kKeyConvert = 97,
kKeyNoconvert = 98,
kKeyAt = 99,
kKeyCircumflex = 100,
kKeyColon2 = 101,
kKeyKanji = 102,
kKeyEqualsPad = 103, // macOS
kKeyBackquote = 104, // macOS
kKeySemicolon = 105, // macOS
kKeyUnknown1 = 106,
kKeyUnknown2 = 107,
kKeyUnknown3 = 108,
kKeyUnknown4 = 109,
kKeyUnknown5 = 110,
kKeyUnknown6 = 111,
kKeyUnknown7 = 112,
kKeyUnknown8 = 113,
kKeyFirstModifierScancode = 114,
kKeyLShift = 114,
kKeyRShift = 115,
kKeyLControl = 116,
kKeyRControl = 117,
kKeyAlt = 118,
kKeyAltGr = 119,
kKeyLWin = 120,
kKeyRWin = 121,
kKeyMenu = 122,
kKeyCommand = 123,
kKeyScrLock = 124,
kKeyNumLock = 125,
kKeyCapsLock = 126,
kKeyScancodes = 127
};
} // namespace os
#endif

View File

@ -1,21 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2014 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_LOGGER_H_INCLUDED
#define OS_LOGGER_H_INCLUDED
#pragma once
namespace os {
class Logger {
public:
virtual ~Logger() { }
virtual void logError(const char* error) = 0;
};
} // namespace os
#endif

View File

@ -1,92 +0,0 @@
// LAF OS Library
// Copyright (C) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_MENUS_H_INCLUDED
#define OS_MENUS_H_INCLUDED
#pragma once
#include "os/keys.h"
#include "os/shortcut.h"
#include <functional>
#include <string>
namespace os {
class MenuItem;
struct MenuItemInfo {
enum Type {
Normal,
Separator
};
enum Action {
UserDefined,
// macOS standard commands
Hide,
HideOthers,
ShowAll,
Quit,
Minimize,
Zoom,
};
Type type;
Action action;
std::string text;
Shortcut shortcut;
std::function<void()> execute;
std::function<void(os::MenuItem*)> validate;
explicit MenuItemInfo(const Type type = Normal,
const Action action = UserDefined)
: type(type)
, action(action) {
}
explicit MenuItemInfo(const char* text,
const Action action = UserDefined)
: type(Normal)
, action(action)
, text(text) {
}
};
class Menu;
class MenuItem;
class Menus;
class MenuItem {
public:
virtual ~MenuItem() { }
virtual void dispose() = 0;
virtual void setText(const std::string& text) = 0;
virtual void setSubmenu(Menu* submenu) = 0;
virtual void setEnabled(bool state) = 0;
virtual void setChecked(bool state) = 0;
virtual void setShortcut(const Shortcut& shortcut) = 0;
};
class Menu {
public:
virtual ~Menu() { }
virtual void dispose() = 0;
virtual void addItem(MenuItem* item) = 0;
virtual void insertItem(const int index, MenuItem* item) = 0;
};
class Menus {
public:
virtual ~Menus() { }
virtual Menu* createMenu() = 0;
virtual MenuItem* createMenuItem(const MenuItemInfo& info) = 0;
virtual void setAppMenu(Menu* menu) = 0;
};
} // namespace os
#endif

View File

@ -1,39 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2014 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_NATIVE_CURSOR_H_INCLUDED
#define OS_NATIVE_CURSOR_H_INCLUDED
#pragma once
#include "gfx/fwd.h"
namespace os {
enum NativeCursor {
kNoCursor,
kArrowCursor,
kCrosshairCursor,
kIBeamCursor,
kWaitCursor,
kLinkCursor,
kHelpCursor,
kForbiddenCursor,
kMoveCursor,
kSizeNSCursor,
kSizeWECursor,
kSizeNCursor,
kSizeNECursor,
kSizeECursor,
kSizeSECursor,
kSizeSCursor,
kSizeSWCursor,
kSizeWCursor,
kSizeNWCursor,
};
} // namespace os
#endif

View File

@ -1,47 +0,0 @@
// LAF OS Library
// Copyright (C) 2015-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_NATIVE_DIALOGS_H_INCLUDED
#define OS_NATIVE_DIALOGS_H_INCLUDED
#pragma once
#include "base/paths.h"
#include <string>
namespace os {
class Display;
class FileDialog {
public:
enum class Type {
OpenFile,
OpenFiles,
OpenFolder,
SaveFile,
};
virtual ~FileDialog() { }
virtual void dispose() = 0;
virtual void setType(const Type type) = 0;
virtual void setTitle(const std::string& title) = 0;
virtual void setDefaultExtension(const std::string& extension) = 0;
virtual void addFilter(const std::string& extension, const std::string& description) = 0;
virtual std::string fileName() = 0;
virtual void getMultipleFileNames(base::paths& output) = 0;
virtual void setFileName(const std::string& filename) = 0;
virtual bool show(Display* parent) = 0;
};
class NativeDialogs {
public:
virtual ~NativeDialogs() { }
virtual FileDialog* createFileDialog() = 0;
};
} // namespace os
#endif

View File

@ -1,75 +0,0 @@
// LAF OS Library
// Copyright (C) 2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "base/memory.h"
#include "os/system.h"
namespace os {
class NoneSystem : public System {
public:
void dispose() override { delete this; }
void activateApp() override { }
void finishLaunching() override { }
Capabilities capabilities() const override { return (Capabilities)0; }
void useWintabAPI(bool enable) override { }
Logger* logger() override { return nullptr; }
Menus* menus() override { return nullptr; }
NativeDialogs* nativeDialogs() override { return nullptr; }
EventQueue* eventQueue() override { return nullptr; }
bool gpuAcceleration() const override { return false; }
void setGpuAcceleration(bool state) override { }
gfx::Size defaultNewDisplaySize() override { return gfx::Size(0, 0); }
Display* defaultDisplay() override { return nullptr; }
Display* createDisplay(int width, int height, int scale) override { return nullptr; }
Surface* createSurface(int width, int height) override { return nullptr; }
Surface* createRgbaSurface(int width, int height) override { return nullptr; }
Surface* loadSurface(const char* filename) override { return nullptr; }
Surface* loadRgbaSurface(const char* filename) override { return nullptr; }
Font* loadSpriteSheetFont(const char* filename, int scale) override { return nullptr; }
Font* loadTrueTypeFont(const char* filename, int height) override { return nullptr; }
bool isKeyPressed(KeyScancode scancode) override { return false; }
KeyModifiers keyModifiers() override { return kKeyNoneModifier; }
int getUnicodeFromScancode(KeyScancode scancode) override { return 0; }
void setTranslateDeadKeys(bool state) override { }
};
System* create_system_impl() {
return new NoneSystem;
}
void error_message(const char* msg)
{
fputs(msg, stderr);
// TODO
}
} // namespace os
extern int app_main(int argc, char* argv[]);
#if _WIN32
int wmain(int argc, wchar_t* wargv[], wchar_t* envp[]) {
char** argv;
if (wargv && argc > 0) {
argv = new char*[argc];
for (int i=0; i<argc; ++i)
argv[i] = base_strdup(base::to_utf8(std::wstring(wargv[i])).c_str());
}
else {
argv = new char*[1];
argv[0] = base_strdup("");
argc = 1;
}
#else
int main(int argc, char* argv[]) {
#endif
return app_main(argc, argv);
}

View File

@ -1,31 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_H_INCLUDED
#define OS_H_INCLUDED
#pragma once
#include "os/capabilities.h"
#include "os/display.h"
#include "os/display_handle.h"
#include "os/draw_text.h"
#include "os/error.h"
#include "os/event.h"
#include "os/event_queue.h"
#include "os/font.h"
#include "os/keys.h"
#include "os/logger.h"
#include "os/menus.h"
#include "os/native_cursor.h"
#include "os/native_dialogs.h"
#include "os/pointer_type.h"
#include "os/scoped_handle.h"
#include "os/shortcut.h"
#include "os/surface.h"
#include "os/surface_format.h"
#include "os/system.h"
#endif

View File

@ -1,35 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_OSX_APP_H_INCLUDED
#define OS_OSX_APP_H_INCLUDED
#pragma once
namespace base {
class thread;
}
namespace os {
class OSXApp {
public:
static OSXApp* instance();
OSXApp();
~OSXApp();
bool init();
void activateApp();
void finishLaunching();
private:
class Impl;
Impl* m_impl;
};
} // namespace os
#endif

View File

@ -1,95 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <Cocoa/Cocoa.h>
#include "os/osx/app.h"
#include "base/debug.h"
#include "base/thread.h"
#include "os/osx/app_delegate.h"
extern int app_main(int argc, char* argv[]);
namespace os {
class OSXApp::Impl {
public:
bool init() {
m_app = [NSApplication sharedApplication];
m_appDelegate = [OSXAppDelegate new];
[m_app setActivationPolicy:NSApplicationActivationPolicyRegular];
[m_app setDelegate:m_appDelegate];
// Don't activate the application ignoring other apps. This is
// called by OS X when the application is launched by the user
// from the application bundle. In this way, we can execute
// aseprite from the command line/bash scripts and the app will
// not be activated.
//[m_app activateIgnoringOtherApps:YES];
return true;
}
// We might need to call this function when the app is launched from
// Steam. It appears that there is a bug on OS X Steam client where
// the app is launched, activated, and then the Steam client is
// activated again.
void activateApp() {
[m_app activateIgnoringOtherApps:YES];
}
void finishLaunching() {
[m_app finishLaunching];
}
private:
NSApplication* m_app;
OSXAppDelegate* m_appDelegate;
};
static OSXApp* g_instance = nullptr;
// static
OSXApp* OSXApp::instance()
{
return g_instance;
}
OSXApp::OSXApp()
: m_impl(new Impl)
{
ASSERT(!g_instance);
g_instance = this;
}
OSXApp::~OSXApp()
{
ASSERT(g_instance == this);
g_instance = nullptr;
}
bool OSXApp::init()
{
return m_impl->init();
}
void OSXApp::activateApp()
{
m_impl->activateApp();
}
void OSXApp::finishLaunching()
{
m_impl->finishLaunching();
}
} // namespace os

View File

@ -1,24 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_OSX_APP_DELEGATE_H_INCLUDED
#define OS_OSX_APP_DELEGATE_H_INCLUDED
#pragma once
#include <Cocoa/Cocoa.h>
@interface OSXAppDelegate : NSObject<NSApplicationDelegate>
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender;
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)app;
- (void)applicationWillTerminate:(NSNotification*)notification;
- (void)applicationWillResignActive:(NSNotification*)notification;
- (void)applicationDidBecomeActive:(NSNotification*)notification;
- (BOOL)application:(NSApplication*)app openFiles:(NSArray*)filenames;
- (void)executeMenuItem:(id)sender;
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem;
@end
#endif

View File

@ -1,83 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <Cocoa/Cocoa.h>
#include "os/osx/app_delegate.h"
#include "base/fs.h"
#include "os/event.h"
#include "os/event_queue.h"
#include "os/osx/app.h"
#include "os/osx/generate_drop_files.h"
#include "os/osx/view.h"
#include "os/system.h"
@protocol OSXValidateMenuItemProtocol
- (void)validateMenuItem;
@end
@implementation OSXAppDelegate
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender
{
os::Event ev;
ev.setType(os::Event::CloseDisplay);
os::queue_event(ev);
return NSTerminateCancel;
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)app
{
return YES;
}
- (void)applicationWillTerminate:(NSNotification*)notification
{
}
- (void)applicationWillResignActive:(NSNotification*)notification
{
NSEvent* event = [NSApp currentEvent];
if (event != nil)
[OSXView updateKeyFlags:event];
}
- (void)applicationDidBecomeActive:(NSNotification*)notification
{
NSEvent* event = [NSApp currentEvent];
if (event != nil)
[OSXView updateKeyFlags:event];
}
- (BOOL)application:(NSApplication*)app openFiles:(NSArray*)filenames
{
generate_drop_files_from_nsarray(filenames);
[app replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
return YES;
}
- (void)executeMenuItem:(id)sender
{
[sender executeMenuItem:sender];
}
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem
{
if ([menuItem respondsToSelector:@selector(validateMenuItem)]) {
[((id<OSXValidateMenuItemProtocol>)menuItem) validateMenuItem];
return menuItem.enabled;
}
else
return [super validateMenuItem:menuItem];
}
@end

View File

@ -1,30 +0,0 @@
// LAF OS Library
// Copyright (C) 2015-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_OSX_EVENT_QUEUE_INCLUDED
#define OS_OSX_EVENT_QUEUE_INCLUDED
#pragma once
#include "base/concurrent_queue.h"
#include "os/event.h"
#include "os/event_queue.h"
namespace os {
class OSXEventQueue : public EventQueue {
public:
void getEvent(Event& ev, bool canWait) override;
void queueEvent(const Event& ev) override;
private:
base::concurrent_queue<Event> m_events;
};
typedef OSXEventQueue EventQueueImpl;
} // namespace os
#endif

View File

@ -1,67 +0,0 @@
// LAF OS Library
// Copyright (C) 2015-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h>
#include "os/osx/event_queue.h"
namespace os {
void OSXEventQueue::getEvent(Event& ev, bool canWait)
{
ev.setType(Event::None);
@autoreleasepool {
retry:;
NSApplication* app = [NSApplication sharedApplication];
if (!app)
return;
// Pump the whole queue of Cocoa events
NSEvent* event;
do {
event = [app nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantPast]
inMode:NSDefaultRunLoopMode
dequeue:YES];
if (event) {
// Intercept <Control+Tab>, <Cmd+[>, and other keyboard
// combinations, and send them directly to the main
// NSView. Without this, the NSApplication intercepts the key
// combination and use it to go to the next key view.
if (event.type == NSEventTypeKeyDown) {
[app.mainWindow.contentView keyDown:event];
}
else {
[app sendEvent:event];
}
}
} while (event);
if (!m_events.try_pop(ev)) {
if (canWait) {
// Wait until there is a Cocoa event in queue
[NSApp nextEventMatchingMask:NSEventMaskAny
untilDate:[NSDate distantFuture]
inMode:NSDefaultRunLoopMode
dequeue:NO];
goto retry;
}
}
}
}
void OSXEventQueue::queueEvent(const Event& ev)
{
m_events.push(ev);
}
} // namespace os

View File

@ -1,27 +0,0 @@
// LAF OS Library
// Copyright (C) 2016-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_OSX_APP_GENERATE_DROP_FILES_H_INCLUDED
#define OS_OSX_APP_GENERATE_DROP_FILES_H_INCLUDED
#pragma once
#include "base/fs.h"
inline void generate_drop_files_from_nsarray(NSArray* filenames)
{
base::paths files;
for (int i=0; i<[filenames count]; ++i) {
NSString* fn = [filenames objectAtIndex: i];
files.push_back(base::normalize_path([fn UTF8String]));
}
os::Event ev;
ev.setType(os::Event::DropFiles);
ev.setFiles(files);
os::queue_event(ev);
}
#endif

View File

@ -1,25 +0,0 @@
// LAF OS Library
// Copyright (C) 2017-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_OSX_KEYS_H_INCLUDED
#define OS_OSX_KEYS_H_INCLUDED
#pragma once
#include "os/keys.h"
#include <Cocoa/Cocoa.h>
namespace os {
KeyScancode scancode_from_nsevent(NSEvent* event);
CFStringRef get_unicode_from_key_code(const UInt16 keyCode,
const NSEventModifierFlags modifierFlags,
UInt32* deadKeyState = nullptr);
}
#endif

View File

@ -1,433 +0,0 @@
// LAF OS Library
// Copyright (C) 2015-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
// Uncomment this to log how scancodes are generated
#define KEY_TRACE(...)
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "os/osx/keys.h"
#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h> // TIS functions
namespace os {
static KeyScancode from_char_to_scancode(int chr)
{
static KeyScancode map[] = {
kKeyNil, // 0 = 00 = NUL
kKeyNil, // 1 = 01 = STX
kKeyNil, // 2 = 02 = SOT
kKeyNil, // 3 = 03 = ETX
kKeyNil, // 4 = 04 = EOT
kKeyNil, // 5 = 05 = ENQ
kKeyNil, // 6 = 06 = ACK
kKeyNil, // 7 = 07 = BEL
kKeyBackspace, // 8 = 08 = BS
kKeyNil, // 9 = 09 = HT
kKeyNil, // 10 =0A = LF
kKeyNil, // 11 =0B = VT
kKeyNil, // 12 =0C = FF
kKeyNil, // 13 =0D = CR
kKeyNil, // 14 =0E = SO
kKeyNil, // 15 =0F = SI
kKeyNil, // 16 =10 = DLE
kKeyNil, // 17 =11 = DC1
kKeyNil, // 18 =12 = DC2
kKeyNil, // 19 =13 = DC3
kKeyNil, // 20 =14 = DC4
kKeyNil, // 21 =15 = NAK
kKeyNil, // 22 =16 = SYN
kKeyNil, // 23 =17 = ETB
kKeyNil, // 24 =18 = CAN
kKeyNil, // 25 =19 = EM
kKeyNil, // 26 =1A = SUB
kKeyNil, // 27 =1B = ESC
kKeyNil, // 28 =1C = FS
kKeyNil, // 29 =1D = GS
kKeyNil, // 30 =1E = RS
kKeyNil, // 31 =1F = US
kKeySpace, // 32 =20 = Space
kKeyNil, // 33 =21 = !
kKeyNil, // 34 =22 = "
kKeyNil, // 35 =23 = #
kKeyNil, // 36 =24 = $
kKeyNil, // 37 =25 = %
kKeyNil, // 38 =26 = &
kKeyQuote, // 39 =27 = '
kKeyNil, // 40 = 28 = (
kKeyNil, // 41 = 29 = )
kKeyNil, // 42 = 2A = *
kKeyNil, // 43 = 2B = +
kKeyComma, // 44 = 2C = ,
kKeyMinus, // 45 = 2D = -
kKeyStop, // 46 = 2E = .
kKeySlash, // 47 = 2F = /
kKey0, // 48 = 30 = 0
kKey1, // 49 = 31 = 1
kKey2, // 50 = 32 = 2
kKey3, // 51 = 33 = 3
kKey4, // 52 = 34 = 4
kKey5, // 53 = 35 = 5
kKey6, // 54 = 36 = 6
kKey7, // 55 = 37 = 7
kKey8, // 56 = 38 = 8
kKey9, // 57 = 39 = 9
kKeyColon, // 58 = 3A = :
kKeySemicolon, // 59 = 3B = ;
kKeyNil, // 60 = 3C = <
kKeyEquals, // 61 = 3D = =
kKeyNil, // 62 = 3E = >
kKeyNil, // 63 = 3F = ?
kKeyNil, // 64 = 40 = @
kKeyA, // 65 = 41 = A
kKeyB, // 66 = 42 = B
kKeyC, // 67 = 43 = C
kKeyD, // 68 = 44 = D
kKeyE, // 69 = 45 = E
kKeyF, // 70 = 46 = F
kKeyG, // 71 = 47 = G
kKeyH, // 72 = 48 = H
kKeyI, // 73 = 49 = I
kKeyJ, // 74 = 4A = J
kKeyK, // 75 = 4B = K
kKeyL, // 76 = 4C = L
kKeyM, // 77 = 4D = M
kKeyN, // 78 = 4E = N
kKeyO, // 79 = 4F = O
kKeyP, // 80 = 50 = P
kKeyQ, // 81 = 51 = Q
kKeyR, // 82 = 52 = R
kKeyS, // 83 = 53 = S
kKeyT, // 84 = 54 = T
kKeyU, // 85 = 55 = U
kKeyV, // 86 = 56 = V
kKeyW, // 87 = 57 = W
kKeyX, // 88 = 58 = X
kKeyY, // 89 = 59 = Y
kKeyZ, // 90 = 5A = Z
kKeyOpenbrace, // 91 = 5B = [
kKeyBackslash, // 92 = 5C = backslash
kKeyClosebrace, // 93 = 5D = ]
kKeyCircumflex, // 94 = 5E = ^
kKeyNil, // 95 = 5F = _
kKeyBackquote, // 96 = 60 = `
kKeyA, // 97 = 61 = a
kKeyB, // 98 = 62 = b
kKeyC, // 99 = 63 = c
kKeyD, // 100 = 64 = d
kKeyE, // 101 = 65 = e
kKeyF, // 102 = 66 = f
kKeyG, // 103 = 67 = g
kKeyH, // 104 = 68 = h
kKeyI, // 105 = 69 = i
kKeyJ, // 106 = 6A = j
kKeyK, // 107 = 6B = k
kKeyL, // 108 = 6C = l
kKeyM, // 109 = 6D = m
kKeyN, // 110 = 6E = n
kKeyO, // 111 = 6F = o
kKeyP, // 112 = 70 = p
kKeyQ, // 113 = 71 = q
kKeyR, // 114 = 72 = r
kKeyS, // 115 = 73 = s
kKeyT, // 116 = 74 = t
kKeyU, // 117 = 75 = u
kKeyV, // 118 = 76 = v
kKeyW, // 119 = 77 = w
kKeyX, // 120 = 78 = x
kKeyY, // 121 = 79 = y
kKeyZ, // 122 = 7A = z
kKeyOpenbrace, // 123 = 7B = {
kKeyBackslash, // 124 = 7C = |
kKeyClosebrace, // 125 = 7D = }
kKeyTilde, // 126 = 7E = ~
kKeyNil, // 127 = 7F = DEL
};
if (chr >= 0 && chr < sizeof(map) / sizeof(map[0])) {
// Converts an ASCII character into a os::KeyScancode
return map[chr];
}
else
return kKeyNil;
}
static KeyScancode from_keycode_to_scancode(UInt16 keyCode)
{
// Converts macOS virtual key code into a os::KeyScancode
static KeyScancode map[256] = {
// 0x00
kKeyA, // 0x00 - kVK_ANSI_A
kKeyS, // 0x01 - kVK_ANSI_S
kKeyD, // 0x02 - kVK_ANSI_D
kKeyF, // 0x03 - kVK_ANSI_F
kKeyH, // 0x04 - kVK_ANSI_H
kKeyG, // 0x05 - kVK_ANSI_G
kKeyZ, // 0x06 - kVK_ANSI_Z
kKeyX, // 0x07 - kVK_ANSI_X
kKeyC, // 0x08 - kVK_ANSI_C
kKeyV, // 0x09 - kVK_ANSI_V
kKeyNil, // 0x0A - kVK_ISO_Section
kKeyB, // 0x0B - kVK_ANSI_B
kKeyQ, // 0x0C - kVK_ANSI_Q
kKeyW, // 0x0D - kVK_ANSI_W
kKeyE, // 0x0E - kVK_ANSI_E
kKeyR, // 0x0F - kVK_ANSI_R
// 0x10
kKeyY, // 0x10 - kVK_ANSI_Y
kKeyT, // 0x11 - kVK_ANSI_T
kKey1, // 0x12 - kVK_ANSI_1
kKey2, // 0x13 - kVK_ANSI_2
kKey3, // 0x14 - kVK_ANSI_3
kKey4, // 0x15 - kVK_ANSI_4
kKey6, // 0x16 - kVK_ANSI_6
kKey5, // 0x17 - kVK_ANSI_5
kKeyEquals, // 0x18 - kVK_ANSI_Equal
kKey9, // 0x19 - kVK_ANSI_9
kKey7, // 0x1A - kVK_ANSI_7
kKeyMinus, // 0x1B - kVK_ANSI_Minus
kKey8, // 0x1C - kVK_ANSI_8
kKey0, // 0x1D - kVK_ANSI_0
kKeyClosebrace, // 0x1E - kVK_ANSI_RightBracket
kKeyO, // 0x1F - kVK_ANSI_O
// 0x20
kKeyU, // 0x20 - kVK_ANSI_U
kKeyOpenbrace, // 0x21 - kVK_ANSI_LeftBracket
kKeyI, // 0x22 - kVK_ANSI_I
kKeyP, // 0x23 - kVK_ANSI_P
kKeyEnter, // 0x24 - kVK_Return
kKeyL, // 0x25 - kVK_ANSI_L
kKeyJ, // 0x26 - kVK_ANSI_J
kKeyQuote, // 0x27 - kVK_ANSI_Quote
kKeyK, // 0x28 - kVK_ANSI_K
kKeySemicolon, // 0x29 - kVK_ANSI_Semicolon
kKeyBackslash, // 0x2A - kVK_ANSI_Backslash
kKeyComma, // 0x2B - kVK_ANSI_Comma
kKeySlash, // 0x2C - kVK_ANSI_Slash
kKeyN, // 0x2D - kVK_ANSI_N
kKeyM, // 0x2E - kVK_ANSI_M
kKeyStop, // 0x2F - kVK_ANSI_Period
// 0x30
kKeyTab, // 0x30 - kVK_Tab
kKeySpace, // 0x31 - kVK_Space
kKeyNil, // 0x32 - kVK_ANSI_Grave
kKeyBackspace, // 0x33 - kVK_Delete
kKeyNil, // 0x34 - ?
kKeyEsc, // 0x35 - kVK_Escape
kKeyNil, // 0x36 - ?
kKeyCommand, // 0x37 - kVK_Command
kKeyLShift, // 0x38 - kVK_Shift
kKeyCapsLock, // 0x39 - kVK_CapsLock
kKeyAlt, // 0x3A - kVK_Option
kKeyLControl, // 0x3B - kVK_Control
kKeyRShift, // 0x3C - kVK_RightShift
kKeyAltGr, // 0x3D - kVK_RightOption
kKeyRControl, // 0x3E - kVK_RightControl
kKeyNil, // 0x3F - kVK_Function
// 0x40
kKeyNil, // 0x40 - kVK_F17
kKeyNil, // 0x41 - kVK_ANSI_KeypadDecimal
kKeyNil, // 0x42 - ?
kKeyAsterisk, // 0x43 - kVK_ANSI_KeypadMultiply
kKeyNil, // 0x44 - ?
kKeyPlusPad, // 0x45 - kVK_ANSI_KeypadPlus
kKeyNil, // 0x46 - ?
kKeyDelPad, // 0x47 - kVK_ANSI_KeypadClear
kKeyNil, // 0x48 - kVK_VolumeUp
kKeyNil, // 0x49 - kVK_VolumeDown
kKeyNil, // 0x4A - kVK_Mute
kKeySlashPad, // 0x4B - kVK_ANSI_KeypadDivide
kKeyEnterPad, // 0x4C - kVK_ANSI_KeypadEnter
kKeyNil, // 0x4D - ?
kKeyMinusPad, // 0x4E - kVK_ANSI_KeypadMinus
kKeyNil, // 0x4F - kVK_F18
// 0x50
kKeyNil, // 0x50 - kVK_F19
kKeyEqualsPad, // 0x51 - kVK_ANSI_KeypadEquals
kKey0Pad, // 0x52 - kVK_ANSI_Keypad0
kKey1Pad, // 0x53 - kVK_ANSI_Keypad1
kKey2Pad, // 0x54 - kVK_ANSI_Keypad2
kKey3Pad, // 0x55 - kVK_ANSI_Keypad3
kKey4Pad, // 0x56 - kVK_ANSI_Keypad4
kKey5Pad, // 0x57 - kVK_ANSI_Keypad5
kKey6Pad, // 0x58 - kVK_ANSI_Keypad6
kKey7Pad, // 0x59 - kVK_ANSI_Keypad7
kKeyNil, // 0x5A - kVK_F20
kKey8Pad, // 0x5B - kVK_ANSI_Keypad8
kKey9Pad, // 0x5C - kVK_ANSI_Keypad9
kKeyYen, // 0x5D - kVK_JIS_Yen
kKeyNil, // 0x5E - kVK_JIS_Underscore
kKeyNil, // 0x5F - kVK_JIS_KeypadComma
// 0x60
kKeyF5, // 0x60 - kVK_F5
kKeyF6, // 0x61 - kVK_F6
kKeyF7, // 0x62 - kVK_F7
kKeyF3, // 0x63 - kVK_F3
kKeyF8, // 0x64 - kVK_F8
kKeyF9, // 0x65 - kVK_F9
kKeyNil, // 0x66 - kVK_JIS_Eisu
kKeyF11, // 0x67 - kVK_F11
kKeyKana, // 0x68 - kVK_JIS_Kana
kKeyNil, // 0x69 - kVK_F13
kKeyNil, // 0x6A - kVK_F16
kKeyNil, // 0x6B - kVK_F14
kKeyNil, // 0x6C - ?
kKeyF10, // 0x6D - kVK_F10
kKeyNil, // 0x6E - ?
kKeyF12, // 0x6F - kVK_F12
// 0x70
kKeyNil, // 0x70 - ?
kKeyNil, // 0x71 - kVK_F15
kKeyNil, // 0x72 - kVK_Help
kKeyHome, // 0x73 - kVK_Home
kKeyPageUp, // 0x74 - kVK_PageUp
kKeyDel, // 0x75 - kVK_ForwardDelete
kKeyF4, // 0x76 - kVK_F4
kKeyEnd, // 0x77 - kVK_End
kKeyF2, // 0x78 - kVK_F2
kKeyPageDown, // 0x79 - kVK_PageDown
kKeyF1, // 0x7A - kVK_F1
kKeyLeft, // 0x7B - kVK_LeftArrow
kKeyRight, // 0x7C - kVK_RightArrow
kKeyDown, // 0x7D - kVK_DownArrow
kKeyUp, // 0x7E - kVK_UpArrow
kKeyNil // 0x7F - ?
};
if (keyCode >= 0 && keyCode < sizeof(map) / sizeof(map[0])) {
// Converts macOS virtual key into a os::KeyScancode
return map[keyCode];
}
else
return kKeyNil;
}
KeyScancode scancode_from_nsevent(NSEvent* event)
{
#if 1
// For keys that are not in the numpad we try to get the scancode
// converting the first char in NSEvent.characters to a
// scancode.
if ((event.modifierFlags & NSEventModifierFlagNumericPad) == 0) {
KeyScancode code;
// It looks like getting the first "event.characters" char is the
// only way to get the correct Cmd+letter combination on "Dvorak -
// QWERTY Cmd" keyboard layout.
NSString* chars = event.characters;
if (chars.length > 0) {
int chr = [chars characterAtIndex:chars.length-1];
// Avoid activating space bar modifier. E.g. pressing
// Ctrl+Alt+Shift+S on "Spanish ISO" layout generates a
// whitespace ' ', and we prefer the S scancode instead of the
// space bar scancode.
if (chr != 32) {
code = from_char_to_scancode(chr);
if (code != kKeyNil) {
KEY_TRACE("scancode_from_nsevent %d -> %d (characters)\n",
(int)chr, (int)code);
return code;
}
}
}
chars = event.charactersIgnoringModifiers;
if (chars.length > 0) {
int chr = [chars characterAtIndex:chars.length-1];
code = from_char_to_scancode(chr);
if (code != kKeyNil) {
KEY_TRACE("scancode_from_nsevent %d -> %d (charactersIgnoringModifiers)\n",
(int)chr, (int)code);
return code;
}
}
}
#else // Don't use this code, it reports scancodes always as QWERTY
// and doesn't work for Dvorak or AZERTY layouts.
{
CFStringRef strRef = get_unicode_from_key_code(
event.keyCode,
event.modifierFlags & NSCommandKeyMask);
if (strRef) {
KeyScancode code = kKeyNil;
int length = CFStringGetLength(strRef);
if (length > 0) {
// Converts the first unicode char into a macOS virtual key
UInt16 chr = CFStringGetCharacterAtIndex(strRef, length-1);
code = from_char_to_scancode(chr);
if (code != kKeyNil) {
KEY_TRACE("scancode_from_nsevent %d -> %d (get_unicode_from_key_code)\n",
(int)chr, (int)code);
}
}
CFRelease(strRef);
if (code != kKeyNil) {
return code;
}
}
}
#endif
KeyScancode code = from_keycode_to_scancode(event.keyCode);
KEY_TRACE("scancode_from_nsevent %d -> %d (keyCode)\n",
(int)event.keyCode, (int)code);
return code;
}
// Based on code from:
// http://stackoverflow.com/questions/22566665/how-to-capture-unicode-from-key-events-without-an-nstextview
// http://stackoverflow.com/questions/12547007/convert-key-code-into-key-equivalent-string
// http://stackoverflow.com/questions/8263618/convert-virtual-key-code-to-unicode-string
//
// If "deadKeyState" is = nullptr, it doesn't process dead keys.
CFStringRef get_unicode_from_key_code(const UInt16 keyCode,
const NSEventModifierFlags modifierFlags,
UInt32* deadKeyState)
{
// The "TISCopyCurrentKeyboardInputSource()" doesn't contain
// kTISPropertyUnicodeKeyLayoutData (returns nullptr) when the input
// source is Japanese (Romaji/Hiragana/Katakana).
//TISInputSourceRef inputSource = TISCopyCurrentKeyboardInputSource();
TISInputSourceRef inputSource = TISCopyCurrentKeyboardLayoutInputSource();
CFDataRef keyLayoutData = (CFDataRef)TISGetInputSourceProperty(inputSource, kTISPropertyUnicodeKeyLayoutData);
const UCKeyboardLayout* keyLayout =
(keyLayoutData ? (const UCKeyboardLayout*)CFDataGetBytePtr(keyLayoutData): nullptr);
UInt32 deadKeyStateWrap = (deadKeyState ? *deadKeyState: 0);
UniChar output[4];
UniCharCount length;
// Reference here:
// https://developer.apple.com/reference/coreservices/1390584-uckeytranslate?language=objc
UCKeyTranslate(
keyLayout,
keyCode,
kUCKeyActionDown,
((modifierFlags >> 16) & 0xFF),
LMGetKbdType(),
(deadKeyState ? 0: kUCKeyTranslateNoDeadKeysMask),
&deadKeyStateWrap,
sizeof(output) / sizeof(output[0]),
&length,
output);
if (deadKeyState)
*deadKeyState = deadKeyStateWrap;
CFRelease(inputSource);
return CFStringCreateWithCharacters(kCFAllocatorDefault, output, length);
}
} // namespace os

View File

@ -1,25 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2014 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#include <CoreFoundation/CoreFoundation.h>
#include <Foundation/Foundation.h>
#include "os/logger.h"
namespace os {
class OSXLogger : public Logger {
public:
void logError(const char* error) override {
NSLog([NSString stringWithUTF8String:error]);
}
};
Logger* getOsxLogger() {
return new OSXLogger;
}
} // namespace os

View File

@ -1,25 +0,0 @@
// LAF OS Library
// Copyright (C) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_OSX_MENUS_H_INCLUDED
#define OS_OSX_MENUS_H_INCLUDED
#pragma once
#include "os/menus.h"
namespace os {
class MenusOSX : public Menus {
public:
MenusOSX();
Menu* createMenu() override;
MenuItem* createMenuItem(const MenuItemInfo& info) override;
void setAppMenu(Menu* menu) override;
};
} // namespace os
#endif

View File

@ -1,288 +0,0 @@
// LAF OS Library
// Copyright (C) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#include <Cocoa/Cocoa.h>
#include "base/debug.h"
#include "base/string.h"
#include "os/osx/menus.h"
#include "os/shortcut.h"
namespace os {
class MenuItemOSX;
}
@interface OSXNSMenu : NSMenu
- (BOOL)performKeyEquivalent:(NSEvent*)event;
@end
@interface OSXNSMenuItem : NSMenuItem {
os::MenuItemOSX* original;
}
+ (OSXNSMenuItem*)alloc:(os::MenuItemOSX*)original;
- (void)executeMenuItem:(id)sender;
- (void)validateMenuItem;
@end
namespace os {
extern bool g_keyEquivalentUsed;
class MenuItemOSX : public MenuItem {
public:
MenuItemOSX(const MenuItemInfo& info);
void dispose() override;
void setText(const std::string& text) override;
void setSubmenu(Menu* submenu) override;
void setEnabled(bool state) override;
void setChecked(bool state) override;
void setShortcut(const Shortcut& shortcut) override;
NSMenuItem* handle() { return m_handle; }
// Called by OSXNSMenuItem.executeMenuItem
void execute();
void validate();
private:
void syncTitle();
NSMenuItem* m_handle;
Menu* m_submenu;
std::function<void()> m_execute;
std::function<void(os::MenuItem*)> m_validate;
};
class MenuOSX : public Menu {
public:
MenuOSX();
void dispose() override;
void addItem(MenuItem* item) override;
void insertItem(const int index, MenuItem* item) override;
NSMenu* handle() { return m_handle; }
private:
NSMenu* m_handle;
};
} // namespace os
@implementation OSXNSMenu
- (BOOL)performKeyEquivalent:(NSEvent*)event
{
BOOL result = [super performKeyEquivalent:event];
if (result)
os::g_keyEquivalentUsed = true;
return result;
}
@end
@implementation OSXNSMenuItem
+ (OSXNSMenuItem*)alloc:(os::MenuItemOSX*)original
{
OSXNSMenuItem* item = [super alloc];
item->original = original;
return item;
}
- (void)executeMenuItem:(id)sender
{
original->execute();
}
- (void)validateMenuItem
{
original->validate();
}
@end
namespace os {
MenuItemOSX::MenuItemOSX(const MenuItemInfo& info)
: m_handle(nullptr)
, m_submenu(nullptr)
{
switch (info.type) {
case MenuItemInfo::Normal: {
SEL sel = nil;
id target = nil;
switch (info.action) {
case MenuItemInfo::UserDefined:
sel = @selector(executeMenuItem:);
// TODO this is strange, it doesn't work, we receive the
// message in OSXAppDelegate anyway. So
// OSXAppDelegate.executeMenuItem: will redirect the message
// to OSXNSMenuItem.executeMenuItem:
target = m_handle;
break;
case MenuItemInfo::Hide:
sel = @selector(hide:);
break;
case MenuItemInfo::HideOthers:
sel = @selector(hideOtherApplications:);
break;
case MenuItemInfo::ShowAll:
sel = @selector(unhideAllApplications:);
break;
case MenuItemInfo::Quit:
sel = @selector(terminate:);
break;
case MenuItemInfo::Minimize:
sel = @selector(performMiniaturize:);
break;
case MenuItemInfo::Zoom:
sel = @selector(performZoom:);
break;
}
m_handle =
[[OSXNSMenuItem alloc:this]
initWithTitle:[NSString stringWithUTF8String:info.text.c_str()]
action:sel
keyEquivalent:@""];
m_handle.target = target;
m_execute = info.execute;
m_validate = info.validate;
if (!info.shortcut.isEmpty())
setShortcut(info.shortcut);
break;
}
case MenuItemInfo::Separator:
m_handle = [NSMenuItem separatorItem];
break;
}
}
void MenuItemOSX::dispose()
{
delete this;
}
void MenuItemOSX::setText(const std::string& text)
{
[m_handle setTitle:[NSString stringWithUTF8String:text.c_str()]];
syncTitle();
}
void MenuItemOSX::setSubmenu(Menu* submenu)
{
m_submenu = submenu;
if (submenu) {
[m_handle setSubmenu:((MenuOSX*)submenu)->handle()];
syncTitle();
}
else
[m_handle setSubmenu:nil];
}
void MenuItemOSX::setEnabled(bool state)
{
m_handle.enabled = state;
}
void MenuItemOSX::setChecked(bool state)
{
if (state)
m_handle.state = NSOnState;
else
m_handle.state = NSOffState;
}
void MenuItemOSX::setShortcut(const Shortcut& shortcut)
{
KeyModifiers mods = shortcut.modifiers();
NSEventModifierFlags nsFlags = 0;
if (mods & kKeyShiftModifier) nsFlags |= NSEventModifierFlagShift;
if (mods & kKeyCtrlModifier) nsFlags |= NSEventModifierFlagControl;
if (mods & kKeyAltModifier) nsFlags |= NSEventModifierFlagOption;
if (mods & kKeyCmdModifier) nsFlags |= NSEventModifierFlagCommand;
NSString* keyStr;
if (shortcut.unicode()) {
unichar chr = shortcut.unicode();
keyStr = [NSString stringWithCharacters:&chr length:1];
}
else
keyStr = @"";
m_handle.keyEquivalent = keyStr;
m_handle.keyEquivalentModifierMask = nsFlags;
}
void MenuItemOSX::execute()
{
if (m_execute)
m_execute();
}
void MenuItemOSX::validate()
{
if (m_validate)
m_validate(this);
}
void MenuItemOSX::syncTitle()
{
// On macOS the submenu title is the one that is displayed in the
// UI instead of the MenuItem title (so here we copy the menu item
// title to the submenu title)
if (m_submenu)
[((MenuOSX*)m_submenu)->handle() setTitle:m_handle.title];
}
MenuOSX::MenuOSX()
{
m_handle = [[OSXNSMenu alloc] init];
}
void MenuOSX::dispose()
{
delete this;
}
void MenuOSX::addItem(MenuItem* item)
{
ASSERT(item);
[m_handle addItem:((MenuItemOSX*)item)->handle()];
}
void MenuOSX::insertItem(const int index, MenuItem* item)
{
ASSERT(item);
[m_handle insertItem:((MenuItemOSX*)item)->handle()
atIndex:index];
}
MenusOSX::MenusOSX()
{
}
Menu* MenusOSX::createMenu()
{
return new MenuOSX;
}
MenuItem* MenusOSX::createMenuItem(const MenuItemInfo& info)
{
return new MenuItemOSX(info);
}
void MenusOSX::setAppMenu(Menu* menu)
{
if (menu)
[NSApp setMainMenu:((MenuOSX*)menu)->handle()];
else
[NSApp setMainMenu:nil];
}
} // namespace os

View File

@ -1,23 +0,0 @@
// LAF OS Library
// Copyright (C) 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_OSX_NATIVE_DIALOGS_H_INCLUDED
#define OS_OSX_NATIVE_DIALOGS_H_INCLUDED
#pragma once
#include "os/native_dialogs.h"
namespace os {
class NativeDialogsOSX : public NativeDialogs {
public:
NativeDialogsOSX();
FileDialog* createFileDialog() override;
};
} // namespace os
#endif

View File

@ -1,174 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#include <Cocoa/Cocoa.h>
#include <vector>
#include "base/fs.h"
#include "os/common/file_dialog.h"
#include "os/display.h"
#include "os/keys.h"
#include "os/native_cursor.h"
#include "os/osx/native_dialogs.h"
@interface OpenSaveHelper : NSObject {
@private
NSSavePanel* panel;
os::Display* display;
int result;
}
- (id)init;
- (void)setPanel:(NSSavePanel*)panel;
- (void)setDisplay:(os::Display*)display;
- (void)runModal;
- (int)result;
@end
@implementation OpenSaveHelper
- (id)init
{
if (self = [super init]) {
result = NSFileHandlingPanelCancelButton;
}
return self;
}
- (void)setPanel:(NSSavePanel*)newPanel
{
panel = newPanel;
}
- (void)setDisplay:(os::Display*)newDisplay
{
display = newDisplay;
}
// This is executed in the main thread.
- (void)runModal
{
os::NativeCursor oldCursor = display->nativeMouseCursor();
display->setNativeMouseCursor(os::kArrowCursor);
#ifndef __MAC_10_6 // runModalForTypes is deprecated in 10.6
if ([panel isKindOfClass:[NSOpenPanel class]]) {
// As we're using OS X 10.4 framework, it looks like runModal
// doesn't recognize the allowedFileTypes property. So we force it
// using runModalForTypes: selector.
result = [(NSOpenPanel*)panel runModalForTypes:[panel allowedFileTypes]];
}
else
#endif
{
result = [panel runModal];
}
display->setNativeMouseCursor(oldCursor);
}
- (int)result
{
return result;
}
@end
namespace os {
class FileDialogOSX : public CommonFileDialog {
public:
FileDialogOSX() {
}
std::string fileName() override {
return m_filename;
}
void getMultipleFileNames(base::paths& output) override {
output = m_filenames;
}
void setFileName(const std::string& filename) override {
m_filename = filename;
}
bool show(Display* display) override {
bool retValue = false;
@autoreleasepool {
NSSavePanel* panel = nil;
if (m_type == Type::SaveFile) {
panel = [NSSavePanel new];
}
else {
panel = [NSOpenPanel new];
[(NSOpenPanel*)panel setAllowsMultipleSelection:(m_type == Type::OpenFiles ? YES: NO)];
[(NSOpenPanel*)panel setCanChooseFiles:(m_type != Type::OpenFolder ? YES: NO)];
[(NSOpenPanel*)panel setCanChooseDirectories:(m_type == Type::OpenFolder ? YES: NO)];
}
[panel setTitle:[NSString stringWithUTF8String:m_title.c_str()]];
[panel setCanCreateDirectories:YES];
std::string defPath = base::get_file_path(m_filename);
std::string defName = base::get_file_name(m_filename);
if (!defPath.empty())
[panel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:defPath.c_str()]]];
if (!defName.empty())
[panel setNameFieldStringValue:[NSString stringWithUTF8String:defName.c_str()]];
if (m_type != Type::OpenFolder && !m_filters.empty()) {
NSMutableArray* types = [[NSMutableArray alloc] init];
// The first extension in the array is used as the default one.
if (!m_defExtension.empty())
[types addObject:[NSString stringWithUTF8String:m_defExtension.c_str()]];
for (const auto& filter : m_filters)
[types addObject:[NSString stringWithUTF8String:filter.first.c_str()]];
[panel setAllowedFileTypes:types];
if (m_type == Type::SaveFile)
[panel setAllowsOtherFileTypes:NO];
}
OpenSaveHelper* helper = [OpenSaveHelper new];
[helper setPanel:panel];
[helper setDisplay:display];
[helper performSelectorOnMainThread:@selector(runModal) withObject:nil waitUntilDone:YES];
if ([helper result] == NSFileHandlingPanelOKButton) {
if (m_type == Type::OpenFiles) {
for (NSURL* url in [(NSOpenPanel*)panel URLs]) {
m_filename = [[url path] UTF8String];
m_filenames.push_back(m_filename);
}
}
else {
NSURL* url = [panel URL];
m_filename = [[url path] UTF8String];
m_filenames.push_back(m_filename);
}
retValue = true;
}
}
return retValue;
}
private:
std::string m_filename;
base::paths m_filenames;
};
NativeDialogsOSX::NativeDialogsOSX()
{
}
FileDialog* NativeDialogsOSX::createFileDialog()
{
return new FileDialogOSX();
}
} // namespace os

View File

@ -1,31 +0,0 @@
// LAF OS Library
// Copyright (C) 2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_OSX_SYSTEM_H
#define OS_OSX_SYSTEM_H
#pragma once
#include "os/common/system.h"
namespace os {
bool osx_is_key_pressed(KeyScancode scancode);
int osx_get_unicode_from_scancode(KeyScancode scancode);
class OSXSystem : public CommonSystem {
public:
bool isKeyPressed(KeyScancode scancode) override {
return osx_is_key_pressed(scancode);
}
int getUnicodeFromScancode(KeyScancode scancode) override {
return osx_get_unicode_from_scancode(scancode);
}
};
} // namespace os
#endif

View File

@ -1,60 +0,0 @@
// LAF OS Library
// Copyright (C) 2015-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_OSX_VIEW_H_INCLUDED
#define OS_OSX_VIEW_H_INCLUDED
#pragma once
#include "os/pointer_type.h"
#include <Cocoa/Cocoa.h>
@interface OSXView : NSView {
@private
NSTrackingArea* m_trackingArea;
NSCursor* m_nsCursor;
bool m_visibleMouse;
os::PointerType m_pointerType;
}
- (id)initWithFrame:(NSRect)frameRect;
- (BOOL)acceptsFirstResponder;
- (void)viewDidHide;
- (void)viewDidUnhide;
- (void)viewDidMoveToWindow;
- (void)drawRect:(NSRect)dirtyRect;
- (void)keyDown:(NSEvent*)event;
- (void)keyUp:(NSEvent*)event;
- (void)flagsChanged:(NSEvent*)event;
+ (void)updateKeyFlags:(NSEvent*)event;
- (void)mouseEntered:(NSEvent*)event;
- (void)mouseMoved:(NSEvent*)event;
- (void)mouseExited:(NSEvent*)event;
- (void)mouseDown:(NSEvent*)event;
- (void)mouseUp:(NSEvent*)event;
- (void)mouseDragged:(NSEvent*)event;
- (void)rightMouseDown:(NSEvent*)event;
- (void)rightMouseUp:(NSEvent*)event;
- (void)rightMouseDragged:(NSEvent*)event;
- (void)otherMouseDown:(NSEvent*)event;
- (void)otherMouseUp:(NSEvent*)event;
- (void)otherMouseDragged:(NSEvent*)event;
- (void)handleMouseDown:(NSEvent*)event;
- (void)handleMouseUp:(NSEvent*)event;
- (void)handleMouseDragged:(NSEvent*)event;
- (void)scrollWheel:(NSEvent*)event;
- (void)cursorUpdate:(NSEvent*)event;
- (void)setCursor:(NSCursor*)cursor;
- (void)setFrameSize:(NSSize)newSize;
- (void)createMouseTrackingArea;
- (void)destroyMouseTrackingArea;
- (void)updateCurrentCursor;
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender;
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender;
- (void)doCommandBySelector:(SEL)selector;
- (void)setTranslateDeadKeys:(BOOL)state;
@end
#endif

View File

@ -1,585 +0,0 @@
// LAF OS Library
// Copyright (C) 2015-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#define KEY_TRACE(...)
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "os/osx/view.h"
#include "gfx/point.h"
#include "os/event.h"
#include "os/event_queue.h"
#include "os/osx/generate_drop_files.h"
#include "os/osx/keys.h"
#include "os/osx/window.h"
#include "os/system.h"
namespace os {
// Global variable used between View and OSXNSMenu to check if the
// keyDown: event was used by a key equivalent in the menu.
//
// TODO I'm not proud of this, but it does the job
bool g_keyEquivalentUsed = false;
bool osx_is_key_pressed(KeyScancode scancode);
namespace {
// Internal array of pressed keys used in isKeyPressed()
int g_pressedKeys[kKeyScancodes];
bool g_translateDeadKeys = false;
UInt32 g_lastDeadKeyState = 0;
gfx::Point get_local_mouse_pos(NSView* view, NSEvent* event)
{
NSPoint point = [view convertPoint:[event locationInWindow]
fromView:nil];
int scale = 1;
if ([view window])
scale = [(OSXWindow*)[view window] scale];
// "os" layer coordinates expect (X,Y) origin at the top-left corner.
return gfx::Point(point.x / scale,
(view.bounds.size.height - point.y) / scale);
}
Event::MouseButton get_mouse_buttons(NSEvent* event)
{
// Some Wacom drivers on OS X report right-clicks with
// buttonNumber=0, so we've to check the type event anyway.
switch (event.type) {
case NSEventTypeLeftMouseDown:
case NSEventTypeLeftMouseUp:
case NSEventTypeLeftMouseDragged:
return Event::LeftButton;
case NSEventTypeRightMouseDown:
case NSEventTypeRightMouseUp:
case NSEventTypeRightMouseDragged:
return Event::RightButton;
}
switch (event.buttonNumber) {
case 0: return Event::LeftButton; break;
case 1: return Event::RightButton; break;
case 2: return Event::MiddleButton; break;
// NSOtherMouseDown/Up/Dragged
case 3: return Event::X1Button; break;
case 4: return Event::X2Button; break;
}
return Event::MouseButton::NoneButton;
}
KeyModifiers get_modifiers_from_nsevent(NSEvent* event)
{
int modifiers = kKeyNoneModifier;
NSEventModifierFlags nsFlags = event.modifierFlags;
if (nsFlags & NSEventModifierFlagShift) modifiers |= kKeyShiftModifier;
if (nsFlags & NSEventModifierFlagControl) modifiers |= kKeyCtrlModifier;
if (nsFlags & NSEventModifierFlagOption) modifiers |= kKeyAltModifier;
if (nsFlags & NSEventModifierFlagCommand) modifiers |= kKeyCmdModifier;
if (osx_is_key_pressed(kKeySpace)) modifiers |= kKeySpaceModifier;
return (KeyModifiers)modifiers;
}
} // anonymous namespace
bool osx_is_key_pressed(KeyScancode scancode)
{
if (scancode >= 0 && scancode < kKeyScancodes)
return (g_pressedKeys[scancode] != 0);
else
return false;
}
int osx_get_unicode_from_scancode(KeyScancode scancode)
{
if (scancode >= 0 && scancode < kKeyScancodes)
return g_pressedKeys[scancode];
else
return 0;
}
} // namespace os
using namespace os;
@implementation OSXView
- (id)initWithFrame:(NSRect)frameRect
{
// We start without the system mouse cursor
m_nsCursor = nil;
m_visibleMouse = true;
m_pointerType = os::PointerType::Unknown;
self = [super initWithFrame:frameRect];
if (self != nil) {
[self createMouseTrackingArea];
[self registerForDraggedTypes:
[NSArray arrayWithObjects:
NSFilenamesPboardType,
nil]];
}
return self;
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (void)viewDidHide
{
[super viewDidHide];
[self destroyMouseTrackingArea];
}
- (void)viewDidUnhide
{
[super viewDidUnhide];
[self createMouseTrackingArea];
}
- (void)viewDidMoveToWindow
{
[super viewDidMoveToWindow];
if ([self window]) {
OSXWindowImpl* impl = [((OSXWindow*)[self window]) impl];
if (impl)
impl->onWindowChanged();
}
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
if ([self window]) {
OSXWindowImpl* impl = [((OSXWindow*)[self window]) impl];
if (impl)
impl->onDrawRect(gfx::Rect(dirtyRect.origin.x,
dirtyRect.origin.y,
dirtyRect.size.width,
dirtyRect.size.height));
}
}
- (void)keyDown:(NSEvent*)event
{
g_keyEquivalentUsed = false;
[super keyDown:event];
// If a key equivalent used the keyDown event, we don't generate
// this os::KeyDown event.
if (g_keyEquivalentUsed)
return;
KeyScancode scancode = scancode_from_nsevent(event);
Event ev;
ev.setType(Event::KeyDown);
ev.setScancode(scancode);
ev.setModifiers(get_modifiers_from_nsevent(event));
ev.setRepeat(event.ARepeat ? 1: 0);
ev.setUnicodeChar(0);
bool sendMsg = true;
CFStringRef strRef = get_unicode_from_key_code(event.keyCode,
event.modifierFlags);
if (strRef) {
int length = CFStringGetLength(strRef);
if (length == 1)
ev.setUnicodeChar(CFStringGetCharacterAtIndex(strRef, 0));
CFRelease(strRef);
}
if (scancode >= 0 && scancode < kKeyScancodes)
g_pressedKeys[scancode] = (ev.unicodeChar() ? ev.unicodeChar(): 1);
if (g_translateDeadKeys) {
strRef = get_unicode_from_key_code(event.keyCode,
event.modifierFlags,
&g_lastDeadKeyState);
if (strRef) {
int length = CFStringGetLength(strRef);
if (length > 0) {
sendMsg = false;
for (int i=0; i<length; ++i) {
ev.setUnicodeChar(CFStringGetCharacterAtIndex(strRef, i));
queue_event(ev);
}
g_lastDeadKeyState = 0;
}
else {
ev.setDeadKey(true);
}
CFRelease(strRef);
}
}
KEY_TRACE("View keyDown: unicode=%d (%c) scancode=%d modifiers=%d\n",
ev.unicodeChar(), ev.unicodeChar(),
ev.scancode(), ev.modifiers());
if (sendMsg)
queue_event(ev);
}
- (void)keyUp:(NSEvent*)event
{
[super keyUp:event];
KeyScancode scancode = scancode_from_nsevent(event);
if (scancode >= 0 && scancode < kKeyScancodes)
g_pressedKeys[scancode] = 0;
Event ev;
ev.setType(Event::KeyUp);
ev.setScancode(scancode);
ev.setModifiers(get_modifiers_from_nsevent(event));
ev.setRepeat(event.ARepeat ? 1: 0);
ev.setUnicodeChar(0);
queue_event(ev);
}
- (void)flagsChanged:(NSEvent*)event
{
[super flagsChanged:event];
[OSXView updateKeyFlags:event];
}
+ (void)updateKeyFlags:(NSEvent*)event
{
static int lastFlags = 0;
static int flags[] = {
NSEventModifierFlagShift,
NSEventModifierFlagControl,
NSEventModifierFlagOption,
NSEventModifierFlagCommand
};
static KeyScancode scancodes[] = {
kKeyLShift,
kKeyLControl,
kKeyAlt,
kKeyCommand
};
KeyModifiers modifiers = get_modifiers_from_nsevent(event);
int newFlags = event.modifierFlags;
for (int i=0; i<sizeof(flags)/sizeof(flags[0]); ++i) {
if ((lastFlags & flags[i]) != (newFlags & flags[i])) {
Event ev;
ev.setType(
((newFlags & flags[i]) != 0 ? Event::KeyDown:
Event::KeyUp));
g_pressedKeys[scancodes[i]] = ((newFlags & flags[i]) != 0);
ev.setScancode(scancodes[i]);
ev.setModifiers(modifiers);
ev.setRepeat(0);
queue_event(ev);
}
}
lastFlags = newFlags;
}
- (void)mouseEntered:(NSEvent*)event
{
[self updateCurrentCursor];
Event ev;
ev.setType(Event::MouseEnter);
ev.setPosition(get_local_mouse_pos(self, event));
ev.setModifiers(get_modifiers_from_nsevent(event));
queue_event(ev);
}
- (void)mouseMoved:(NSEvent*)event
{
Event ev;
ev.setType(Event::MouseMove);
ev.setPosition(get_local_mouse_pos(self, event));
ev.setModifiers(get_modifiers_from_nsevent(event));
if (m_pointerType != os::PointerType::Unknown)
ev.setPointerType(m_pointerType);
queue_event(ev);
}
- (void)mouseExited:(NSEvent*)event
{
// Restore arrow cursor
if (!m_visibleMouse) {
m_visibleMouse = true;
[NSCursor unhide];
}
[[NSCursor arrowCursor] set];
Event ev;
ev.setType(Event::MouseLeave);
ev.setPosition(get_local_mouse_pos(self, event));
ev.setModifiers(get_modifiers_from_nsevent(event));
queue_event(ev);
}
- (void)mouseDown:(NSEvent*)event
{
[self handleMouseDown:event];
}
- (void)mouseUp:(NSEvent*)event
{
[self handleMouseUp:event];
}
- (void)mouseDragged:(NSEvent*)event
{
[self handleMouseDragged:event];
}
- (void)rightMouseDown:(NSEvent*)event
{
[self handleMouseDown:event];
}
- (void)rightMouseUp:(NSEvent*)event
{
[self handleMouseUp:event];
}
- (void)rightMouseDragged:(NSEvent*)event
{
[self handleMouseDragged:event];
}
- (void)otherMouseDown:(NSEvent*)event
{
[self handleMouseDown:event];
}
- (void)otherMouseUp:(NSEvent*)event
{
[self handleMouseUp:event];
}
- (void)otherMouseDragged:(NSEvent*)event
{
[self handleMouseDragged:event];
}
- (void)handleMouseDown:(NSEvent*)event
{
Event ev;
ev.setType(event.clickCount == 2 ? Event::MouseDoubleClick:
Event::MouseDown);
ev.setPosition(get_local_mouse_pos(self, event));
ev.setButton(get_mouse_buttons(event));
ev.setModifiers(get_modifiers_from_nsevent(event));
if (m_pointerType != os::PointerType::Unknown)
ev.setPointerType(m_pointerType);
queue_event(ev);
}
- (void)handleMouseUp:(NSEvent*)event
{
Event ev;
ev.setType(Event::MouseUp);
ev.setPosition(get_local_mouse_pos(self, event));
ev.setButton(get_mouse_buttons(event));
ev.setModifiers(get_modifiers_from_nsevent(event));
if (m_pointerType != os::PointerType::Unknown)
ev.setPointerType(m_pointerType);
queue_event(ev);
}
- (void)handleMouseDragged:(NSEvent*)event
{
Event ev;
ev.setType(Event::MouseMove);
ev.setPosition(get_local_mouse_pos(self, event));
ev.setButton(get_mouse_buttons(event));
ev.setModifiers(get_modifiers_from_nsevent(event));
if (m_pointerType != os::PointerType::Unknown)
ev.setPointerType(m_pointerType);
queue_event(ev);
}
- (void)setFrameSize:(NSSize)newSize
{
[super setFrameSize:newSize];
// Re-create the mouse tracking area
[self destroyMouseTrackingArea];
[self createMouseTrackingArea];
// Call OSXWindowImpl::onResize handler
if ([self window]) {
OSXWindowImpl* impl = [((OSXWindow*)[self window]) impl];
if (impl)
impl->onResize(gfx::Size(newSize.width,
newSize.height));
}
}
- (void)scrollWheel:(NSEvent*)event
{
Event ev;
ev.setType(Event::MouseWheel);
ev.setPosition(get_local_mouse_pos(self, event));
ev.setButton(get_mouse_buttons(event));
ev.setModifiers(get_modifiers_from_nsevent(event));
int scale = 1;
if (self.window)
scale = [(OSXWindow*)self.window scale];
if (event.hasPreciseScrollingDeltas) {
ev.setPointerType(os::PointerType::Touchpad);
ev.setWheelDelta(gfx::Point(-event.scrollingDeltaX / scale,
-event.scrollingDeltaY / scale));
ev.setPreciseWheel(true);
}
else {
// Ignore the acceleration factor, just use the wheel sign.
gfx::Point pt(0, 0);
if (event.scrollingDeltaX >= 0.1)
pt.x = -1;
else if (event.scrollingDeltaX <= -0.1)
pt.x = 1;
if (event.scrollingDeltaY >= 0.1)
pt.y = -1;
else if (event.scrollingDeltaY <= -0.1)
pt.y = 1;
ev.setPointerType(os::PointerType::Mouse);
ev.setWheelDelta(pt);
}
queue_event(ev);
}
- (void)magnifyWithEvent:(NSEvent*)event
{
Event ev;
ev.setType(Event::TouchMagnify);
ev.setMagnification(event.magnification);
ev.setPosition(get_local_mouse_pos(self, event));
ev.setModifiers(get_modifiers_from_nsevent(event));
ev.setPointerType(os::PointerType::Touchpad);
queue_event(ev);
}
- (void)tabletProximity:(NSEvent*)event
{
if (event.isEnteringProximity == YES) {
switch (event.pointingDeviceType) {
case NSPointingDeviceTypePen: m_pointerType = os::PointerType::Pen; break;
case NSPointingDeviceTypeCursor: m_pointerType = os::PointerType::Cursor; break;
case NSPointingDeviceTypeEraser: m_pointerType = os::PointerType::Eraser; break;
default:
m_pointerType = os::PointerType::Unknown;
break;
}
}
else {
m_pointerType = os::PointerType::Unknown;
}
}
- (void)cursorUpdate:(NSEvent*)event
{
[self updateCurrentCursor];
}
- (void)setCursor:(NSCursor*)cursor
{
m_nsCursor = cursor;
[self updateCurrentCursor];
}
- (void)createMouseTrackingArea
{
// Create a tracking area to receive mouseMoved events
m_trackingArea =
[[NSTrackingArea alloc]
initWithRect:self.bounds
options:(NSTrackingMouseEnteredAndExited |
NSTrackingMouseMoved |
NSTrackingActiveAlways |
NSTrackingEnabledDuringMouseDrag)
owner:self
userInfo:nil];
[self addTrackingArea:m_trackingArea];
}
- (void)destroyMouseTrackingArea
{
[self removeTrackingArea:m_trackingArea];
m_trackingArea = nil;
}
- (void)updateCurrentCursor
{
if (m_nsCursor) {
if (!m_visibleMouse) {
m_visibleMouse = true;
[NSCursor unhide];
}
[m_nsCursor set];
}
else if (m_visibleMouse) {
m_visibleMouse = false;
[NSCursor hide];
}
}
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
{
return NSDragOperationCopy;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
NSPasteboard* pasteboard = [sender draggingPasteboard];
if ([pasteboard.types containsObject:NSFilenamesPboardType]) {
NSArray* filenames = [pasteboard propertyListForType:NSFilenamesPboardType];
generate_drop_files_from_nsarray(filenames);
return YES;
}
else
return NO;
}
- (void)doCommandBySelector:(SEL)selector
{
// Do nothing (avoid beep pressing Escape key)
}
- (void)setTranslateDeadKeys:(BOOL)state
{
g_translateDeadKeys = (state ? true: false);
g_lastDeadKeyState = 0;
}
@end

View File

@ -1,56 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_OSX_WINDOW_H_INCLUDED
#define OS_OSX_WINDOW_H_INCLUDED
#pragma once
#include <Cocoa/Cocoa.h>
#include "gfx/point.h"
#include "gfx/rect.h"
#include "gfx/size.h"
#include "os/keys.h"
#include "os/native_cursor.h"
namespace os {
class Surface;
}
class OSXWindowImpl {
public:
virtual ~OSXWindowImpl() { }
virtual void onClose() = 0;
virtual void onResize(const gfx::Size& size) = 0;
virtual void onDrawRect(const gfx::Rect& rect) = 0;
virtual void onWindowChanged() = 0;
};
@class OSXWindowDelegate;
@interface OSXWindow : NSWindow {
@private
OSXWindowImpl* m_impl;
OSXWindowDelegate* m_delegate;
int m_scale;
}
- (OSXWindow*)initWithImpl:(OSXWindowImpl*)impl
width:(int)width
height:(int)height
scale:(int)scale;
- (OSXWindowImpl*)impl;
- (int)scale;
- (void)setScale:(int)scale;
- (gfx::Size)clientSize;
- (gfx::Size)restoredSize;
- (void)setMousePosition:(const gfx::Point&)position;
- (BOOL)setNativeMouseCursor:(os::NativeCursor)cursor;
- (BOOL)setNativeMouseCursor:(const os::Surface*)surface
focus:(const gfx::Point&)focus
scale:(const int)scale;
@end
#endif

View File

@ -1,242 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "os/osx/window.h"
#include "base/debug.h"
#include "os/event.h"
#include "os/osx/event_queue.h"
#include "os/osx/view.h"
#include "os/osx/window_delegate.h"
#include "os/surface.h"
using namespace os;
@implementation OSXWindow
- (OSXWindow*)initWithImpl:(OSXWindowImpl*)impl
width:(int)width
height:(int)height
scale:(int)scale
{
m_impl = impl;
m_scale = scale;
NSRect rect = NSMakeRect(0, 0, width, height);
self = [self initWithContentRect:rect
styleMask:(NSWindowStyleMaskTitled |
NSWindowStyleMaskClosable |
NSWindowStyleMaskMiniaturizable |
NSWindowStyleMaskResizable)
backing:NSBackingStoreBuffered
defer:NO];
if (!self)
return nil;
m_delegate = [[OSXWindowDelegate alloc] initWithWindowImpl:impl];
// The NSView width and height will be a multiple of 4. In this way
// all scaled pixels should be exactly the same
// for Screen Scaling > 1 and <= 4)
self.contentResizeIncrements = NSMakeSize(4, 4);
OSXView* view = [[OSXView alloc] initWithFrame:rect];
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[self setDelegate:m_delegate];
[self setContentView:view];
[self center];
[self makeKeyAndOrderFront:self];
// Hide the "View > Show Tab Bar" menu item
if ([self respondsToSelector:@selector(setTabbingMode:)])
[self setTabbingMode:NSWindowTabbingModeDisallowed];
return self;
}
- (OSXWindowImpl*)impl
{
return m_impl;
}
- (int)scale
{
return m_scale;
}
- (void)setScale:(int)scale
{
m_scale = scale;
if (m_impl) {
NSRect bounds = [[self contentView] bounds];
m_impl->onResize(gfx::Size(bounds.size.width,
bounds.size.height));
}
}
- (gfx::Size)clientSize
{
return gfx::Size([[self contentView] frame].size.width,
[[self contentView] frame].size.height);
}
- (gfx::Size)restoredSize
{
return [self clientSize];
}
- (void)setMousePosition:(const gfx::Point&)position
{
NSView* view = self.contentView;
NSPoint pt = NSMakePoint(
position.x*m_scale,
view.frame.size.height - position.y*m_scale);
pt = [view convertPoint:pt toView:view];
pt = [view convertPoint:pt toView:nil];
pt = [self convertBaseToScreen:pt];
pt.y = [[self screen] frame].size.height - pt.y;
CGPoint pos = CGPointMake(pt.x, pt.y);
CGEventRef event = CGEventCreateMouseEvent(
NULL, kCGEventMouseMoved, pos, kCGMouseButtonLeft);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
}
- (BOOL)setNativeMouseCursor:(NativeCursor)cursor
{
NSCursor* nsCursor = nullptr;
switch (cursor) {
case kArrowCursor:
case kWaitCursor:
case kHelpCursor:
case kSizeNECursor:
case kSizeNWCursor:
case kSizeSECursor:
case kSizeSWCursor:
nsCursor = [NSCursor arrowCursor];
break;
case kCrosshairCursor:
nsCursor = [NSCursor crosshairCursor];
break;
case kIBeamCursor:
nsCursor = [NSCursor IBeamCursor];
break;
case kLinkCursor:
nsCursor = [NSCursor pointingHandCursor];
break;
case kForbiddenCursor:
nsCursor = [NSCursor operationNotAllowedCursor];
break;
case kMoveCursor:
nsCursor = [NSCursor openHandCursor];
break;
case kSizeNSCursor:
nsCursor = [NSCursor resizeUpDownCursor];
break;
case kSizeWECursor:
nsCursor = [NSCursor resizeLeftRightCursor];
break;
case kSizeNCursor:
nsCursor = [NSCursor resizeUpCursor];
break;
case kSizeECursor:
nsCursor = [NSCursor resizeRightCursor];
break;
case kSizeSCursor:
nsCursor = [NSCursor resizeDownCursor];
break;
case kSizeWCursor:
nsCursor = [NSCursor resizeLeftCursor];
break;
}
[self.contentView setCursor:nsCursor];
return (nsCursor ? YES: NO);
}
- (BOOL)setNativeMouseCursor:(const os::Surface*)surface
focus:(const gfx::Point&)focus
scale:(const int)scale
{
ASSERT(surface);
SurfaceFormatData format;
surface->getFormat(&format);
if (format.bitsPerPixel != 32)
return NO;
const int w = scale*surface->width();
const int h = scale*surface->height();
if (4*w*h == 0)
return NO;
@autoreleasepool {
NSBitmapImageRep* bmp =
[[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:nil
pixelsWide:w
pixelsHigh:h
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bitmapFormat:NSAlphaNonpremultipliedBitmapFormat
bytesPerRow:w*4
bitsPerPixel:32];
if (!bmp)
return NO;
uint32_t* dst = (uint32_t*)[bmp bitmapData];
for (int y=0; y<h; ++y) {
const uint32_t* src = (const uint32_t*)surface->getData(0, y/scale);
for (int x=0, u=0; x<w; ++x, ++dst) {
*dst = *src;
if (++u == scale) {
u = 0;
++src;
}
}
}
NSImage* img = [[NSImage alloc] initWithSize:NSMakeSize(w, h)];
if (!img)
return NO;
[img addRepresentation:bmp];
NSCursor* nsCursor =
[[NSCursor alloc] initWithImage:img
hotSpot:NSMakePoint(scale*focus.x + scale/2,
scale*focus.y + scale/2)];
if (!nsCursor)
return NO;
[self.contentView setCursor:nsCursor];
return YES;
}
}
- (void)noResponderFor:(SEL)eventSelector
{
if (eventSelector == @selector(keyDown:)) {
// Do nothing (avoid beep)
}
else {
[super noResponderFor:eventSelector];
}
}
@end

View File

@ -1,45 +0,0 @@
// LAF OS Library
// Copyright (C) 2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
class OSXWindowImpl;
@interface OSXWindowDelegate : NSObject {
@private
OSXWindowImpl* m_impl;
}
@end
@implementation OSXWindowDelegate
- (OSXWindowDelegate*)initWithWindowImpl:(OSXWindowImpl*)impl
{
m_impl = impl;
return self;
}
- (BOOL)windowShouldClose:(id)sender
{
os::Event ev;
ev.setType(os::Event::CloseDisplay);
//ev.setDisplay(nullptr); // TODO
os::queue_event(ev);
return NO;
}
- (void)windowWillClose:(NSNotification*)notification
{
m_impl->onClose();
}
- (void)windowDidResize:(NSNotification*)notification
{
}
- (void)windowDidMiniaturize:(NSNotification*)notification
{
}
@end

View File

@ -1,26 +0,0 @@
// LAF OS Library
// Copyright (C) 2016-2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_POINTER_TYPE_H_INCLUDED
#define OS_POINTER_TYPE_H_INCLUDED
#pragma once
namespace os {
// Source of a mouse like event
enum class PointerType {
Unknown,
Mouse, // A regular mouse
Touchpad, // Touchpad/trackpad
Touch, // Touch screen
Pen, // Stylus pen
Cursor, // Puck like device
Eraser // Eraser end of a stylus pen
};
} // namespace os
#endif

View File

@ -1,34 +0,0 @@
// LAF OS Library
// Copyright (C) 2012-2013 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_SCOPED_HANDLE_H_INCLUDED
#define OS_SCOPED_HANDLE_H_INCLUDED
#pragma once
namespace os {
template<typename T>
class ScopedHandle {
public:
ScopedHandle(T* handle) : m_handle(handle) { }
~ScopedHandle() {
if (m_handle)
m_handle->dispose();
}
T* operator->() { return m_handle; }
operator T*() { return m_handle; }
private:
T* m_handle;
// Cannot copy
ScopedHandle(const ScopedHandle&);
ScopedHandle& operator=(const ScopedHandle&);
};
} // namespace os
#endif

View File

@ -1,35 +0,0 @@
// LAF OS Library
// Copyright (C) 2017 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef OS_SHORTCUT_H_INCLUDED
#define OS_SHORTCUT_H_INCLUDED
#pragma once
#include "os/keys.h"
namespace os {
class Shortcut {
public:
Shortcut(int unicode = 0,
KeyModifiers modifiers = kKeyNoneModifier)
: m_unicode(unicode)
, m_modifiers(modifiers) {
}
int unicode() const { return m_unicode; }
KeyModifiers modifiers() const { return m_modifiers; }
bool isEmpty() const { return m_unicode == 0; }
private:
int m_unicode;
KeyModifiers m_modifiers;
};
} // namespace os
#endif

Some files were not shown because too many files have changed in this diff Show More