File: gui_fixedwidth_textarea.cc

package info (click to toggle)
simutrans 111.2.2-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd, wheezy
  • size: 13,504 kB
  • ctags: 12,645
  • sloc: cpp: 101,849; ansic: 3,466; makefile: 694; sh: 44
file content (147 lines) | stat: -rw-r--r-- 3,488 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * Copyright (c) 1997 - 2010 Hansjrg Malthaner
 *
 * This file is part of the Simutrans project under the artistic licence.
 * (see licence.txt)
 */

#include <string.h>

#include "gui_fixedwidth_textarea.h"
#include "../../dataobj/translator.h"
#include "../../utils/cbuffer_t.h"



gui_fixedwidth_textarea_t::gui_fixedwidth_textarea_t(cbuffer_t* buf_, const sint16 width, const koord reserved_area_)
{
	buf = buf_;
	set_width(width);
	set_reserved_area(reserved_area_);
}



void gui_fixedwidth_textarea_t::recalc_size()
{
	calc_display_text(koord::invalid, false);
}



void gui_fixedwidth_textarea_t::set_width(const sint16 width)
{
	if(  width>0  ) {
		// height is simply reset to 0 as it requires recalculation anyway
		gui_komponente_t::set_groesse( koord(width, 0) );
	}
}



void gui_fixedwidth_textarea_t::set_reserved_area(const koord area)
{
	if(  area.x>=0  &&  area.y>=0  ) {
		reserved_area = area;
	}
}



void gui_fixedwidth_textarea_t::set_groesse(koord groesse)
{
	// y-component (height) in groesse is deliberately ignored
	set_width(groesse.x);
}



/* calculates the height of the text that flows around the world_view
 * if draw is true, it will also draw the text
 * borrowed from ding_infowin_t::calc_draw_info() with adaptation
 */
void gui_fixedwidth_textarea_t::calc_display_text(const koord offset, const bool draw)
{
	const bool unicode = translator::get_lang()->utf_encoded;
	KOORD_VAL x=0, word_x=0, y = 0;

	const char* text(*buf);
	const utf8 *p = (const utf8 *)text;
	const utf8 *line_start = p;
	const utf8 *word_start = p;
	const utf8 *line_end  = p;

	// also in unicode *c==0 is end
	while(*p!=0  ||  p!=line_end) {

		// force at end of text or newline
		const KOORD_VAL max_width = ( y<reserved_area.y ) ? get_groesse().x-reserved_area.x : get_groesse().x;

		// smaller than the allowd width?
		do {

			// end of line?
			size_t len = 0;
			uint16 next_char = unicode ? utf8_to_utf16(p, &len) : *p++;
			p += len;

			if(next_char==0  ||  next_char=='\n') {
				line_end = p-1;
				if(  next_char == 0  ) {
					p--;
				}
				word_start = p;
				word_x = 0;
				break;
			}
			// Space: Maybe break here
			else if(  next_char==' '  ||  (next_char >= 0x3000  &&   next_char<0xFE70)  ) {
				// ignore space at start of line
				if(next_char!=' '  ||  x>0) {
					x += (KOORD_VAL)display_get_char_width( next_char );
				}
				word_start = p;
				word_x = 0;
			}
			else {
				// normal char: retrieve and calculate width
				int ch_width = display_get_char_width( next_char );
				x += ch_width;
				word_x += ch_width;
			}
		}	while(  x<max_width  );

		// spaces at the end can be omitted
		line_end = word_start;
		if(line_end==line_start) {
			// too long word for a single line => break the word
			word_start = line_end = p;
			word_x = 0;
		}
		else if(word_start[-1]==' '  ||  word_start[-1]=='\n') {
			line_end --;
		}

		// start of new line or end of text
		if(draw  &&  (line_end-line_start)!=0) {
			display_text_proportional_len_clip( offset.x, offset.y+y, (const char *)line_start, ALIGN_LEFT | DT_DIRTY | DT_CLIP, COL_BLACK, (size_t)(line_end - line_start) );
		}
		y += LINESPACE;
		// back to start of new line
		line_start = word_start;
		x = word_x;
		word_x = 0;
	}

	// reset component height where necessary
	if(  y!=get_groesse().y  ) {
		gui_komponente_t::set_groesse( koord(get_groesse().x, y) );
	}
}



void gui_fixedwidth_textarea_t::zeichnen(koord offset)
{
	calc_display_text(offset + get_pos(), true);
}