2018-01-17 19:22:57 +01:00
|
|
|
#include "cell.h"
|
|
|
|
#include "options.h"
|
|
|
|
#include "string_buffer.h"
|
2018-05-06 12:12:28 +02:00
|
|
|
#include <assert.h>
|
2018-01-17 19:22:57 +01:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* CELL
|
|
|
|
* ***************************************************************************/
|
|
|
|
|
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
|
|
|
};
|
|
|
|
|
2018-03-31 12:33:37 +02:00
|
|
|
fort_cell_t *create_cell(void)
|
2018-01-17 19:22:57 +01:00
|
|
|
{
|
2018-03-17 19:53:38 +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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void destroy_cell(fort_cell_t *cell)
|
|
|
|
{
|
|
|
|
if (cell == NULL)
|
|
|
|
return;
|
|
|
|
destroy_string_buffer(cell->str_buffer);
|
|
|
|
F_FREE(cell);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum CellType get_cell_type(const fort_cell_t *cell)
|
|
|
|
{
|
|
|
|
assert(cell);
|
|
|
|
return cell->cell_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-17 19:14:50 +02:00
|
|
|
size_t hint_width_cell(const fort_cell_t *cell, const context_t *context)
|
2018-01-17 19:22:57 +01:00
|
|
|
{
|
2018-02-26 19:47:19 +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-04-17 19:14:50 +02:00
|
|
|
size_t cell_padding_left = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_LEFT_PADDING);
|
|
|
|
size_t cell_padding_right = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_RIGHT_PADDING);
|
|
|
|
size_t result = cell_padding_left + cell_padding_right;
|
2018-03-17 19:53:38 +01:00
|
|
|
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-04-17 19:14:50 +02:00
|
|
|
result = MAX(result, (size_t)get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_MIN_WIDTH));
|
2018-01-17 19:22:57 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
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-04-17 19:14:50 +02:00
|
|
|
size_t cell_padding_top = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_TOP_PADDING);
|
|
|
|
size_t cell_padding_bottom = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_BOTTOM_PADDING);
|
|
|
|
size_t cell_empty_string_height = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_EMPTY_STR_HEIGHT);
|
|
|
|
size_t result = cell_padding_top + cell_padding_bottom;
|
2018-03-17 19:53:38 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns number of lines in cell. If cell is empty or
|
|
|
|
* contains empty string, then 0 is returned.
|
|
|
|
*/
|
2018-03-09 10:44:16 +01:00
|
|
|
/*
|
|
|
|
static int lines_number_cell(fort_cell_t *cell)
|
|
|
|
{
|
|
|
|
assert(cell);
|
|
|
|
if (cell->str_buffer == NULL || cell->str_buffer->str == NULL || cell->str_buffer->str[0] == '\0') {
|
|
|
|
return 0;
|
|
|
|
}
|
2018-01-17 19:22:57 +01:00
|
|
|
|
2018-03-09 10:44:16 +01:00
|
|
|
int result = 0;
|
|
|
|
char *pos = cell->str_buffer->str;
|
|
|
|
while ((pos = strchr(pos, '\n')) != NULL) {
|
|
|
|
result++;
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
return result + 1;
|
|
|
|
}
|
|
|
|
*/
|
2018-01-17 19:22:57 +01:00
|
|
|
|
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-03-31 12:33:37 +02:00
|
|
|
int (*buffer_printf_)(string_buffer_t *, size_t, char *, size_t, const context_t *) = buffer_printf;
|
2018-05-02 20:16:41 +02:00
|
|
|
// int (*snprint_n_chars_)(char *, size_t, size_t, char) = snprint_n_chars;
|
|
|
|
int (*snprint_n_strings_)(char *, size_t, size_t, const char *) = snprint_n_strings;
|
|
|
|
|
2018-03-05 19:08:14 +01:00
|
|
|
|
|
|
|
|
2018-01-21 09:19:18 +01:00
|
|
|
if (cell == NULL || buf_len == 0
|
2018-03-31 12:33:37 +02:00
|
|
|
|| (buf_len <= hint_width_cell(cell, context))) {
|
2018-01-17 19:22:57 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-04-16 21:33:05 +02:00
|
|
|
unsigned int cell_padding_top = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_TOP_PADDING);
|
|
|
|
unsigned int cell_padding_left = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_LEFT_PADDING);
|
|
|
|
unsigned int cell_padding_right = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_RIGHT_PADDING);
|
2018-02-27 19:41:58 +01:00
|
|
|
|
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-05-02 20:16:41 +02:00
|
|
|
return snprint_n_strings_(buf, buf_len, buf_len - 1, space_char);
|
2018-01-17 19:22:57 +01:00
|
|
|
}
|
2018-03-29 21:18:49 +02:00
|
|
|
|
|
|
|
|
2018-03-31 16:54:01 +02:00
|
|
|
int written = 0;
|
|
|
|
int tmp = 0;
|
2018-03-29 21:18:49 +02:00
|
|
|
int left = cell_padding_left;
|
|
|
|
int right = cell_padding_right;
|
|
|
|
|
2018-05-02 20:16:41 +02:00
|
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, left, space_char));
|
2018-03-29 21:18:49 +02:00
|
|
|
|
|
|
|
if (cell->str_buffer)
|
2018-03-31 16:54:01 +02:00
|
|
|
CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf_(cell->str_buffer, row - cell_padding_top, buf + written, buf_len - written - right, context));
|
2018-03-29 21:18:49 +02:00
|
|
|
else
|
2018-05-02 20:16:41 +02:00
|
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, buf_len - written - right, space_char));
|
|
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, right, space_char));
|
2018-03-29 21:18:49 +02:00
|
|
|
|
2018-03-31 16:54:01 +02:00
|
|
|
return written;
|
2018-03-29 21:18:49 +02:00
|
|
|
|
|
|
|
clear:
|
|
|
|
return -1;
|
2018-01-17 19:22:57 +01:00
|
|
|
}
|
|
|
|
|
2018-04-24 20:36:07 +02:00
|
|
|
#ifdef FT_HAVE_WCHAR
|
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-03-31 12:33:37 +02:00
|
|
|
int (*buffer_printf_)(string_buffer_t *, size_t, wchar_t *, size_t, const context_t *) = buffer_wprintf;
|
2018-05-02 20:16:41 +02:00
|
|
|
// int (*snprint_n_chars_)(wchar_t *, size_t, size_t, wchar_t) = wsnprint_n_chars;
|
|
|
|
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-03-31 12:33:37 +02:00
|
|
|
|| (buf_len <= hint_width_cell(cell, context))) {
|
2018-03-05 19:08:14 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-04-16 21:33:05 +02:00
|
|
|
unsigned int cell_padding_top = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_TOP_PADDING);
|
|
|
|
unsigned int cell_padding_left = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_LEFT_PADDING);
|
|
|
|
unsigned int cell_padding_right = get_cell_opt_value_hierarcial(context->table_options, context->row, context->column, FT_COPT_RIGHT_PADDING);
|
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-05-02 20:16:41 +02:00
|
|
|
return snprint_n_strings_(buf, buf_len, buf_len - 1, space_char);
|
2018-03-05 19:08:14 +01:00
|
|
|
}
|
2018-03-29 21:18:49 +02:00
|
|
|
|
2018-03-31 16:54:01 +02:00
|
|
|
int written = 0;
|
|
|
|
int tmp = 0;
|
2018-03-29 21:18:49 +02:00
|
|
|
int left = cell_padding_left;
|
|
|
|
int right = cell_padding_right;
|
|
|
|
|
2018-05-02 20:16:41 +02:00
|
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, left, space_char));
|
2018-03-29 21:18:49 +02:00
|
|
|
|
|
|
|
if (cell->str_buffer)
|
2018-03-31 16:54:01 +02:00
|
|
|
CHCK_RSLT_ADD_TO_WRITTEN(buffer_printf_(cell->str_buffer, row - cell_padding_top, buf + written, buf_len - written - right, context));
|
2018-03-29 21:18:49 +02:00
|
|
|
else
|
2018-05-02 20:16:41 +02:00
|
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, buf_len - written - right, space_char));
|
|
|
|
CHCK_RSLT_ADD_TO_WRITTEN(snprint_n_strings_(buf + written, buf_len - written, right, space_char));
|
2018-03-29 21:18:49 +02:00
|
|
|
|
2018-03-31 16:54:01 +02:00
|
|
|
return written;
|
2018-03-29 21:18:49 +02:00
|
|
|
|
|
|
|
clear:
|
|
|
|
return -1;
|
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
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
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
|
|
|
|
|
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;
|
|
|
|
}
|
2018-03-17 19:53:38 +01:00
|
|
|
|