mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-12 18:20:57 +00:00
Split text attribute handling into its own API (#9890)
This commit is contained in:
parent
93509c8499
commit
99ee4a7703
|
@ -370,6 +370,8 @@
|
|||
<Unit filename="../../src/floating_label.hpp" />
|
||||
<Unit filename="../../src/floating_textbox.cpp" />
|
||||
<Unit filename="../../src/floating_textbox.hpp" />
|
||||
<Unit filename="../../src/font/attributes.cpp" />
|
||||
<Unit filename="../../src/font/attributes.hpp" />
|
||||
<Unit filename="../../src/font/constants.cpp" />
|
||||
<Unit filename="../../src/font/constants.hpp" />
|
||||
<Unit filename="../../src/font/error.hpp" />
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
04C748F7835C62498D27442D /* edit_pbl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6FA542D78393E8FF067775DA /* edit_pbl.cpp */; };
|
||||
04DC4E59AEDBC1A0AFDCA8CC /* units_dialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CAF74C3AB8D456EA3E756396 /* units_dialog.cpp */; };
|
||||
0554467DB5FE99D85ABCDCA0 /* edit_pbl_translation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00574699A982AA23F12B39E0 /* edit_pbl_translation.cpp */; };
|
||||
0813449DBC67700714FA3ACD /* attributes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57724A59B2F7D072D91DD787 /* attributes.cpp */; };
|
||||
08964907BF0C2F261FC984DC /* reachmap_options.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 231C4A6BB2F1A717F0D6E2E2 /* reachmap_options.hpp */; };
|
||||
0DA840E1AD033775DD626F42 /* markup.hpp in Headers */ = {isa = PBXBuildFile; fileRef = D7B540678519F0EBD7C19A17 /* markup.hpp */; };
|
||||
1234567890ABCDEF12345678 /* file_progress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1234567890ABCDEF12345680 /* file_progress.cpp */; };
|
||||
|
@ -35,6 +36,7 @@
|
|||
365D4F89BD511BC074E639D7 /* migrate_version_selection.hpp in Headers */ = {isa = PBXBuildFile; fileRef = B3DE4F95AF72C6F6BC37E695 /* migrate_version_selection.hpp */; };
|
||||
36B146FAA79A55E9F43723B1 /* general.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84234C54BB84519421FD4136 /* general.cpp */; };
|
||||
36D74F7F8D7655ACCABE562D /* edit_pbl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6FA542D78393E8FF067775DA /* edit_pbl.cpp */; };
|
||||
38C444C497ECBE2DF9BB2319 /* attributes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57724A59B2F7D072D91DD787 /* attributes.cpp */; };
|
||||
393E4C9DAEE19E12B2B168B5 /* edit_unit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A05D48F0A2C022FC128C8B3E /* edit_unit.cpp */; };
|
||||
3C0F4FFA9A0331ED6846D216 /* spritesheet_generator.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D284B9A81882806D8B25006 /* spritesheet_generator.hpp */; };
|
||||
3C254DF5B7DF196F2041955F /* mp_report.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 58C649488B3014E6F7254B62 /* mp_report.cpp */; };
|
||||
|
@ -653,6 +655,7 @@
|
|||
7A0347D48BDB52B1430D9E79 /* migrate_version_selection.hpp in Headers */ = {isa = PBXBuildFile; fileRef = B3DE4F95AF72C6F6BC37E695 /* migrate_version_selection.hpp */; };
|
||||
7A7146D7893AA09891352019 /* test_schema_validator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CF14AB694764953E2CB3AF7 /* test_schema_validator.cpp */; };
|
||||
7BFC4DF5BFF8CF75855BA662 /* prompt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 67044415B63F5888193BD7A6 /* prompt.cpp */; };
|
||||
7C4740B081A838A09779FAAA /* attributes.hpp in Headers */ = {isa = PBXBuildFile; fileRef = B56948C5B90E74C62F2D078F /* attributes.hpp */; };
|
||||
7FDF4E8D9C94E7DA8F41F7BB /* tod_new_schedule.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 5D46466DBCD81B13621C7342 /* tod_new_schedule.hpp */; };
|
||||
805143B8BABF92CA79BEC8F5 /* gui_test_dialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7FBD4033B4B52E9424819B5F /* gui_test_dialog.cpp */; };
|
||||
80724CBB88A3B6C36D1E3199 /* spritesheet_generator.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D284B9A81882806D8B25006 /* spritesheet_generator.hpp */; };
|
||||
|
@ -1143,6 +1146,7 @@
|
|||
9C6342BC8A95B6D23D384486 /* gui_test_dialog.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0110429EAA81AED07D53B749 /* gui_test_dialog.hpp */; };
|
||||
9FE64884AE8121CDBABF7D8A /* preferences.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C1D64406873FEB11E9758A05 /* preferences.cpp */; };
|
||||
AC4242F78B39C571E34AF48F /* edit_unit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A05D48F0A2C022FC128C8B3E /* edit_unit.cpp */; };
|
||||
B14E4163984EED844169EF4F /* attributes.hpp in Headers */ = {isa = PBXBuildFile; fileRef = B56948C5B90E74C62F2D078F /* attributes.hpp */; };
|
||||
B45C431C9B7250C3321F8BC2 /* preferences.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 2CFD4922B64EA6C9F71F71A2 /* preferences.hpp */; };
|
||||
B508D193100146E300B12852 /* engine_fai.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B508D191100146E300B12852 /* engine_fai.cpp */; };
|
||||
B513B2290ED36BFB0006E551 /* libcairo.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = B513B2270ED36BFB0006E551 /* libcairo.2.dylib */; };
|
||||
|
@ -2119,6 +2123,7 @@
|
|||
4944F41A1354FBFF0027E614 /* teleport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = teleport.cpp; sourceTree = "<group>"; };
|
||||
49478712172FF6F8002B7ABA /* tristate_button.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tristate_button.cpp; sourceTree = "<group>"; };
|
||||
49478713172FF6F8002B7ABA /* tristate_button.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = tristate_button.hpp; sourceTree = "<group>"; };
|
||||
57724A59B2F7D072D91DD787 /* attributes.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = attributes.cpp; path = font/attributes.cpp; sourceTree = "<group>"; };
|
||||
58C649488B3014E6F7254B62 /* mp_report.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = mp_report.cpp; sourceTree = "<group>"; };
|
||||
5D46466DBCD81B13621C7342 /* tod_new_schedule.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = tod_new_schedule.hpp; sourceTree = "<group>"; };
|
||||
620A386215E9364E00A4F513 /* attack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = attack.cpp; sourceTree = "<group>"; };
|
||||
|
@ -2687,6 +2692,7 @@
|
|||
B55BE04A11234B1A00154E6C /* lobby_info.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = lobby_info.hpp; sourceTree = "<group>"; };
|
||||
B561F366104B1042001369F5 /* component.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = component.cpp; sourceTree = "<group>"; };
|
||||
B561F367104B1042001369F5 /* component.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = component.hpp; sourceTree = "<group>"; };
|
||||
B56948C5B90E74C62F2D078F /* attributes.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = attributes.hpp; path = font/attributes.hpp; sourceTree = "<group>"; };
|
||||
B5951A811013BB0800C10B66 /* chat_events.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = chat_events.hpp; sourceTree = "<group>"; };
|
||||
B5951A831013BB0800C10B66 /* multiplayer_error_codes.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = multiplayer_error_codes.hpp; sourceTree = "<group>"; };
|
||||
B5951A841013BB0800C10B66 /* resources.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = resources.cpp; sourceTree = "<group>"; };
|
||||
|
@ -5145,6 +5151,8 @@
|
|||
46F92EF42174FEBD00602C1C /* standard_colors.hpp */,
|
||||
46F92F0C2174FEC000602C1C /* text.cpp */,
|
||||
46F92F0D2174FEC000602C1C /* text.hpp */,
|
||||
57724A59B2F7D072D91DD787 /* attributes.cpp */,
|
||||
B56948C5B90E74C62F2D078F /* attributes.hpp */,
|
||||
);
|
||||
name = font;
|
||||
sourceTree = "<group>";
|
||||
|
@ -5201,6 +5209,7 @@
|
|||
F7524948ADF9BC097E6D8DBC /* charconv.hpp in Headers */,
|
||||
00424091A60B5901585B212F /* units_dialog.hpp in Headers */,
|
||||
48C54CF8AD9615C43EB823E7 /* addon_server_info.hpp in Headers */,
|
||||
B14E4163984EED844169EF4F /* attributes.hpp in Headers */,
|
||||
08964907BF0C2F261FC984DC /* reachmap_options.hpp in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -5226,6 +5235,7 @@
|
|||
92644A76AAB2F29A77107DC0 /* charconv.hpp in Headers */,
|
||||
96D34041A501AB7F5B7AD596 /* units_dialog.hpp in Headers */,
|
||||
E60E437B8712EC8D22CA2608 /* addon_server_info.hpp in Headers */,
|
||||
7C4740B081A838A09779FAAA /* attributes.hpp in Headers */,
|
||||
63B0402A889C6663911DC677 /* reachmap_options.hpp in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -5963,6 +5973,7 @@
|
|||
99494BD0ABBAE79FB3814E00 /* charconv.cpp in Sources */,
|
||||
04DC4E59AEDBC1A0AFDCA8CC /* units_dialog.cpp in Sources */,
|
||||
DA2B4478B9C7AB102479C322 /* addon_server_info.cpp in Sources */,
|
||||
0813449DBC67700714FA3ACD /* attributes.cpp in Sources */,
|
||||
6C4A4F7982769422C51DC3E6 /* reachmap_options.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -6637,6 +6648,7 @@
|
|||
355942A786D57DD0A6A93E2A /* units_dialog.cpp in Sources */,
|
||||
52074B55B6C7AC8A1AE8BEA8 /* addon_server_info.cpp in Sources */,
|
||||
144E49509EAC409649899BD4 /* test_lua_ptr.cpp in Sources */,
|
||||
38C444C497ECBE2DF9BB2319 /* attributes.cpp in Sources */,
|
||||
E875402885AA34096C34E3B0 /* reachmap_options.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
|
@ -8,6 +8,7 @@ display.cpp
|
|||
display_context.cpp
|
||||
events.cpp
|
||||
floating_label.cpp
|
||||
font/attributes.cpp
|
||||
font/font_config.cpp
|
||||
font/sdl_ttf_compat.cpp
|
||||
font/standard_colors.cpp
|
||||
|
|
174
src/font/attributes.cpp
Normal file
174
src/font/attributes.cpp
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
Copyright (C) 2025
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "font/attributes.hpp"
|
||||
#include "font/font_config.hpp"
|
||||
|
||||
#include "color.hpp"
|
||||
#include "gui/core/log.hpp"
|
||||
#include "preferences/preferences.hpp"
|
||||
#include "tstring.hpp"
|
||||
#include "video.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace font
|
||||
{
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* Private helper class to manage a single PangoAttribute.
|
||||
*
|
||||
* This object owns its attribute until relinquished to an attribute_list
|
||||
* by calling @ref add_to or @ref modify_in.
|
||||
*/
|
||||
class attribute
|
||||
{
|
||||
public:
|
||||
attribute(PangoAttribute* attr, unsigned offset_start, unsigned offset_end)
|
||||
: value_(attr, &pango_attribute_destroy)
|
||||
{
|
||||
attr->start_index = offset_start;
|
||||
attr->end_index = offset_end;
|
||||
}
|
||||
|
||||
void add_to(font::attribute_list& list)
|
||||
{
|
||||
list.insert(value_.release());
|
||||
}
|
||||
|
||||
void modify_in(font::attribute_list& list)
|
||||
{
|
||||
list.modify(value_.release());
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<PangoAttribute, void(*)(PangoAttribute*)> value_;
|
||||
};
|
||||
|
||||
/** Pango sometimes handles colors as 16 bit integers. */
|
||||
constexpr std::tuple<uint16_t, uint16_t, uint16_t> color_to_uint16(const color_t& color)
|
||||
{
|
||||
return {
|
||||
color.r / 255.0 * std::numeric_limits<uint16_t>::max(),
|
||||
color.g / 255.0 * std::numeric_limits<uint16_t>::max(),
|
||||
color.b / 255.0 * std::numeric_limits<uint16_t>::max()
|
||||
};
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
void add_attribute_size(attribute_list& list, unsigned offset_start, unsigned offset_end, int size)
|
||||
{
|
||||
// TODO: we shouldn't be doing scaling stuff here...
|
||||
size = prefs::get().font_scaled(size) * video::get_pixel_scale();
|
||||
|
||||
attribute attr {
|
||||
pango_attr_size_new_absolute(PANGO_SCALE * size),
|
||||
offset_start, offset_end
|
||||
};
|
||||
|
||||
DBG_GUI_D << "attribute: size";
|
||||
DBG_GUI_D << "attribute start: " << offset_start << " end : " << offset_end;
|
||||
|
||||
attr.add_to(list);
|
||||
}
|
||||
|
||||
void add_attribute_weight(attribute_list& list, unsigned offset_start, unsigned offset_end, PangoWeight weight)
|
||||
{
|
||||
attribute attr {
|
||||
pango_attr_weight_new(weight),
|
||||
offset_start, offset_end
|
||||
};
|
||||
|
||||
DBG_GUI_D << "attribute: weight";
|
||||
DBG_GUI_D << "attribute start: " << offset_start << " end : " << offset_end;
|
||||
|
||||
attr.add_to(list);
|
||||
}
|
||||
|
||||
void add_attribute_style(attribute_list& list, unsigned offset_start, unsigned offset_end, PangoStyle style)
|
||||
{
|
||||
attribute attr {
|
||||
pango_attr_style_new(style),
|
||||
offset_start, offset_end
|
||||
};
|
||||
|
||||
DBG_GUI_D << "attribute: style";
|
||||
DBG_GUI_D << "attribute start: " << offset_start << " end : " << offset_end;
|
||||
|
||||
attr.add_to(list);
|
||||
}
|
||||
|
||||
void add_attribute_underline(attribute_list& list, unsigned offset_start, unsigned offset_end, PangoUnderline underline)
|
||||
{
|
||||
attribute attr {
|
||||
pango_attr_underline_new(underline),
|
||||
offset_start, offset_end
|
||||
};
|
||||
|
||||
DBG_GUI_D << "attribute: underline";
|
||||
DBG_GUI_D << "attribute start: " << offset_start << " end : " << offset_end;
|
||||
|
||||
attr.add_to(list);
|
||||
}
|
||||
|
||||
void add_attribute_fg_color(attribute_list& list, unsigned offset_start, unsigned offset_end, const color_t& color)
|
||||
{
|
||||
auto [col_r, col_g, col_b] = color_to_uint16(color);
|
||||
|
||||
attribute attr {
|
||||
pango_attr_foreground_new(col_r, col_g, col_b),
|
||||
offset_start, offset_end
|
||||
};
|
||||
|
||||
DBG_GUI_D << "attribute: fg color";
|
||||
DBG_GUI_D << "attribute start: " << offset_start << " end : " << offset_end;
|
||||
DBG_GUI_D << "color: " << col_r << "," << col_g << "," << col_b;
|
||||
|
||||
attr.add_to(list);
|
||||
}
|
||||
|
||||
void add_attribute_bg_color(attribute_list& list, unsigned offset_start, unsigned offset_end, const color_t& color)
|
||||
{
|
||||
auto [col_r, col_g, col_b] = color_to_uint16(color);
|
||||
|
||||
attribute attr {
|
||||
pango_attr_background_new(col_r, col_g, col_b),
|
||||
offset_start, offset_end
|
||||
};
|
||||
|
||||
DBG_GUI_D << "highlight start: " << offset_start << "end : " << offset_end;
|
||||
DBG_GUI_D << "highlight color: " << col_r << "," << col_g << "," << col_b;
|
||||
|
||||
attr.modify_in(list);
|
||||
}
|
||||
|
||||
void add_attribute_font_family(attribute_list& list, unsigned offset_start, unsigned offset_end, font::family_class family)
|
||||
{
|
||||
const t_string& family_name = get_font_families(family);
|
||||
|
||||
attribute attr {
|
||||
pango_attr_family_new(family_name.c_str()),
|
||||
offset_start, offset_end
|
||||
};
|
||||
|
||||
DBG_GUI_D << "attribute: font family";
|
||||
DBG_GUI_D << "attribute start: " << offset_start << " end : " << offset_end;
|
||||
DBG_GUI_D << "font family: " << family;
|
||||
|
||||
attr.add_to(list);
|
||||
}
|
||||
|
||||
} // namespace font
|
148
src/font/attributes.hpp
Normal file
148
src/font/attributes.hpp
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
Copyright (C) 2025
|
||||
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pango/pango-layout.h>
|
||||
|
||||
#include "font/font_options.hpp"
|
||||
|
||||
struct color_t;
|
||||
|
||||
namespace font
|
||||
{
|
||||
/** Helper class to encapsulate the management of a PangoAttrList. */
|
||||
class attribute_list
|
||||
{
|
||||
public:
|
||||
attribute_list()
|
||||
: attributes_(pango_attr_list_new())
|
||||
{
|
||||
}
|
||||
|
||||
~attribute_list()
|
||||
{
|
||||
pango_attr_list_unref(attributes_);
|
||||
}
|
||||
|
||||
attribute_list(const attribute_list&) = delete;
|
||||
attribute_list& operator=(const attribute_list&) = delete;
|
||||
|
||||
void insert(PangoAttribute* attr)
|
||||
{
|
||||
pango_attr_list_insert(attributes_, attr);
|
||||
}
|
||||
|
||||
void modify(PangoAttribute* attr)
|
||||
{
|
||||
pango_attr_list_change(attributes_, attr);
|
||||
}
|
||||
|
||||
void apply_to(PangoLayout* layout) const
|
||||
{
|
||||
pango_layout_set_attributes(layout, attributes_);
|
||||
}
|
||||
|
||||
void splice_into(PangoAttrList* target) const
|
||||
{
|
||||
pango_attr_list_splice(target, attributes_, 0, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
PangoAttrList* attributes_;
|
||||
};
|
||||
|
||||
//
|
||||
// The following free functions are thin wrappers around the corresponding
|
||||
// pango_attr_new methods. For more details, refer to the Pango docs.
|
||||
//
|
||||
|
||||
/**
|
||||
* Add Pango font weight attribute to a specific portion of text. This changes the font weight
|
||||
* of the corresponding part of the text.
|
||||
*
|
||||
* @param list The attribute list to which to append this attribute.
|
||||
* @param offset_start Byte index of the cursor where font weight change starts
|
||||
* @param offset_end Byte index of the cursor where font weight change ends
|
||||
* @param weight Pango font weight
|
||||
*/
|
||||
void add_attribute_weight(attribute_list& list, unsigned offset_start, unsigned offset_end, PangoWeight weight);
|
||||
|
||||
/**
|
||||
* Add Pango font style attribute to a specific portion of text, used to set italic/oblique text
|
||||
*
|
||||
* @param list The attribute list to which to append this attribute.
|
||||
* @param offset_start Byte index of the cursor where font style change starts
|
||||
* @param offset_end Byte index of the cursor where font style change ends
|
||||
* @param style Pango font style (normal/italic/oblique)
|
||||
*/
|
||||
void add_attribute_style(attribute_list& list, unsigned offset_start, unsigned offset_end, PangoStyle style);
|
||||
|
||||
/**
|
||||
* Add Pango underline attribute to a specific portion of text. This adds an underline to the
|
||||
* corresponding part of the text.
|
||||
*
|
||||
* @param list The attribute list to which to append this attribute.
|
||||
* @param offset_start Byte index of the cursor where underline starts
|
||||
* @param offset_end Byte index of the cursor where underline change ends
|
||||
* @param underline Pango underline style
|
||||
*/
|
||||
void add_attribute_underline(attribute_list& list, unsigned offset_start, unsigned offset_end, PangoUnderline underline);
|
||||
|
||||
/**
|
||||
* Add Pango fg color attribute to a specific portion of text. This changes the foreground
|
||||
* color of the corresponding part of the text.
|
||||
*
|
||||
* @param list The attribute list to which to append this attribute.
|
||||
* @param offset_start Byte index of the cursor where color change starts
|
||||
* @param offset_end Byte index of the cursor where color change ends
|
||||
* @param color Foreground color
|
||||
*/
|
||||
void add_attribute_fg_color(attribute_list& list, unsigned offset_start, unsigned offset_end, const color_t& color);
|
||||
|
||||
/**
|
||||
* Mark a specific portion of text for highlighting. Used for selection box.
|
||||
* BGColor is set in set_text(), this just marks the area to be colored.
|
||||
* Markup not used because the user may enter their own markup or special characters
|
||||
*
|
||||
* @param list The attribute list to which to append this attribute.
|
||||
* @param offset_start Byte index of the cursor where selection/highlight starts
|
||||
* @param offset_end Byte index of the cursor where selection/highlight ends
|
||||
* @param color Highlight/Background color
|
||||
*/
|
||||
void add_attribute_bg_color(attribute_list& list, unsigned offset_start, unsigned offset_end, const color_t& color);
|
||||
|
||||
/**
|
||||
* Add Pango font size attribute to a specific portion of text. This changes the font size
|
||||
* of the corresponding part of the text.
|
||||
*
|
||||
* @param list The attribute list to which to append this attribute.
|
||||
* @param offset_start Byte index of the cursor where size change starts
|
||||
* @param offset_end Byte index of the cursor where size change ends
|
||||
* @param size Font size
|
||||
*/
|
||||
void add_attribute_size(attribute_list& list, unsigned offset_start, unsigned offset_end, int size);
|
||||
|
||||
/**
|
||||
* Add Pango font family attribute to a specific portion of text. This changes
|
||||
* the font family of the corresponding part of the text.
|
||||
*
|
||||
* @param list The attribute list to which to append this attribute.
|
||||
* @param offset_start Byte index of the cursor where size change starts
|
||||
* @param offset_end Byte index of the cursor where size change ends
|
||||
* @param family The font family
|
||||
*/
|
||||
void add_attribute_font_family(attribute_list& list, unsigned offset_start, unsigned offset_end, font::family_class family);
|
||||
|
||||
} // namespace font
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "font/text.hpp"
|
||||
|
||||
#include "font/attributes.hpp"
|
||||
#include "font/font_config.hpp"
|
||||
|
||||
#include "font/pango/escape.hpp"
|
||||
|
@ -32,7 +33,6 @@
|
|||
#include "preferences/preferences.hpp"
|
||||
#include "video.hpp"
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
@ -66,9 +66,6 @@ pango_text::pango_text()
|
|||
, pixel_scale_(1)
|
||||
, surface_buffer_()
|
||||
{
|
||||
// Initialize global list
|
||||
global_attribute_list_ = pango_attr_list_new();
|
||||
|
||||
// With 72 dpi the sizes are the same as with SDL_TTF so hardcoded.
|
||||
pango_cairo_context_set_resolution(context_.get(), 72.0);
|
||||
|
||||
|
@ -305,138 +302,20 @@ int pango_text::xy_to_index(const point& position) const
|
|||
return index;
|
||||
}
|
||||
|
||||
void pango_text::add_attribute_size(const unsigned start_offset, const unsigned end_offset, int size)
|
||||
void pango_text::clear_attributes()
|
||||
{
|
||||
size = prefs::get().font_scaled(size) * pixel_scale_;
|
||||
pango_layout_set_attributes(layout_.get(), nullptr);
|
||||
}
|
||||
|
||||
if (start_offset != end_offset) {
|
||||
PangoAttribute *attr = pango_attr_size_new_absolute(PANGO_SCALE * size);
|
||||
attr->start_index = start_offset;
|
||||
attr->end_index = end_offset;
|
||||
|
||||
DBG_GUI_D << "attribute: size";
|
||||
DBG_GUI_D << "attribute start: " << start_offset << " end : " << end_offset;
|
||||
|
||||
// Insert all attributes
|
||||
pango_attr_list_insert(global_attribute_list_, attr);
|
||||
void pango_text::apply_attributes(const font::attribute_list& attrs)
|
||||
{
|
||||
if(PangoAttrList* current_attrs = pango_layout_get_attributes(layout_.get())) {
|
||||
attrs.splice_into(current_attrs);
|
||||
} else {
|
||||
attrs.apply_to(layout_.get());
|
||||
}
|
||||
}
|
||||
|
||||
void pango_text::add_attribute_weight(const unsigned start_offset, const unsigned end_offset, PangoWeight weight)
|
||||
{
|
||||
if (start_offset != end_offset) {
|
||||
PangoAttribute *attr = pango_attr_weight_new(weight);
|
||||
attr->start_index = start_offset;
|
||||
attr->end_index = end_offset;
|
||||
|
||||
DBG_GUI_D << "attribute: weight";
|
||||
DBG_GUI_D << "attribute start: " << start_offset << " end : " << end_offset;
|
||||
|
||||
// Insert all attributes
|
||||
pango_attr_list_insert(global_attribute_list_, attr);
|
||||
}
|
||||
}
|
||||
|
||||
void pango_text::add_attribute_style(const unsigned start_offset, const unsigned end_offset, PangoStyle style)
|
||||
{
|
||||
if (start_offset != end_offset) {
|
||||
PangoAttribute *attr = pango_attr_style_new(style);
|
||||
attr->start_index = start_offset;
|
||||
attr->end_index = end_offset;
|
||||
|
||||
DBG_GUI_D << "attribute: style";
|
||||
DBG_GUI_D << "attribute start: " << start_offset << " end : " << end_offset;
|
||||
|
||||
// Insert all attributes
|
||||
pango_attr_list_insert(global_attribute_list_, attr);
|
||||
}
|
||||
}
|
||||
|
||||
void pango_text::add_attribute_underline(const unsigned start_offset, const unsigned end_offset, PangoUnderline underline)
|
||||
{
|
||||
if (start_offset != end_offset) {
|
||||
PangoAttribute *attr = pango_attr_underline_new(underline);
|
||||
attr->start_index = start_offset;
|
||||
attr->end_index = end_offset;
|
||||
|
||||
DBG_GUI_D << "attribute: underline";
|
||||
DBG_GUI_D << "attribute start: " << start_offset << " end : " << end_offset;
|
||||
|
||||
// Insert all attributes
|
||||
pango_attr_list_insert(global_attribute_list_, attr);
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
std::tuple<uint16_t, uint16_t, uint16_t> color_to_uint16(const color_t& color)
|
||||
{
|
||||
return {
|
||||
color.r / 255.0 * std::numeric_limits<uint16_t>::max(),
|
||||
color.g / 255.0 * std::numeric_limits<uint16_t>::max(),
|
||||
color.b / 255.0 * std::numeric_limits<uint16_t>::max()
|
||||
};
|
||||
}
|
||||
|
||||
} // end anon namespace
|
||||
|
||||
void pango_text::add_attribute_fg_color(const unsigned start_offset, const unsigned end_offset, const color_t& color)
|
||||
{
|
||||
if (start_offset != end_offset) {
|
||||
auto [col_r, col_g, col_b] = color_to_uint16(color);
|
||||
PangoAttribute *attr = pango_attr_foreground_new(col_r, col_g, col_b);
|
||||
attr->start_index = start_offset;
|
||||
attr->end_index = end_offset;
|
||||
|
||||
DBG_GUI_D << "attribute: fg color";
|
||||
DBG_GUI_D << "attribute start: " << start_offset << " end : " << end_offset;
|
||||
DBG_GUI_D << "color: " << col_r << "," << col_g << "," << col_b;
|
||||
|
||||
// Insert all attributes
|
||||
pango_attr_list_insert(global_attribute_list_, attr);
|
||||
}
|
||||
}
|
||||
|
||||
void pango_text::add_attribute_font_family(const unsigned start_offset, const unsigned end_offset, font::family_class family)
|
||||
{
|
||||
if (start_offset != end_offset) {
|
||||
const t_string& family_name = get_font_families(family);
|
||||
PangoAttribute *attr = pango_attr_family_new(family_name.c_str());
|
||||
attr->start_index = start_offset;
|
||||
attr->end_index = end_offset;
|
||||
|
||||
DBG_GUI_D << "attribute: font family";
|
||||
DBG_GUI_D << "attribute start: " << start_offset << " end : " << end_offset;
|
||||
DBG_GUI_D << "font family: " << family;
|
||||
|
||||
// Insert all attributes
|
||||
pango_attr_list_insert(global_attribute_list_, attr);
|
||||
}
|
||||
}
|
||||
|
||||
void pango_text::add_attribute_bg_color(const unsigned start_offset, const unsigned end_offset, const color_t& color)
|
||||
{
|
||||
// Highlight
|
||||
int col_r = color.r / 255.0 * 65535.0;
|
||||
int col_g = color.g / 255.0 * 65535.0;
|
||||
int col_b = color.b / 255.0 * 65535.0;
|
||||
|
||||
DBG_GUI_D << "highlight start: " << start_offset << "end : " << end_offset;
|
||||
DBG_GUI_D << "highlight color: " << col_r << "," << col_g << "," << col_b;
|
||||
|
||||
PangoAttribute *attr = pango_attr_background_new(col_r, col_g, col_b);
|
||||
attr->start_index = start_offset;
|
||||
attr->end_index = end_offset;
|
||||
|
||||
// Insert all attributes
|
||||
pango_attr_list_change(global_attribute_list_, attr);
|
||||
}
|
||||
|
||||
void pango_text::clear_attribute_list() {
|
||||
global_attribute_list_ = pango_attr_list_new();
|
||||
pango_layout_set_attributes(layout_.get(), global_attribute_list_);
|
||||
}
|
||||
|
||||
bool pango_text::set_text(const std::string& text, const bool markedup)
|
||||
{
|
||||
if(markedup != markedup_text_ || text != text_) {
|
||||
|
@ -461,11 +340,6 @@ bool pango_text::set_text(const std::string& text, const bool markedup)
|
|||
pango_layout_set_text(layout_.get(), narrow.c_str(), narrow.size());
|
||||
}
|
||||
|
||||
pango_layout_set_attributes(layout_.get(), global_attribute_list_);
|
||||
|
||||
// Clear list. Using pango_attr_list_unref() causes segfault
|
||||
global_attribute_list_ = pango_attr_list_new();
|
||||
|
||||
text_ = narrow;
|
||||
length_ = wide.size();
|
||||
markedup_text_ = markedup;
|
||||
|
@ -951,14 +825,6 @@ bool pango_text::set_markup(std::string_view text, PangoLayout& layout)
|
|||
} else {
|
||||
pango_layout_set_markup(&layout, text.data(), text.size());
|
||||
}
|
||||
|
||||
// append any manual attributes to those generated by pango_layout_set_markup
|
||||
PangoAttrList* markup_list = pango_layout_get_attributes(&layout);
|
||||
for (auto* l = pango_attr_list_get_attributes(global_attribute_list_); l != nullptr; l = l->next) {
|
||||
PangoAttribute* attr = static_cast<PangoAttribute*>(l->data);
|
||||
pango_attr_list_change(markup_list, attr);
|
||||
}
|
||||
global_attribute_list_ = markup_list;
|
||||
}
|
||||
|
||||
return valid;
|
||||
|
|
|
@ -35,7 +35,9 @@
|
|||
|
||||
struct point;
|
||||
|
||||
namespace font {
|
||||
namespace font
|
||||
{
|
||||
class attribute_list;
|
||||
|
||||
// add background color and also font markup.
|
||||
|
||||
|
@ -315,74 +317,8 @@ public:
|
|||
|
||||
pango_text& set_add_outline(bool do_add);
|
||||
|
||||
// The following add attribute methods are thin wrappers around the corresponding pango
|
||||
// add attribute methods. For more details, refer to the Pango docs.
|
||||
|
||||
/**
|
||||
* Add pango font weight attribute to a specific portion of text. This changes the font weight
|
||||
* of the corresponding part of the text.
|
||||
* @param start_offset Byte index of the cursor where font weight change starts
|
||||
* @param end_offset Byte index of the cursor where font weight change ends
|
||||
* @param weight Pango font weight
|
||||
*/
|
||||
void add_attribute_weight(const unsigned start_offset, const unsigned end_offset, PangoWeight weight);
|
||||
|
||||
/**
|
||||
* Add pango font style attribute to a specific portion of text, used to set italic/oblique text
|
||||
* @param start_offset Byte index of the cursor where font style change starts
|
||||
* @param end_offset Byte index of the cursor where font style change ends
|
||||
* @param style Pango font style (normal/italic/oblique)
|
||||
*/
|
||||
void add_attribute_style(const unsigned start_offset, const unsigned end_offset, PangoStyle style);
|
||||
|
||||
/**
|
||||
* Add pango underline attribute to a specific portion of text. This adds an underline to the
|
||||
* corresponding part of the text.
|
||||
* @param start_offset Byte index of the cursor where underline starts
|
||||
* @param end_offset Byte index of the cursor where underline change ends
|
||||
* @param underline Pango underline style
|
||||
*/
|
||||
void add_attribute_underline(const unsigned start_offset, const unsigned end_offset, PangoUnderline underline);
|
||||
|
||||
/**
|
||||
* Add pango fg color attribute to a specific portion of text. This changes the foreground
|
||||
* color of the corresponding part of the text.
|
||||
* @param start_offset Byte index of the cursor where color change starts
|
||||
* @param end_offset Byte index of the cursor where color change ends
|
||||
* @param color Foreground color
|
||||
*/
|
||||
void add_attribute_fg_color(const unsigned start_offset, const unsigned end_offset, const color_t& color);
|
||||
|
||||
/**
|
||||
* Mark a specific portion of text for highlighting. Used for selection box.
|
||||
* BGColor is set in set_text(), this just marks the area to be colored.
|
||||
* Markup not used because the user may enter their own markup or special characters
|
||||
* @param start_offset Byte index of the cursor where selection/highlight starts
|
||||
* @param end_offset Byte index of the cursor where selection/highlight ends
|
||||
* @param color Highlight/Background color
|
||||
*/
|
||||
void add_attribute_bg_color(const unsigned start_offset, const unsigned end_offset, const color_t& color);
|
||||
|
||||
/**
|
||||
* Add pango font size attribute to a specific portion of text. This changes the font size
|
||||
* of the corresponding part of the text.
|
||||
* @param start_offset Byte index of the cursor where size change starts
|
||||
* @param end_offset Byte index of the cursor where size change ends
|
||||
* @param size Font size
|
||||
*/
|
||||
void add_attribute_size(const unsigned start_offset, const unsigned end_offset, int size);
|
||||
|
||||
/**
|
||||
* Add pango font family attribute to a specific portion of text. This changes
|
||||
* the font family of the corresponding part of the text.
|
||||
* @param start_offset Byte index of the cursor where size change starts
|
||||
* @param end_offset Byte index of the cursor where size change ends
|
||||
* @param family The font family
|
||||
*/
|
||||
void add_attribute_font_family(const unsigned start_offset, const unsigned end_offset, font::family_class family);
|
||||
|
||||
/** Clears all attributes from the global attribute list */
|
||||
void clear_attribute_list();
|
||||
void clear_attributes();
|
||||
void apply_attributes(const font::attribute_list& attrs);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -481,12 +417,6 @@ private:
|
|||
/** Length of the text. */
|
||||
mutable std::size_t length_;
|
||||
|
||||
/**
|
||||
* Global pango attribute list. All attributes in this list
|
||||
* will be applied one by one to the text
|
||||
*/
|
||||
PangoAttrList* global_attribute_list_;
|
||||
|
||||
/** The pixel scale, used to render high-DPI text. */
|
||||
int pixel_scale_;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "draw.hpp"
|
||||
#include "draw_manager.hpp"
|
||||
#include "font/attributes.hpp"
|
||||
#include "font/text.hpp"
|
||||
#include "formatter.hpp"
|
||||
#include "gettext.hpp"
|
||||
|
@ -438,8 +439,7 @@ void text_shape::draw(wfl::map_formula_callable& variables)
|
|||
return;
|
||||
}
|
||||
|
||||
font::pango_text& text_renderer = font::get_text_renderer();
|
||||
text_renderer.clear_attribute_list();
|
||||
font::attribute_list text_attributes;
|
||||
|
||||
//
|
||||
// Highlight
|
||||
|
@ -450,7 +450,7 @@ void text_shape::draw(wfl::map_formula_callable& variables)
|
|||
for(size_t i = 0; i < std::min(starts.size(), stops.size()); i++) {
|
||||
typed_formula<int> hstart(starts.at(i));
|
||||
typed_formula<int> hstop(stops.at(i));
|
||||
text_renderer.add_attribute_bg_color(hstart(variables), hstop(variables), highlight_color_(variables));
|
||||
add_attribute_bg_color(text_attributes, hstart(variables), hstop(variables), highlight_color_(variables));
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -467,30 +467,33 @@ void text_shape::draw(wfl::map_formula_callable& variables)
|
|||
const unsigned end = attr["end"].to_int(text.size());
|
||||
|
||||
if (name == "color" || name == "fgcolor" || name == "foreground") {
|
||||
text_renderer.add_attribute_fg_color(start, end, attr["value"].empty() ? font::NORMAL_COLOR : font::string_to_color(attr["value"]));
|
||||
} else if (name == "bgcolor"||name == "background") {
|
||||
text_renderer.add_attribute_bg_color(start, end, attr["value"].empty() ? font::GOOD_COLOR : font::string_to_color(attr["value"]));
|
||||
} else if (name == "font_size"||name == "size") {
|
||||
text_renderer.add_attribute_size(start, end, attr["value"].to_int(font::SIZE_NORMAL));
|
||||
} else if (name == "font_family"||name == "face") {
|
||||
text_renderer.add_attribute_font_family(start, end, font::str_to_family_class(attr["value"]));
|
||||
add_attribute_fg_color(text_attributes, start, end, attr["value"].empty() ? font::NORMAL_COLOR : font::string_to_color(attr["value"]));
|
||||
} else if (name == "bgcolor" || name == "background") {
|
||||
add_attribute_bg_color(text_attributes, start, end, attr["value"].empty() ? font::GOOD_COLOR : font::string_to_color(attr["value"]));
|
||||
} else if (name == "font_size" || name == "size") {
|
||||
add_attribute_size(text_attributes, start, end, attr["value"].to_int(font::SIZE_NORMAL));
|
||||
} else if (name == "font_family" || name == "face") {
|
||||
add_attribute_font_family(text_attributes, start, end, font::str_to_family_class(attr["value"]));
|
||||
} else if (name == "weight") {
|
||||
text_renderer.add_attribute_weight(start, end, decode_text_weight(attr["value"]));
|
||||
add_attribute_weight(text_attributes, start, end, decode_text_weight(attr["value"]));
|
||||
} else if (name == "style") {
|
||||
text_renderer.add_attribute_style(start, end, decode_text_style(attr["value"]));
|
||||
add_attribute_style(text_attributes, start, end, decode_text_style(attr["value"]));
|
||||
} else if (name == "bold" || name == "b") {
|
||||
text_renderer.add_attribute_weight(start, end, PANGO_WEIGHT_BOLD);
|
||||
add_attribute_weight(text_attributes, start, end, PANGO_WEIGHT_BOLD);
|
||||
} else if (name == "italic" || name == "i") {
|
||||
text_renderer.add_attribute_style(start, end, PANGO_STYLE_ITALIC);
|
||||
add_attribute_style(text_attributes, start, end, PANGO_STYLE_ITALIC);
|
||||
} else if (name == "underline" || name == "u") {
|
||||
text_renderer.add_attribute_underline(start, end, PANGO_UNDERLINE_SINGLE);
|
||||
add_attribute_underline(text_attributes, start, end, PANGO_UNDERLINE_SINGLE);
|
||||
} else {
|
||||
// Unsupported formatting or normal text
|
||||
text_renderer.add_attribute_weight(start, end, PANGO_WEIGHT_NORMAL);
|
||||
text_renderer.add_attribute_style(start, end, PANGO_STYLE_NORMAL);
|
||||
add_attribute_weight(text_attributes, start, end, PANGO_WEIGHT_NORMAL);
|
||||
add_attribute_style(text_attributes, start, end, PANGO_STYLE_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
font::pango_text& text_renderer = font::get_text_renderer();
|
||||
text_renderer.clear_attributes();
|
||||
|
||||
text_renderer
|
||||
.set_link_aware(link_aware_(variables))
|
||||
.set_link_color(link_color_(variables))
|
||||
|
@ -509,6 +512,9 @@ void text_shape::draw(wfl::map_formula_callable& variables)
|
|||
.set_characters_per_line(characters_per_line_)
|
||||
.set_add_outline(outline_(variables));
|
||||
|
||||
// Do this last so it can merge with attributes from markup
|
||||
text_renderer.apply_attributes(text_attributes);
|
||||
|
||||
wfl::map_formula_callable local_variables(variables);
|
||||
const auto [tw, th] = text_renderer.get_size();
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "cursor.hpp"
|
||||
#include "desktop/clipboard.hpp"
|
||||
#include "font/attributes.hpp"
|
||||
#include "gui/core/gui_definition.hpp"
|
||||
#include "gui/core/log.hpp"
|
||||
#include "gui/core/timer.hpp"
|
||||
|
@ -122,6 +123,13 @@ void text_box_base::set_maximum_length(const std::size_t maximum_length)
|
|||
}
|
||||
}
|
||||
|
||||
void text_box_base::set_highlight_area(const unsigned start_offset, const unsigned end_offset, const color_t& color)
|
||||
{
|
||||
font::attribute_list attrs;
|
||||
add_attribute_bg_color(attrs, start_offset, end_offset, color);
|
||||
text_.apply_attributes(attrs);
|
||||
}
|
||||
|
||||
void text_box_base::set_value(const std::string& text)
|
||||
{
|
||||
if(text != text_.text()) {
|
||||
|
|
|
@ -121,12 +121,9 @@ public:
|
|||
/**
|
||||
* Wrapper function, sets the area between column start and end
|
||||
* offset to be highlighted in a specific color.
|
||||
* See @ref font::pango_text::add_attribute_bg_color.
|
||||
* See @ref font::add_attribute_bg_color.
|
||||
*/
|
||||
void set_highlight_area(const unsigned start_offset, const unsigned end_offset, const color_t& color)
|
||||
{
|
||||
text_.add_attribute_bg_color(start_offset, end_offset, color);
|
||||
}
|
||||
void set_highlight_area(const unsigned start_offset, const unsigned end_offset, const color_t& color);
|
||||
|
||||
/***** ***** ***** setters / getters for members ***** ****** *****/
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user