libfort/src/cell.c

340 lines
14 KiB
C
Raw Normal View History

2018-01-17 19:22:57 +01:00
#include "cell.h"
2018-11-03 21:50:30 +01:00
#include "properties.h"
2018-01-17 19:22:57 +01:00
#include "string_buffer.h"
2018-05-06 12:12:28 +02:00
#include <assert.h>
2018-01-17 19:22:57 +01:00
2018-03-31 12:33:37 +02:00
struct fort_cell {
2018-01-17 19:22:57 +01:00
string_buffer_t *str_buffer;
2018-05-02 16:55:29 +02:00
enum CellType cell_type;
2018-01-17 19:22:57 +01:00
};
FT_INTERNAL
2018-03-31 12:33:37 +02:00
fort_cell_t *create_cell(void)
2018-01-17 19:22:57 +01:00
{
fort_cell_t *cell = (fort_cell_t *)F_CALLOC(sizeof(fort_cell_t), 1);
2018-01-17 19:22:57 +01:00
if (cell == NULL)
return NULL;
2018-03-05 19:08:14 +01:00
cell->str_buffer = create_string_buffer(DEFAULT_STR_BUF_SIZE, CharBuf);
2018-01-17 19:22:57 +01:00
if (cell->str_buffer == NULL) {
F_FREE(cell);
return NULL;
}
2018-05-02 16:55:29 +02:00
cell->cell_type = CommonCell;
2018-01-17 19:22:57 +01:00
return cell;
}
FT_INTERNAL
2018-01-17 19:22:57 +01:00
void destroy_cell(fort_cell_t *cell)
{
if (cell == NULL)
return;
destroy_string_buffer(cell->str_buffer);
F_FREE(cell);
}
2018-11-02 22:16:20 +01:00
FT_INTERNAL
fort_cell_t *copy_cell(fort_cell_t *cell)
{
assert(cell);
fort_cell_t *result = create_cell();
2019-01-02 07:52:31 +01:00
if (result == NULL)
return NULL;
2018-11-02 22:16:20 +01:00
destroy_string_buffer(result->str_buffer);
result->str_buffer = copy_string_buffer(cell->str_buffer);
if (result->str_buffer == NULL) {
destroy_cell(result);
return NULL;
}
result->cell_type = cell->cell_type;
return result;
}
FT_INTERNAL
2018-05-02 16:55:29 +02:00
void set_cell_type(fort_cell_t *cell, enum CellType type)
{
assert(cell);
cell->cell_type = type;
}
FT_INTERNAL
2018-05-02 16:55:29 +02:00
enum CellType get_cell_type(const fort_cell_t *cell)
{
assert(cell);
return cell->cell_type;
}
FT_INTERNAL
2018-11-10 07:58:21 +01:00
size_t hint_width_cell(const fort_cell_t *cell, const context_t *context, enum request_geom_type geom)
2018-01-17 19:22:57 +01:00
{
/* todo:
* At the moment min width includes paddings. Maybe it is better that min width weren't include
* paddings but be min width of the cell content without padding
*/
2018-01-17 19:22:57 +01:00
assert(cell);
assert(context);
2018-11-03 21:50:30 +01:00
size_t cell_padding_left = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_LEFT_PADDING);
size_t cell_padding_right = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_RIGHT_PADDING);
2018-04-17 19:14:50 +02:00
size_t result = cell_padding_left + cell_padding_right;
if (cell->str_buffer && cell->str_buffer->str.data) {
2018-01-17 19:22:57 +01:00
result += buffer_text_width(cell->str_buffer);
}
2018-11-03 21:50:30 +01:00
result = MAX(result, (size_t)get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_MIN_WIDTH));
2018-11-10 07:58:21 +01:00
if (geom == INTERN_REPR_GEOMETRY) {
char cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_style_tag_for_cell(context->table_properties, context->row, context->column, cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
result += strlen(cell_style_tag);
char reset_cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_reset_style_tag_for_cell(context->table_properties, context->row, context->column, reset_cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
result += strlen(reset_cell_style_tag);
char content_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_style_tag_for_content(context->table_properties, context->row, context->column, content_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
result += strlen(content_style_tag);
char reset_content_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_reset_style_tag_for_content(context->table_properties, context->row, context->column, reset_content_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
result += strlen(reset_content_style_tag);
}
2018-01-17 19:22:57 +01:00
return result;
}
FT_INTERNAL
2018-04-17 19:14:50 +02:00
size_t hint_height_cell(const fort_cell_t *cell, const context_t *context)
2018-01-17 19:22:57 +01:00
{
assert(cell);
assert(context);
2018-11-03 21:50:30 +01:00
size_t cell_padding_top = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_TOP_PADDING);
size_t cell_padding_bottom = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_BOTTOM_PADDING);
size_t cell_empty_string_height = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_EMPTY_STR_HEIGHT);
2018-04-17 19:14:50 +02:00
size_t result = cell_padding_top + cell_padding_bottom;
if (cell->str_buffer && cell->str_buffer->str.data) {
2018-01-17 19:22:57 +01:00
size_t text_height = buffer_text_height(cell->str_buffer);
2018-02-27 19:41:58 +01:00
result += text_height == 0 ? cell_empty_string_height : text_height;
2018-01-17 19:22:57 +01:00
}
return result;
}
FT_INTERNAL
2018-03-29 20:25:04 +02:00
int cell_printf(fort_cell_t *cell, size_t row, char *buf, size_t buf_len, const context_t *context)
2018-01-17 19:22:57 +01:00
{
2018-05-02 20:16:41 +02:00
const char *space_char = " ";
2018-11-10 07:58:21 +01:00
int (*buffer_printf_)(string_buffer_t *, size_t, char *, size_t, const context_t *, const char *, const char *) = buffer_printf;
2018-05-02 20:16:41 +02:00
int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings;
2018-01-21 09:19:18 +01:00
if (cell == NULL || buf_len == 0
2018-11-10 07:58:21 +01:00
|| (buf_len <= hint_width_cell(cell, context, VISIBLE_GEOMETRY))) {
2018-01-17 19:22:57 +01:00
return -1;
}
2018-11-03 21:50:30 +01:00
unsigned int cell_padding_top = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_TOP_PADDING);
unsigned int cell_padding_left = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_LEFT_PADDING);
unsigned int cell_padding_right = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_RIGHT_PADDING);
2018-02-27 19:41:58 +01:00
2019-01-01 17:55:00 +01:00
size_t written = 0;
size_t invisible_written = 0;
2018-11-10 07:58:21 +01:00
int tmp = 0;
/* todo: Dirty hack with changing buf_len! need refactoring. */
/* Also maybe it is better to move all struff with colors to buffers? */
char cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_style_tag_for_cell(context->table_properties, context->row, context->column, cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
buf_len += strlen(cell_style_tag);
char reset_cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_reset_style_tag_for_cell(context->table_properties, context->row, context->column, reset_cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
buf_len += strlen(reset_cell_style_tag);
char content_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_style_tag_for_content(context->table_properties, context->row, context->column, content_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
buf_len += strlen(content_style_tag);
char reset_content_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_reset_style_tag_for_content(context->table_properties, context->row, context->column, reset_content_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
buf_len += strlen(reset_content_style_tag);
/* CELL_STYLE_T LEFT_PADDING CONTENT_STYLE_T CONTENT RESET_CONTENT_STYLE_T RIGHT_PADDING RESET_CELL_STYLE_T
* | | | | | | | |
* L1 R1
* L2 R2
* L3 R3
*/
size_t L2 = cell_padding_left;
size_t R2 = cell_padding_right;
size_t R3 = strlen(reset_cell_style_tag);
#define TOTAL_WRITTEN (written + invisible_written)
#define RIGHT (cell_padding_right + extra_right)
#define WRITE_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, cell_style_tag))
#define WRITE_RESET_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, reset_cell_style_tag))
#define WRITE_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, content_style_tag))
#define WRITE_RESET_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, reset_content_style_tag))
2018-01-21 09:19:18 +01:00
if (row >= hint_height_cell(cell, context)
2018-03-31 12:33:37 +02:00
|| row < cell_padding_top
|| row >= (cell_padding_top + buffer_text_height(cell->str_buffer))) {
2018-11-10 07:58:21 +01:00
WRITE_CELL_STYLE_TAG;
WRITE_CONTENT_STYLE_TAG;
WRITE_RESET_CONTENT_STYLE_TAG;
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len, buf_len - 1 - TOTAL_WRITTEN - R3, space_char));
WRITE_RESET_CELL_STYLE_TAG;
2019-01-01 17:55:00 +01:00
return (int)TOTAL_WRITTEN;
2018-01-17 19:22:57 +01:00
}
2018-03-29 21:18:49 +02:00
2018-11-10 07:58:21 +01:00
WRITE_CELL_STYLE_TAG;
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, L2, space_char));
if (cell->str_buffer) {
CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf_(cell->str_buffer, row - cell_padding_top, buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN - R2 - R3, context, content_style_tag, reset_content_style_tag));
} else {
WRITE_CONTENT_STYLE_TAG;
WRITE_RESET_CONTENT_STYLE_TAG;
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN - R2 - R3, space_char));
}
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, R2, space_char));
WRITE_RESET_CELL_STYLE_TAG;
2018-03-29 21:18:49 +02:00
2019-01-01 17:55:00 +01:00
return (int)TOTAL_WRITTEN;
2018-03-29 21:18:49 +02:00
clear:
return -1;
2018-11-10 07:58:21 +01:00
#undef WRITE_CELL_STYLE_TAG
#undef WRITE_RESET_CELL_STYLE_TAG
#undef WRITE_CONTENT_STYLE_TAG
#undef WRITE_RESET_CONTENT_STYLE_TAG
#undef TOTAL_WRITTEN
#undef RIGHT
2018-01-17 19:22:57 +01:00
}
2018-04-24 20:36:07 +02:00
#ifdef FT_HAVE_WCHAR
FT_INTERNAL
2018-03-29 20:25:04 +02:00
int cell_wprintf(fort_cell_t *cell, size_t row, wchar_t *buf, size_t buf_len, const context_t *context)
2018-03-05 19:08:14 +01:00
{
2018-05-02 20:16:41 +02:00
const char *space_char = " ";
2018-11-10 07:58:21 +01:00
int (*buffer_printf_)(string_buffer_t *, size_t, wchar_t *, size_t, const context_t *, const char *, const char *) = buffer_wprintf;
2018-05-02 20:16:41 +02:00
int (*snprint_n_strings_)(wchar_t *, size_t, size_t, const char *) = wsnprint_n_string;
2018-03-05 19:08:14 +01:00
if (cell == NULL || buf_len == 0
2018-11-10 07:58:21 +01:00
|| (buf_len <= hint_width_cell(cell, context, VISIBLE_GEOMETRY))) {
2018-03-05 19:08:14 +01:00
return -1;
}
2018-11-03 21:50:30 +01:00
unsigned int cell_padding_top = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_TOP_PADDING);
unsigned int cell_padding_left = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_LEFT_PADDING);
unsigned int cell_padding_right = get_cell_property_value_hierarcial(context->table_properties, context->row, context->column, FT_CPROP_RIGHT_PADDING);
2018-03-05 19:08:14 +01:00
2019-01-01 17:55:00 +01:00
size_t written = 0;
size_t invisible_written = 0;
2018-11-10 07:58:21 +01:00
int tmp = 0;
/* todo: Dirty hack with changing buf_len! need refactoring. */
/* Also maybe it is better to move all struff with colors to buffers? */
char cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_style_tag_for_cell(context->table_properties, context->row, context->column, cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
buf_len += strlen(cell_style_tag);
char reset_cell_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_reset_style_tag_for_cell(context->table_properties, context->row, context->column, reset_cell_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
buf_len += strlen(reset_cell_style_tag);
char content_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_style_tag_for_content(context->table_properties, context->row, context->column, content_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
buf_len += strlen(content_style_tag);
char reset_content_style_tag[TEXT_STYLE_TAG_MAX_SIZE];
get_reset_style_tag_for_content(context->table_properties, context->row, context->column, reset_content_style_tag, TEXT_STYLE_TAG_MAX_SIZE);
buf_len += strlen(reset_content_style_tag);
/* CELL_STYLE_T LEFT_PADDING CONTENT_STYLE_T CONTENT RESET_CONTENT_STYLE_T RIGHT_PADDING RESET_CELL_STYLE_T
* | | | | | | | |
* L1 R1
* L2 R2
* L3 R3
*/
size_t L2 = cell_padding_left;
size_t R2 = cell_padding_right;
size_t R3 = strlen(reset_cell_style_tag);
#define TOTAL_WRITTEN (written + invisible_written)
#define RIGHT (right + extra_right)
#define WRITE_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, cell_style_tag))
#define WRITE_RESET_CELL_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, reset_cell_style_tag))
#define WRITE_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, content_style_tag))
#define WRITE_RESET_CONTENT_STYLE_TAG CHCK_RSLT_ADD_TO_INVISIBLE_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, 1, reset_content_style_tag))
2018-03-05 19:08:14 +01:00
if (row >= hint_height_cell(cell, context)
2018-03-31 12:33:37 +02:00
|| row < cell_padding_top
|| row >= (cell_padding_top + buffer_text_height(cell->str_buffer))) {
2018-11-10 07:58:21 +01:00
WRITE_CELL_STYLE_TAG;
WRITE_CONTENT_STYLE_TAG;
WRITE_RESET_CONTENT_STYLE_TAG;
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len, buf_len - 1 - TOTAL_WRITTEN - R3, space_char));
WRITE_RESET_CELL_STYLE_TAG;
2019-01-01 17:55:00 +01:00
return (int)TOTAL_WRITTEN;
2018-03-05 19:08:14 +01:00
}
2018-03-29 21:18:49 +02:00
2018-11-10 07:58:21 +01:00
WRITE_CELL_STYLE_TAG;
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, L2, space_char));
if (cell->str_buffer) {
CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf_(cell->str_buffer, row - cell_padding_top, buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN - R2 - R3, context, content_style_tag, reset_content_style_tag));
} else {
WRITE_CONTENT_STYLE_TAG;
WRITE_RESET_CONTENT_STYLE_TAG;
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN - R2 - R3, space_char));
}
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + TOTAL_WRITTEN, buf_len - TOTAL_WRITTEN, R2, space_char));
WRITE_RESET_CELL_STYLE_TAG;
2018-03-29 21:18:49 +02:00
2019-01-01 17:55:00 +01:00
return (int)TOTAL_WRITTEN;
2018-03-29 21:18:49 +02:00
clear:
return -1;
2018-11-10 07:58:21 +01:00
#undef WRITE_CELL_STYLE_TAG
#undef WRITE_RESET_CELL_STYLE_TAG
#undef WRITE_CONTENT_STYLE_TAG
#undef WRITE_RESET_CONTENT_STYLE_TAG
#undef TOTAL_WRITTEN
#undef RIGHT
2018-03-05 19:08:14 +01:00
}
2018-04-24 20:36:07 +02:00
#endif
2018-01-17 19:22:57 +01:00
FT_INTERNAL
2018-01-17 19:22:57 +01:00
fort_status_t fill_cell_from_string(fort_cell_t *cell, const char *str)
{
assert(str);
assert(cell);
return fill_buffer_from_string(cell->str_buffer, str);
}
2018-04-24 20:36:07 +02:00
#ifdef FT_HAVE_WCHAR
FT_INTERNAL
2018-04-24 20:36:07 +02:00
fort_status_t fill_cell_from_wstring(fort_cell_t *cell, const wchar_t *str)
{
assert(str);
assert(cell);
return fill_buffer_from_wstring(cell->str_buffer, str);
}
#endif
FT_INTERNAL
2018-01-17 19:22:57 +01:00
string_buffer_t *cell_get_string_buffer(fort_cell_t *cell)
{
assert(cell);
assert(cell->str_buffer);
return cell->str_buffer;
}