1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-09-20 02:04:44 +00:00

Merge branch 'QB64-Phoenix-Edition:main' into midi-update

This commit is contained in:
Samuel Gomes 2024-06-07 03:50:22 +05:30 committed by GitHub
commit e1c4ca34a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 23878 additions and 23803 deletions

View file

@ -11413,7 +11413,7 @@ int32_t chrwidth(uint32_t character) {
// Custom font
// a740g: No need to render just to find the pixel length
if ((fontflags[f] & FONT_LOAD_UNICODE)) { // UNICODE character
w = FontPrintWidthUTF32(font[f], (uint32_t *)&character, 1);
w = FontPrintWidthUTF32(font[f], (char32_t *)&character, 1);
} else { // ASCII character
character &= 255;
w = FontPrintWidthASCII(font[f], (uint8_t *)&character, 1);
@ -30354,7 +30354,7 @@ void display() {
render_option = 1;
if (rt_data_last)
free(rt_data_last);
ok = FontRenderTextUTF32(font[f], &chr_utf32, 1, render_option, &rt_data, &rt_w, &rt_h);
ok = FontRenderTextUTF32(font[f], (char32_t *)&chr_utf32, 1, render_option, &rt_data, &rt_w, &rt_h);
rt_data_last = rt_data;
cp2 = rt_data;
f_pitch = 0;
@ -31964,11 +31964,11 @@ extern "C" void qb64_os_event_linux(XEvent *event, Display *display, int *qb64_o
if (*qb64_os_event_info == OS_EVENT_POST_PROCESSING) {
switch (event->type) {
case EnterNotify:
case FocusIn:
window_focused = -1;
break;
case LeaveNotify:
case FocusOut:
window_focused = 0;
// Iterate over all modifiers
for (uint32 key = VK + QBVK_RSHIFT; key <= VK + QBVK_MODE; key++) {

View file

@ -1,6 +1,6 @@
//----------------------------------------------------------------------------------------------------------------------
// QB64-PE Font Library
// Powered by FreeType 2.4.12 (https://github.com/vinniefalco/FreeTypeAmalgam)
// Powered by FreeType (https://freetype.org/)
//----------------------------------------------------------------------------------------------------------------------
#pragma once
@ -45,14 +45,15 @@ uint8_t *FontLoadFileToMemory(const char *file_path_name, int32_t *out_bytes);
int32_t FontLoad(const uint8_t *content_original, int32_t content_bytes, int32_t default_pixel_height, int32_t which_font, int32_t &options);
void FontFree(int32_t fh);
int32_t FontWidth(int32_t fh);
bool FontRenderTextUTF32(int32_t fh, const uint32_t *codepoint, int32_t codepoints, int32_t options, uint8_t **out_data, int32_t *out_x, int32_t *out_y);
bool FontRenderTextUTF32(int32_t fh, const char32_t *codepoint, int32_t codepoints, int32_t options, uint8_t **out_data, int32_t *out_x, int32_t *out_y);
bool FontRenderTextASCII(int32_t fh, const uint8_t *codepoint, int32_t codepoints, int32_t options, uint8_t **out_data, int32_t *out_x, int32_t *out_y);
int32_t FontPrintWidthUTF32(int32_t fh, const uint32_t *codepoint, int32_t codepoints);
int32_t FontPrintWidthUTF32(int32_t fh, const char32_t *codepoint, int32_t codepoints);
int32_t FontPrintWidthASCII(int32_t fh, const uint8_t *codepoint, int32_t codepoints);
qbs *func__md5(qbs *text);
int32_t func__UFontHeight(int32_t qb64_fh, int32_t passed);
int32_t func__UPrintWidth(const qbs *text, int32_t utf_encoding, int32_t qb64_fh, int32_t passed);
int32_t func__ULineSpacing(int32_t qb64_fh, int32_t passed);
void sub__UPrintString(int32_t start_x, int32_t start_y, const qbs *text, int32_t max_width, int32_t utf_encoding, int32_t qb64_fh, int32_t passed);
void sub__UPrintString(int32_t start_x, int32_t start_y, const qbs *text, int32_t max_width, int32_t utf_encoding, int32_t qb64_fh, int32_t dst_img,
int32_t passed);
int32_t func__UCharPos(const qbs *text, void *arr, int32_t utf_encoding, int32_t qb64_fh, int32_t passed);

View file

@ -70,13 +70,11 @@ void sub_environ(qbs *str) {
buf = (char *)malloc(str->len + 1);
buf[str->len] = '\0';
memcpy(buf, str->chr, str->len);
// Name and value may be separated by = or space
separator = strchr(buf, ' ');
if (!separator) {
separator = strchr(buf, '=');
}
if (!separator) {
// Name and value may be separated by = or space, whichever appears first.
separator = buf + strcspn(buf, " =");
if (*separator == '\0') {
// It is an error is there is no separator
free(buf);
error(5);
return;
}

View file

@ -635,7 +635,7 @@ qbs *func__files(qbs *qbsFileSpec, int32_t passed) {
std::string fileSpec(reinterpret_cast<char *>(qbsFileSpec->chr), qbsFileSpec->len);
if (fileSpec.empty())
fileSpec = "*.*";
fileSpec = "*";
if (FS_DirectoryExists(filepath_fix_directory(fileSpec))) {
directory = fileSpec;

View file

@ -1155,7 +1155,10 @@ void fgOpenWindow( SFG_Window* window, const char* title,
StructureNotifyMask | SubstructureNotifyMask | ExposureMask |
ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
VisibilityChangeMask | EnterWindowMask | LeaveWindowMask |
PointerMotionMask | ButtonMotionMask;
PointerMotionMask | ButtonMotionMask |
// QB64-PE: custom code begin
FocusChangeMask;
// QB64-PE: custom code end
winAttr.background_pixmap = None;
winAttr.background_pixel = 0;
winAttr.border_pixel = 0;

View file

@ -1,6 +1,6 @@
//----------------------------------------------------------------------------------------------------------------------
// QB64-PE Font Library
// Powered by FreeType 2.4.12 (https://github.com/vinniefalco/FreeTypeAmalgam)
// Powered by FreeType (https://freetype.org/)
//----------------------------------------------------------------------------------------------------------------------
#define FONT_DEBUG 0
@ -12,12 +12,15 @@
#include "libqb-common.h"
#include "mutex.h"
#include "rounding.h"
#include <codecvt>
#include <cstdio>
#include <ft2build.h>
#include FT_FREETYPE_H
extern "C" {
#include "freetype/md5.h"
}
#include <locale>
#include <string>
#include <unordered_map>
#include <vector>
@ -40,146 +43,82 @@ void pset_and_clip(int32_t x, int32_t y, uint32_t col);
/// @brief A simple class that manages conversions from various encodings to UTF32
class UTF32 {
private:
// See DecodeUTF8() below for more details
enum UTF8DecoderState { ACCEPT = 0, REJECT = 1 };
/// @brief See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
/// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
/// 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.
/// @param state The current state of the decoder
/// @param codep The decoded codepoint after state changes to UTF8DecodeState::ACCEPT
/// @param byte The next UTF-8 byte in the input stream
/// @return UTF8DecodeState::ACCEPT if enough bytes have been read for a character,
/// UTF8DecodeState::REJECT if the byte is not allowed to occur at its position,
/// and some other positive value if more bytes have to be read
uint32_t DecodeUTF8(uint32_t *state, uint32_t *codep, uint8_t byte) {
// clang-format off
static const uint8_t utf8d[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
};
// clang-format on
uint32_t type = utf8d[byte];
*codep = (*state != UTF8DecoderState::ACCEPT) ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & (byte);
*state = utf8d[256 + *state * 16 + type];
return *state;
}
static const uint32_t MAX_UNICODE_CODEPOINT = 0x10FFFFu;
public:
std::u32string string; // UTF32 string
UTF32 &operator=(const UTF32 &) = delete;
UTF32 &operator=(UTF32 &&) = delete;
std::vector<uint32_t> codepoints; // UTF32 codepoint dynamic array
/// @brief Converts an ASCII array to UTF-32
/// @param str The ASCII array
/// @param byte_len The size of the array in bytes
/// @brief Converts an ASCII string to UTF-32
/// @param str The ASCII string
/// @param len The size of the string in bytes
/// @return The number of codepoints that were converted
size_t ConvertASCII(const uint8_t *str, size_t byte_len) {
// Clear the codepoint vector
codepoints.clear();
size_t ConvertASCII(const uint8_t *str, size_t len) {
string.resize(len);
// Convert the ASCII string
for (size_t i = 0; i < byte_len; i++)
codepoints.push_back(codepage437_to_unicode16[str[i]]);
for (size_t i = 0; i < len; i++)
string[i] = codepage437_to_unicode16[str[i]];
return codepoints.size();
return string.size();
}
/// @brief Converts an UTF-8 array to UTF-32. This does not check for BOM
/// @param str The UTF-8 array
/// @param byte_len The size of the array in bytes
/// @brief Converts an UTF-8 string to UTF-32
/// @param str The UTF-8 string
/// @param len The size of the string in bytes
/// @return The number of codepoints that were converted
size_t ConvertUTF8(const uint8_t *str, size_t byte_len) {
// Clear the codepoint vector
codepoints.clear();
uint32_t prevState = UTF8DecoderState::ACCEPT, currentState = UTF8DecoderState::ACCEPT;
uint32_t cp;
for (size_t i = 0; i < byte_len; i++, prevState = currentState) {
switch (DecodeUTF8(&currentState, &cp, str[i])) {
case UTF8DecoderState::ACCEPT:
// Good codepoint
codepoints.push_back(cp);
break;
case UTF8DecoderState::REJECT:
// Codepoint would be U+FFFD (replacement character)
cp = 0xFFFD;
currentState = UTF8DecoderState::ACCEPT;
if (prevState != UTF8DecoderState::ACCEPT)
--i;
codepoints.push_back(cp);
break;
default:
// Need to read continuation bytes
continue;
}
size_t ConvertUTF8(const uint8_t *str, size_t len) {
try {
string = std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t>().from_bytes((const char *)str, (const char *)str + len);
} catch (...) {
string.clear();
}
return codepoints.size();
return string.size();
}
/// @brief Converts an UTF-16LE array to UTF-32. This does not check for BOM
/// @param str The UTF-16LE array
/// @param byte_len The size of the array in bytes
/// @brief Converts an UTF-16 LE/BE string (with BOM or naked) to UTF-32
/// @param str The UTF-16 string. If no BOM is present, little-endian is assumed
/// @param len The size of the string in bytes
/// @return The number of codepoints that were converted
size_t ConvertUTF16(const uint8_t *str, size_t byte_len) {
// Clear the codepoint vector
codepoints.clear();
// We'll assume the worst case scenario and allocate a buffer that is byte_len / 2 codepoints long
auto len16 = byte_len / sizeof(uint16_t);
auto str16 = (const uint16_t *)str;
uint32_t cp;
for (size_t i = 0; i < len16; i++) {
auto ch = str16[i];
// If the character is a surrogate, we need to combine it with the next character to get the actual codepoint
if (ch >= 0xD800 && ch <= 0xDBFF && i + 1 < len16) {
auto ch2 = str16[i + 1];
if (ch2 >= 0xDC00 && ch2 <= 0xDFFF) {
cp = ((ch - 0xD800) << 10) + (ch2 - 0xDC00) + 0x10000;
++i; // skip the second surrogate
size_t ConvertUTF16(const uint8_t *str, size_t len) {
try {
if (len > 2) {
// Detect BOM
if (str[0] == 0xFF && str[1] == 0xFE) {
// Little-endian
string = std::wstring_convert<
std::codecvt_utf16<char32_t, MAX_UNICODE_CODEPOINT,
static_cast<std::codecvt_mode>(std::codecvt_mode::consume_header | std::codecvt_mode::little_endian)>,
char32_t>()
.from_bytes((const char *)str, (const char *)str + len);
} else if (str[0] == 0xFE && str[1] == 0xFF) {
// Big-endian (C++ default)
string =
std::wstring_convert<std::codecvt_utf16<char32_t, MAX_UNICODE_CODEPOINT, std::codecvt_mode::consume_header>, char32_t>().from_bytes(
(const char *)str, (const char *)str + len);
} else {
cp = 0xFFFD; // invalid surrogate pair
// No BOM, assuming little-endian by default
string = std::wstring_convert<
std::codecvt_utf16<char32_t, MAX_UNICODE_CODEPOINT,
static_cast<std::codecvt_mode>(std::codecvt_mode::consume_header | std::codecvt_mode::little_endian)>,
char32_t>()
.from_bytes((const char *)str, (const char *)str + len);
}
} else if (ch >= 0xDC00 && ch <= 0xDFFF) {
cp = 0xFFFD; // invalid surrogate pair
} else {
cp = ch;
// Short string, assuming little-endian by default
string = std::wstring_convert<
std::codecvt_utf16<char32_t, MAX_UNICODE_CODEPOINT,
static_cast<std::codecvt_mode>(std::codecvt_mode::consume_header | std::codecvt_mode::little_endian)>,
char32_t>()
.from_bytes((const char *)str, (const char *)str + len);
}
codepoints.push_back(cp);
} catch (...) {
string.clear();
}
return codepoints.size();
return string.size();
}
};
@ -317,7 +256,7 @@ struct FontManager {
/// @param codepoint A valid UTF-32 codepoint
/// @param parentFont The parent font object
/// @return True if successful or if bitmap is already cached
bool CacheBitmap(uint32_t codepoint, Font *parentFont) {
bool CacheBitmap(char32_t codepoint, Font *parentFont) {
if (!bitmap) {
// Get the glyph index first and store it
// Note that this can return a valid glyph index but the index need not have any glyph bitmap
@ -396,7 +335,7 @@ struct FontManager {
}
};
std::unordered_map<uint32_t, Glyph *> glyphs; // holds pointers to cached glyph data for codepoints
std::unordered_map<char32_t, Glyph *> glyphs; // holds pointers to cached glyph data for codepoints
// Delete copy and move constructors and assignments
Font(const Font &) = delete;
@ -436,7 +375,7 @@ struct FontManager {
/// @param codepoint A valid UTF-32 codepoint
/// @param isMono True for mono bitmap and false for gray
/// @return The glyph pointer if successful or if the glyph is already in the map, nullptr otherwise
Glyph *GetGlyph(uint32_t codepoint, bool isMono) {
Glyph *GetGlyph(char32_t codepoint, bool isMono) {
if (glyphs.count(codepoint) == 0) {
// The glyph is not cached yet
auto newGlyph = new Glyph;
@ -471,7 +410,7 @@ struct FontManager {
/// @param codepoint The codepoint array (string)
/// @param codepoints The number of codepoints in the array
/// @return The length of the string in pixels
FT_Pos GetStringPixelWidth(const uint32_t *codepoint, size_t codepoints) {
FT_Pos GetStringPixelWidth(const char32_t *codepoint, size_t codepoints) {
if (monospaceWidth) // return monospace width simply by multiplying the fixed width by the codepoints
return monospaceWidth * codepoints;
@ -896,7 +835,7 @@ int32_t FontWidth(int32_t fh) {
/// @param codepoint The UTF32 codepoint array
/// @param codepoints The number of codepoints
/// @return Length in pixels
int32_t FontPrintWidthUTF32(int32_t fh, const uint32_t *codepoint, int32_t codepoints) {
int32_t FontPrintWidthUTF32(int32_t fh, const char32_t *codepoint, int32_t codepoints) {
libqb_mutex_guard lock(fontManager.m);
if (codepoints > 0) {
@ -922,7 +861,7 @@ int32_t FontPrintWidthASCII(int32_t fh, const uint8_t *codepoint, int32_t codepo
// Attempt to convert the string to UTF32 and get the actual width in pixels
auto count = utf32.ConvertASCII(codepoint, codepoints);
return FontPrintWidthUTF32(fh, utf32.codepoints.data(), count);
return FontPrintWidthUTF32(fh, utf32.string.data(), count);
}
return 0;
@ -937,7 +876,7 @@ int32_t FontPrintWidthASCII(int32_t fh, const uint8_t *codepoint, int32_t codepo
/// @param out_x A pointer to the output width of the rendered text in pixels
/// @param out_y A pointer to the output height of the rendered text in pixels
/// @return success = 1, failure = 0
bool FontRenderTextUTF32(int32_t fh, const uint32_t *codepoint, int32_t codepoints, int32_t options, uint8_t **out_data, int32_t *out_x, int32_t *out_y) {
bool FontRenderTextUTF32(int32_t fh, const char32_t *codepoint, int32_t codepoints, int32_t options, uint8_t **out_data, int32_t *out_x, int32_t *out_y) {
libqb_mutex_guard lock(fontManager.m);
FONT_DEBUG_CHECK(IS_VALID_FONT_HANDLE(fh));
@ -972,7 +911,7 @@ bool FontRenderTextUTF32(int32_t fh, const uint32_t *codepoint, int32_t codepoin
auto glyph = fnt->GetGlyph(cp, isMonochrome);
if (glyph) {
glyph->RenderBitmap(outBuf, strPixSize.x, strPixSize.y,
penX + glyph->bitmap->bearing.x + fnt->monospaceWidth / 2 - glyph->bitmap->advanceWidth / 2,
penX + glyph->bitmap->bearing.x + (fnt->monospaceWidth >> 1) - (glyph->bitmap->advanceWidth >> 1),
fnt->baseline - glyph->bitmap->bearing.y);
penX += fnt->monospaceWidth;
}
@ -1025,7 +964,7 @@ bool FontRenderTextASCII(int32_t fh, const uint8_t *codepoint, int32_t codepoint
// Attempt to convert the string to UTF32 and forward to FontRenderTextUTF32()
auto count = utf32.ConvertASCII(codepoint, codepoints);
return FontRenderTextUTF32(fh, utf32.codepoints.data(), count, options, out_data, out_x, out_y);
return FontRenderTextUTF32(fh, utf32.string.data(), count, options, out_data, out_x, out_y);
}
return false;
@ -1082,7 +1021,7 @@ int32_t func__UFontHeight(int32_t qb64_fh, int32_t passed) {
auto face = fnt->face;
if (FT_IS_SCALABLE(face))
return (((FT_Pos)face->ascender - (FT_Pos)face->descender) * fnt->defaultHeight) / (FT_Pos)face->units_per_EM;
return FT_MulDiv(((FT_Long)face->ascender - (FT_Long)face->descender), (FT_Long)fnt->defaultHeight, (FT_Long)face->units_per_EM);
return fnt->defaultHeight;
}
@ -1120,31 +1059,31 @@ int32_t func__UPrintWidth(const qbs *text, int32_t utf_encoding, int32_t qb64_fh
}
// Convert the string to UTF-32 if needed
uint32_t const *str32 = nullptr;
char32_t const *str32 = nullptr;
size_t codepoints = 0;
switch (utf_encoding) {
case 32: // UTF-32: no conversion needed
str32 = (uint32_t *)text->chr;
codepoints = text->len / sizeof(uint32_t);
str32 = (char32_t *)text->chr;
codepoints = text->len / sizeof(char32_t);
break;
case 16: // UTF-16: conversion required
codepoints = utf32.ConvertUTF16(text->chr, text->len);
if (codepoints)
str32 = utf32.codepoints.data();
str32 = utf32.string.data();
break;
case 8: // UTF-8: conversion required
codepoints = utf32.ConvertUTF8(text->chr, text->len);
if (codepoints)
str32 = utf32.codepoints.data();
str32 = utf32.string.data();
break;
default: // ASCII: conversion required
codepoints = utf32.ConvertASCII(text->chr, text->len);
if (codepoints)
str32 = utf32.codepoints.data();
str32 = utf32.string.data();
}
if (qb64_fh < 32)
@ -1184,7 +1123,7 @@ int32_t func__ULineSpacing(int32_t qb64_fh, int32_t passed) {
auto face = fnt->face;
if (FT_IS_SCALABLE(face))
return ((FT_Pos)face->height * fnt->defaultHeight) / (FT_Pos)face->units_per_EM;
return FT_MulDiv((FT_Long)face->height, (FT_Long)fnt->defaultHeight, (FT_Long)face->units_per_EM);
return fnt->defaultHeight;
}
@ -1193,28 +1132,23 @@ int32_t func__ULineSpacing(int32_t qb64_fh, int32_t passed) {
/// @param start_x The starting x position
/// @param start_y The starting y position
/// @param text The text that needs to be rendered
/// @param max_width The maximum width of the text (rendering will be clipped beyond width)
/// @param utf_encoding The UTF encoding of the text (0 = ASCII, 8 = UTF-8, 16 - UTF-16, 32 = UTF-32)
/// @param qb64_fh A QB64 font handle (this can be a builtin font as well)
/// @param max_width [optional] The maximum width of the text (rendering will be clipped beyond width)
/// @param utf_encoding [optional] The UTF encoding of the text (0 = ASCII, 8 = UTF-8, 16 - UTF-16, 32 = UTF-32)
/// @param qb64_fh [optional] A QB64 font handle (this can be a builtin font as well)
/// @param dst_img [optional] A QB64 image handle (zero designates current SCREEN page)
/// @param passed Optional arguments flag
void sub__UPrintString(int32_t start_x, int32_t start_y, const qbs *text, int32_t max_width, int32_t utf_encoding, int32_t qb64_fh, int32_t passed) {
void sub__UPrintString(int32_t start_x, int32_t start_y, const qbs *text, int32_t max_width, int32_t utf_encoding, int32_t qb64_fh, int32_t dst_img,
int32_t passed) {
libqb_mutex_guard lock(fontManager.m);
if (is_error_pending() || !text->len)
return;
// Check if we are in text mode and generate an error if we are
if (write_page->text) {
error(QB_ERROR_ILLEGAL_FUNCTION_CALL);
return;
}
FONT_DEBUG_PRINT("Graphics mode set. Proceeding...");
// Check max width
if (passed & 1) {
if (max_width < 1)
if (max_width < 1) {
return;
}
} else {
max_width = 0;
}
@ -1229,10 +1163,29 @@ void sub__UPrintString(int32_t start_x, int32_t start_y, const qbs *text, int32_
utf_encoding = 0;
}
int32_t old_dst_img;
if (passed & 8) {
old_dst_img = func__dest();
sub__dest(dst_img);
}
// Check if we are in text mode and generate an error if we are
if (write_page->text) {
error(QB_ERROR_ILLEGAL_FUNCTION_CALL);
if (passed & 8)
sub__dest(old_dst_img);
return;
}
FONT_DEBUG_PRINT("Graphics mode set. Proceeding...");
// Check if a valid font handle was passed
if (passed & 4) {
if (!IS_VALID_QB64_FONT_HANDLE(qb64_fh)) {
error(QB_ERROR_INVALID_HANDLE);
if (passed & 8)
sub__dest(old_dst_img);
return;
}
} else {
@ -1240,39 +1193,42 @@ void sub__UPrintString(int32_t start_x, int32_t start_y, const qbs *text, int32_
}
// Convert the string to UTF-32 if needed
uint32_t const *str32 = nullptr;
char32_t const *str32 = nullptr;
size_t codepoints = 0;
switch (utf_encoding) {
case 32: // UTF-32: no conversion needed
FONT_DEBUG_PRINT("UTF-32 string. Skipping conversion");
str32 = (uint32_t *)text->chr;
codepoints = text->len / sizeof(uint32_t);
str32 = (char32_t *)text->chr;
codepoints = text->len / sizeof(char32_t);
break;
case 16: // UTF-16: conversion required
FONT_DEBUG_PRINT("UTF-16 string. Converting to UTF32");
codepoints = utf32.ConvertUTF16(text->chr, text->len);
if (codepoints)
str32 = utf32.codepoints.data();
str32 = utf32.string.data();
break;
case 8: // UTF-8: conversion required
FONT_DEBUG_PRINT("UTF-8 string. Converting to UTF32");
codepoints = utf32.ConvertUTF8(text->chr, text->len);
if (codepoints)
str32 = utf32.codepoints.data();
str32 = utf32.string.data();
break;
default: // ASCII: conversion required
FONT_DEBUG_PRINT("ASCII string. Converting to UTF32");
codepoints = utf32.ConvertASCII(text->chr, text->len);
if (codepoints)
str32 = utf32.codepoints.data();
str32 = utf32.string.data();
}
if (!codepoints)
if (!codepoints) {
if (passed & 8)
sub__dest(old_dst_img);
return;
}
FontManager::Font *fnt = nullptr;
FT_Face face = nullptr;
@ -1290,7 +1246,7 @@ void sub__UPrintString(int32_t start_x, int32_t start_y, const qbs *text, int32_
strPixSize.x = fnt->GetStringPixelWidth(str32, codepoints);
pen.x = 0;
if (FT_IS_SCALABLE(face)) {
strPixSize.y = (((FT_Pos)face->ascender - (FT_Pos)face->descender) * fnt->defaultHeight) / (FT_Pos)face->units_per_EM;
strPixSize.y = FT_MulDiv(((FT_Long)face->ascender - (FT_Long)face->descender), (FT_Long)fnt->defaultHeight, (FT_Long)face->units_per_EM);
pen.y = ((FT_Pos)face->ascender * fnt->defaultHeight) / (FT_Pos)face->units_per_EM;
} else {
strPixSize.y = fnt->defaultHeight;
@ -1305,8 +1261,11 @@ void sub__UPrintString(int32_t start_x, int32_t start_y, const qbs *text, int32_
strPixSize.x = max_width;
auto drawBuf = (uint8_t *)calloc(strPixSize.x, strPixSize.y);
if (!drawBuf)
if (!drawBuf) {
if (passed & 8)
sub__dest(old_dst_img);
return;
}
FONT_DEBUG_PRINT("Allocated (%lu x %lu) buffer", strPixSize.x, strPixSize.y);
@ -1364,7 +1323,7 @@ void sub__UPrintString(int32_t start_x, int32_t start_y, const qbs *text, int32_
break;
glyph->RenderBitmap(drawBuf, strPixSize.x, strPixSize.y,
pen.x + glyph->bitmap->bearing.x + fnt->monospaceWidth / 2 - glyph->bitmap->advanceWidth / 2,
pen.x + glyph->bitmap->bearing.x + (fnt->monospaceWidth >> 1) - (glyph->bitmap->advanceWidth >> 1),
pen.y - glyph->bitmap->bearing.y);
pen.x += fnt->monospaceWidth;
}
@ -1506,6 +1465,9 @@ void sub__UPrintString(int32_t start_x, int32_t start_y, const qbs *text, int32_
}
free(drawBuf);
if (passed & 8)
sub__dest(old_dst_img);
}
/// @brief Calculate the starting pixel positions of each codepoint to an array. First one being zero.
@ -1550,31 +1512,31 @@ int32_t func__UCharPos(const qbs *text, void *arr, int32_t utf_encoding, int32_t
}
// Convert the string to UTF-32 if needed
uint32_t const *str32 = nullptr;
char32_t const *str32 = nullptr;
size_t codepoints = 0;
switch (utf_encoding) {
case 32: // UTF-32: no conversion needed
str32 = (uint32_t *)text->chr;
codepoints = text->len / sizeof(uint32_t);
str32 = (char32_t *)text->chr;
codepoints = text->len / sizeof(char32_t);
break;
case 16: // UTF-16: conversion required
codepoints = utf32.ConvertUTF16(text->chr, text->len);
if (codepoints)
str32 = utf32.codepoints.data();
str32 = utf32.string.data();
break;
case 8: // UTF-8: conversion required
codepoints = utf32.ConvertUTF8(text->chr, text->len);
if (codepoints)
str32 = utf32.codepoints.data();
str32 = utf32.string.data();
break;
default: // ASCII: conversion required
codepoints = utf32.ConvertASCII(text->chr, text->len);
if (codepoints)
str32 = utf32.codepoints.data();
str32 = utf32.string.data();
}
// Simply return the codepoint count if we do not have any array

View file

@ -24,7 +24,7 @@ int32_t FontWidth(int32_t fh) {
return 0;
}
bool FontRenderTextUTF32(int32_t fh, const uint32_t *codepoint, int32_t codepoints, int32_t options, uint8_t **out_data, int32_t *out_x, int32_t *out_y) {
bool FontRenderTextUTF32(int32_t fh, const char32_t *codepoint, int32_t codepoints, int32_t options, uint8_t **out_data, int32_t *out_x, int32_t *out_y) {
(void)fh;
(void)codepoint;
(void)codepoints;
@ -46,7 +46,7 @@ bool FontRenderTextASCII(int32_t fh, const uint8_t *codepoint, int32_t codepoint
return 0;
}
int32_t FontPrintWidthUTF32(int32_t fh, const uint32_t *codepoint, int32_t codepoints) {
int32_t FontPrintWidthUTF32(int32_t fh, const char32_t *codepoint, int32_t codepoints) {
(void)fh;
(void)codepoint;
(void)codepoints;

View file

@ -7,7 +7,7 @@ if (_FUNC_EVALUATEFUNCTION_ARRAY_UDT_ARGS[2]&1){
tmp_long=_FUNC_EVALUATEFUNCTION_ARRAY_UDT_ARGS[5];
while(tmp_long--) {
qbs_free(*(qbs**)(_FUNC_EVALUATEFUNCTION_ARRAY_UDT_ARGS[0]+(480/8+1-1)*tmp_long+ 48));}
qbs_free(*(qbs**)(_FUNC_EVALUATEFUNCTION_ARRAY_UDT_ARGS[0]+60*tmp_long+ 48));}
free((void*)(_FUNC_EVALUATEFUNCTION_ARRAY_UDT_ARGS[0]));
}
free_mem_lock( (mem_lock*)((ptrszint*)_FUNC_EVALUATEFUNCTION_ARRAY_UDT_ARGS)[8] );

View file

@ -3,7 +3,7 @@ if (_SUB_DEBUGMODE_ARRAY_UDT_BUTTON[2]&1){
tmp_long=_SUB_DEBUGMODE_ARRAY_UDT_BUTTON[5];
while(tmp_long--) {
qbs_free(*(qbs**)(_SUB_DEBUGMODE_ARRAY_UDT_BUTTON[0]+(128/8+1-1)*tmp_long+ 8));}
qbs_free(*(qbs**)(_SUB_DEBUGMODE_ARRAY_UDT_BUTTON[0]+16*tmp_long+ 8));}
free((void*)(_SUB_DEBUGMODE_ARRAY_UDT_BUTTON[0]));
}
free_mem_lock( (mem_lock*)((ptrszint*)_SUB_DEBUGMODE_ARRAY_UDT_BUTTON)[8] );

View file

@ -20,7 +20,7 @@ if (_FUNC_IDEVARIABLEWATCHBOX_ARRAY_UDT_VARDLGLIST[2]&1){
tmp_long=_FUNC_IDEVARIABLEWATCHBOX_ARRAY_UDT_VARDLGLIST[5];
while(tmp_long--) {
qbs_free(*(qbs**)(_FUNC_IDEVARIABLEWATCHBOX_ARRAY_UDT_VARDLGLIST[0]+(264/8+1-1)*tmp_long+ 25));}
qbs_free(*(qbs**)(_FUNC_IDEVARIABLEWATCHBOX_ARRAY_UDT_VARDLGLIST[0]+33*tmp_long+ 25));}
free((void*)(_FUNC_IDEVARIABLEWATCHBOX_ARRAY_UDT_VARDLGLIST[0]));
}
free_mem_lock( (mem_lock*)((ptrszint*)_FUNC_IDEVARIABLEWATCHBOX_ARRAY_UDT_VARDLGLIST)[8] );

View file

@ -19,7 +19,7 @@ if (_FUNC_IDEELEMENTWATCHBOX_ARRAY_UDT_VARDLGLIST[2]&1){
tmp_long=_FUNC_IDEELEMENTWATCHBOX_ARRAY_UDT_VARDLGLIST[5];
while(tmp_long--) {
qbs_free(*(qbs**)(_FUNC_IDEELEMENTWATCHBOX_ARRAY_UDT_VARDLGLIST[0]+(264/8+1-1)*tmp_long+ 25));}
qbs_free(*(qbs**)(_FUNC_IDEELEMENTWATCHBOX_ARRAY_UDT_VARDLGLIST[0]+33*tmp_long+ 25));}
free((void*)(_FUNC_IDEELEMENTWATCHBOX_ARRAY_UDT_VARDLGLIST[0]));
}
free_mem_lock( (mem_lock*)((ptrszint*)_FUNC_IDEELEMENTWATCHBOX_ARRAY_UDT_VARDLGLIST)[8] );

View file

@ -11,7 +11,7 @@ if (_FUNC_IDEASCIIBOX_ARRAY_UDT_ASCIITABLE[2]&1){
tmp_long=_FUNC_IDEASCIIBOX_ARRAY_UDT_ASCIITABLE[5];
while(tmp_long--) {
qbs_free(*(qbs**)(_FUNC_IDEASCIIBOX_ARRAY_UDT_ASCIITABLE[0]+(96/8+1-1)*tmp_long+ 4));}
qbs_free(*(qbs**)(_FUNC_IDEASCIIBOX_ARRAY_UDT_ASCIITABLE[0]+12*tmp_long+ 4));}
free((void*)(_FUNC_IDEASCIIBOX_ARRAY_UDT_ASCIITABLE[0]));
}
free_mem_lock( (mem_lock*)((ptrszint*)_FUNC_IDEASCIIBOX_ARRAY_UDT_ASCIITABLE)[8] );

File diff suppressed because it is too large Load diff

View file

@ -52,7 +52,7 @@ if (__ARRAY_UDT_CONSTFUNCS[2]&1){
tmp_long=__ARRAY_UDT_CONSTFUNCS[5];
while(tmp_long--) {
qbs_free(*(qbs**)(__ARRAY_UDT_CONSTFUNCS[0]+(80/8+1-1)*tmp_long+ 0));}
qbs_free(*(qbs**)(__ARRAY_UDT_CONSTFUNCS[0]+10*tmp_long+ 0));}
free((void*)(__ARRAY_UDT_CONSTFUNCS[0]));
}
free_mem_lock( (mem_lock*)((ptrszint*)__ARRAY_UDT_CONSTFUNCS)[8] );
@ -401,17 +401,17 @@ if (__ARRAY_UDT_BACKUPUSEDVARIABLELIST[2]&1){
tmp_long=__ARRAY_UDT_BACKUPUSEDVARIABLELIST[5];
while(tmp_long--) {
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 32));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 40));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 48));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 56));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 64));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 72));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 80));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 88));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 96));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 104));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 112));}
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+120*tmp_long+ 32));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+120*tmp_long+ 40));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+120*tmp_long+ 48));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+120*tmp_long+ 56));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+120*tmp_long+ 64));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+120*tmp_long+ 72));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+120*tmp_long+ 80));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+120*tmp_long+ 88));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+120*tmp_long+ 96));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+120*tmp_long+ 104));
qbs_free(*(qbs**)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]+120*tmp_long+ 112));}
free((void*)(__ARRAY_UDT_BACKUPUSEDVARIABLELIST[0]));
}
free_mem_lock( (mem_lock*)((ptrszint*)__ARRAY_UDT_BACKUPUSEDVARIABLELIST)[8] );
@ -802,7 +802,7 @@ if (__ARRAY_UDT_IDS[2]&1){
tmp_long=__ARRAY_UDT_IDS[5];
while(tmp_long--) {
qbs_free(*(qbs**)(__ARRAY_UDT_IDS[0]+(22952/8+1-1)*tmp_long+ 2861));}
qbs_free(*(qbs**)(__ARRAY_UDT_IDS[0]+2869*tmp_long+ 2861));}
free((void*)(__ARRAY_UDT_IDS[0]));
}
free_mem_lock( (mem_lock*)((ptrszint*)__ARRAY_UDT_IDS)[8] );
@ -955,17 +955,17 @@ if (__ARRAY_UDT_USEDVARIABLELIST[2]&1){
tmp_long=__ARRAY_UDT_USEDVARIABLELIST[5];
while(tmp_long--) {
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 32));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 40));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 48));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 56));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 64));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 72));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 80));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 88));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 96));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 104));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+(960/8+1-1)*tmp_long+ 112));}
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+120*tmp_long+ 32));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+120*tmp_long+ 40));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+120*tmp_long+ 48));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+120*tmp_long+ 56));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+120*tmp_long+ 64));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+120*tmp_long+ 72));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+120*tmp_long+ 80));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+120*tmp_long+ 88));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+120*tmp_long+ 96));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+120*tmp_long+ 104));
qbs_free(*(qbs**)(__ARRAY_UDT_USEDVARIABLELIST[0]+120*tmp_long+ 112));}
free((void*)(__ARRAY_UDT_USEDVARIABLELIST[0]));
}
free_mem_lock( (mem_lock*)((ptrszint*)__ARRAY_UDT_USEDVARIABLELIST)[8] );

View file

@ -1536,16 +1536,14 @@ FUNCTION ide2 (ignore)
END IF
END IF
IF os$ = "WIN" OR MacOSX = 1 THEN
IF _WINDOWHASFOCUS THEN
LOCATE , , 1
_PALETTECOLOR 5, IDEBracketHighlightColor, 0
_PALETTECOLOR 6, IDEBackgroundColor2, 0
ELSE
LOCATE , , 0
_PALETTECOLOR 5, IDEBackgroundColor, 0
_PALETTECOLOR 6, IDEBackgroundColor, 0
END IF
IF _WINDOWHASFOCUS THEN
LOCATE , , 1
_PALETTECOLOR 5, IDEBracketHighlightColor, 0
_PALETTECOLOR 6, IDEBackgroundColor2, 0
ELSE
LOCATE , , 0
_PALETTECOLOR 5, IDEBackgroundColor, 0
_PALETTECOLOR 6, IDEBackgroundColor, 0
END IF
IF KALT THEN 'alt held
@ -1570,7 +1568,7 @@ FUNCTION ide2 (ignore)
idealthighlight = 0
LOCATE , , 0: COLOR 0, 7: _PRINTSTRING (1, 1), menubar$
IF ideentermenu = 1 AND KCONTROL = 0 THEN 'alt was pressed then released
IF _WINDOWHASFOCUS OR os$ = "LNX" THEN
IF _WINDOWHASFOCUS THEN
LOCATE , , , IDENormalCursorStart, IDENormalCursorEnd
skipdisplay = 0
ideentermenu = 0
@ -4421,7 +4419,7 @@ FUNCTION ide2 (ignore)
DO
_LIMIT 100
GetInput
IF _WINDOWHASFOCUS = 0 AND (os$ = "WIN" OR MacOSX = 1) THEN
IF _WINDOWHASFOCUS = 0 THEN
COLOR 0, 7: _PRINTSTRING (1, 1), menubar$
SCREEN , , 3, 0: PCOPY 3, 0
GOTO ideloop
@ -4434,7 +4432,7 @@ FUNCTION ide2 (ignore)
KB = KEY_ESC
END IF
IF _WINDOWHASFOCUS = 0 AND (os$ = "WIN" OR MacOSX = 1) THEN
IF _WINDOWHASFOCUS = 0 THEN
COLOR 0, 7: _PRINTSTRING (1, 1), menubar$
SCREEN , , 3, 0: PCOPY 3, 0
GOTO ideloop
@ -4657,7 +4655,7 @@ FUNCTION ide2 (ignore)
DO
_LIMIT 100
GetInput
IF _WINDOWHASFOCUS = 0 AND (os$ = "WIN" OR MacOSX = 1) THEN
IF _WINDOWHASFOCUS = 0 THEN
COLOR 0, 7: _PRINTSTRING (1, 1), menubar$
PCOPY 3, 0: SCREEN , , 3, 0
GOTO ideloop
@ -4677,7 +4675,7 @@ FUNCTION ide2 (ignore)
ideexit = 1: GOTO ideloop
END IF
END IF
IF _WINDOWHASFOCUS = 0 AND (os$ = "WIN" OR MacOSX = 1) THEN
IF _WINDOWHASFOCUS = 0 THEN
COLOR 0, 7: _PRINTSTRING (1, 1), menubar$
PCOPY 3, 0: SCREEN , , 3, 0
IF IdeDebugMode = 2 THEN GOTO EnterDebugMode
@ -11856,7 +11854,7 @@ SUB ideinsline (i, text$)
idegotoline i
'insert line
textlen = LEN(text$)
idet$ = LEFT$(idet$, ideli - 1) + MKL$(textlen) + text$ + MKL$(textlen) + RIGHT$(idet$, LEN(idet$) - ideli + 1)
idet$ = LEFT$(idet$, ideli - 1) + (MKL$(textlen) + text$ + MKL$(textlen)) + RIGHT$(idet$, LEN(idet$) - ideli + 1)
iden = iden + 1
END SUB
@ -12536,7 +12534,7 @@ SUB idesetline (i, text$)
IF i <> -1 THEN idegotoline i
textlen = LEN(text$)
idet$ = LEFT$(idet$, ideli - 1) + MKL$(textlen) + text$ + MKL$(textlen) + RIGHT$(idet$, LEN(idet$) - ideli + 1 - CVL(MID$(idet$, ideli, 4)) - 8)
idet$ = LEFT$(idet$, ideli - 1) + (MKL$(textlen) + text$ + MKL$(textlen)) + RIGHT$(idet$, LEN(idet$) - ideli + 1 - CVL(MID$(idet$, ideli, 4)) - 8)
END SUB

View file

@ -1537,10 +1537,10 @@ id.n = qb64prefix$ + "UPrintString"
id.Dependency = DEPENDENCY_LOADFONT
id.subfunc = 2
id.callname = "sub__UPrintString"
id.args = 6
id.arg = MKL$(LONGTYPE - ISPOINTER) + MKL$(LONGTYPE - ISPOINTER) + MKL$(STRINGTYPE - ISPOINTER) + MKL$(LONGTYPE - ISPOINTER) + MKL$(LONGTYPE - ISPOINTER) + MKL$(LONGTYPE - ISPOINTER)
id.specialformat = "(?,?),?[,[?][,[?][,?]]]"
id.hr_syntax = "_UPRINTSTRING (x&, y&), text$[, maxWidth&][, utfEncoding&][, fontHandle&]"
id.args = 7
id.arg = MKL$(LONGTYPE - ISPOINTER) + MKL$(LONGTYPE - ISPOINTER) + MKL$(STRINGTYPE - ISPOINTER) + MKL$(LONGTYPE - ISPOINTER) + MKL$(LONGTYPE - ISPOINTER) + MKL$(LONGTYPE - ISPOINTER) + MKL$(LONGTYPE - ISPOINTER)
id.specialformat = "(?,?),?[,[?][,[?][,[?][,?]]]]"
id.hr_syntax = "_UPRINTSTRING (x&, y&), text$[, maxWidth&][, utfEncoding&][, fontHandle&][, imageHandle&]"
regid
clearid

View file

@ -0,0 +1,48 @@
$CONSOLE:ONLY
ON ERROR GOTO ehandler
'Test setting with =
ENVIRON "FOO=BAR"
PRINT ENVIRON$("FOO")
'Test settings with space
ENVIRON "VAR VAL"
PRINT ENVIRON$("VAR")
'Test setting value with spaces with = separator
ENVIRON "ABC=DEF GHI"
PRINT ENVIRON$("ABC")
'Test setting value with spaces with space separator
ENVIRON "JKL MNO PQR"
PRINT ENVIRON$("JKL")
'Test overwriting existing
ENVIRON "X=XY"
ENVIRON "X=ZZZ"
PRINT ENVIRON$("X")
'Test unset variable with = separator
ENVIRON "NAME=LUKE"
ENVIRON "NAME="
PRINT "["; ENVIRON$("NAME"); "]"
'Test unset variable with space separator
ENVIRON "TEXT BOO"
ENVIRON "TEXT "
PRINT "["; ENVIRON$("TEXT"); "]"
'Test no separator
ENVIRON "NOSEP"
SYSTEM
ehandler:
print "Error"; ERR; "line"; _ERRORLINE
RESUME NEXT

View file

@ -0,0 +1,8 @@
BAR
VAL
DEF GHI
MNO PQR
ZZZ
[]
[]
Error 5 line 42

View file

@ -20,7 +20,7 @@ NAME "temp_dir" AS "dummy_dir"
PRINT "_DIREXISTS(dummy_dir):"; _DIREXISTS("./dummy_dir")
PRINT "Creating a temporary file inside dummy_dir"
DIM fileName AS STRING: fileName = CreateDummyFile$("./dummy_dir/")
DIM fileName AS STRING: fileName = CreateDummyFile("./dummy_dir/", ".tmp")
PRINT "_FILEEXISTS(fileName):"; _FILEEXISTS(fileName)
@ -29,9 +29,41 @@ KILL fileName
PRINT "Creating 10 dummy files inside dummy_dir"
DIM i AS LONG: FOR i = 0 TO 9
fileName = CreateDummyFile$("./dummy_dir/")
fileName = CreateDummyFile("./dummy_dir/", ".tmp")
NEXT i
' Start _FILES$ test
CHDIR "dummy_dir"
fileName = CreateDummyFile("./", "")
i = 0
DIM dirEntry AS STRING: dirEntry = _FILES$("") ' should count 13 entries
DO WHILE LEN(dirEntry) > 0
i = i + 1
dirEntry = _FILES$
LOOP
PRINT "Counted"; i; "entries."
i = 0
dirEntry = _FILES$("*.*") ' should count 12 entries
DO WHILE LEN(dirEntry) > 0
i = i + 1
dirEntry = _FILES$
LOOP
PRINT "Counted"; i; "entries."
KILL fileName
CHDIR ".."
' End _FILES$ test
PRINT "Deleting all 10 dummy files"
KILL "./dummy_dir/*.tmp"
@ -44,9 +76,10 @@ test_failed:
PRINT "Test failed!"
SYSTEM 1
FUNCTION CreateDummyFile$ (directory AS STRING)
FUNCTION CreateDummyFile$ (directory AS STRING, extension AS STRING)
DO
DIM fileName AS STRING: fileName = directory + LTRIM$(STR$(100! * (TIMER + RND))) + ".tmp"
DIM fileName AS STRING: fileName = directory + LTRIM$(STR$(INT(100! * (TIMER + RND)))) + extension
LOOP WHILE _FILEEXISTS(fileName)
DIM h AS LONG: h = FREEFILE

View file

@ -7,5 +7,7 @@ Creating a temporary file inside dummy_dir
_FILEEXISTS(fileName):-1
Deleting fileName
Creating 10 dummy files inside dummy_dir
Counted 13 entries.
Counted 12 entries.
Deleting all 10 dummy files
Deleting dummy_dir

View file

@ -97,8 +97,8 @@ SUB PrintFontDetails (handle AS LONG, testFileName AS STRING)
_DEST image
_FONT handle
COLOR _RGB32(255)
_UPRINTSTRING (0, 0), SAMPLE_TEXT_1
_UPRINTSTRING (0, uLineSpacing), SAMPLE_TEXT_2
_UPRINTSTRING (0, 0), SAMPLE_TEXT_1, , , handle
_UPRINTSTRING (0, uLineSpacing), SAMPLE_TEXT_2, , , , image
'_SAVEIMAGE testFileName + "u", image, TEST_IMAGE_FORMAT
_FONT 16

View file

@ -65,8 +65,8 @@ Success, images are identical!
Loading font from memory (automono) ... done.
_FONTWIDTH = 0
_FONTHEIGHT = 22
_UFONTHEIGHT = 27
_ULINESPACING = 27
_UFONTHEIGHT = 28
_ULINESPACING = 28
_PRINTWIDTH = 1088
_UPRINTWIDTH = 1088
_UCHARPOS = 95
@ -78,7 +78,7 @@ Loading font LiberationSans-Regular.ttf () ... done.
_FONTWIDTH = 0
_FONTHEIGHT = 12
_UFONTHEIGHT = 13
_ULINESPACING = 13
_ULINESPACING = 14
_PRINTWIDTH = 606
_UPRINTWIDTH = 606
_UCHARPOS = 95
@ -89,7 +89,7 @@ Success, images are identical!
Loading font LiberationSans-Regular.ttf (monospace) ... done.
_FONTWIDTH = 15
_FONTHEIGHT = 16
_UFONTHEIGHT = 17
_UFONTHEIGHT = 18
_ULINESPACING = 18
_PRINTWIDTH = 1425
_UPRINTWIDTH = 1425
@ -101,7 +101,7 @@ Success, images are identical!
Loading font LiberationSans-Regular.ttf (automono) ... done.
_FONTWIDTH = 0
_FONTHEIGHT = 22
_UFONTHEIGHT = 24
_UFONTHEIGHT = 25
_ULINESPACING = 25
_PRINTWIDTH = 1094
_UPRINTWIDTH = 1094
@ -114,7 +114,7 @@ Loading font LiberationSerif-Regular.ttf () ... done.
_FONTWIDTH = 0
_FONTHEIGHT = 12
_UFONTHEIGHT = 13
_ULINESPACING = 13
_ULINESPACING = 14
_PRINTWIDTH = 583
_UPRINTWIDTH = 583
_UCHARPOS = 95
@ -125,7 +125,7 @@ Success, images are identical!
Loading font LiberationSerif-Regular.ttf (monospace) ... done.
_FONTWIDTH = 15
_FONTHEIGHT = 16
_UFONTHEIGHT = 17
_UFONTHEIGHT = 18
_ULINESPACING = 18
_PRINTWIDTH = 1425
_UPRINTWIDTH = 1425
@ -149,8 +149,8 @@ Success, images are identical!
Loading font LiberationMono-Regular.ttf () ... done.
_FONTWIDTH = 0
_FONTHEIGHT = 12
_UFONTHEIGHT = 13
_ULINESPACING = 13
_UFONTHEIGHT = 14
_ULINESPACING = 14
_PRINTWIDTH = 665
_UPRINTWIDTH = 665
_UCHARPOS = 95
@ -173,8 +173,8 @@ Success, images are identical!
Loading font LiberationMono-Regular.ttf (automono) ... done.
_FONTWIDTH = 13
_FONTHEIGHT = 22
_UFONTHEIGHT = 24
_ULINESPACING = 24
_UFONTHEIGHT = 25
_ULINESPACING = 25
_PRINTWIDTH = 1235
_UPRINTWIDTH = 1235
_UCHARPOS = 95

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 241 KiB

View file

@ -148,6 +148,9 @@ SUB AssertImage2 (originalActualImage AS LONG, expectedFileName AS STRING)
DIM actual AS _MEM, expected AS _MEM
actual = _MEMIMAGE(actualImage)
expected = _MEMIMAGE(expectedImage)
IF _WIDTH(actualImage) <> _WIDTH(expectedImage) THEN
PRINT "Failure! Image width differs, actual:"; _WIDTH(actualImage); ", Expected:"; _WIDTH(expectedImage)
GOTO freeImages
@ -158,9 +161,6 @@ SUB AssertImage2 (originalActualImage AS LONG, expectedFileName AS STRING)
GOTO freeImages
END IF
actual = _MEMIMAGE(actualImage)
expected = _MEMIMAGE(expectedImage)
IF actual.SIZE <> expected.SIZE THEN
PRINT "Failure! Image sizes differ, Actual:"; actual.SIZE; ", Expected:"; expected.SIZE
GOTO freeImages