1 /*
2  *  STFL - The Structured Terminal Forms Language/Library
3  *  Copyright (C) 2006, 2007  Clifford Wolf <clifford@clifford.at>
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 3 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18  *  MA 02110-1301 USA
19  *
20  *  wt_box.c: Widget types 'hbox' and 'vbox'
21  */
22 
23 #include "stfl_internals.h"
24 
25 #include <stdlib.h>
26 #include <string.h>
27 
28 struct box_data {
29 	char type;
30 };
31 
wt_vbox_init(struct stfl_widget * w)32 static void wt_vbox_init(struct stfl_widget *w)
33 {
34 	struct box_data *d = calloc(1, sizeof(struct box_data));
35 	d->type = 'V';
36 	w->internal_data = d;
37 }
38 
wt_hbox_init(struct stfl_widget * w)39 static void wt_hbox_init(struct stfl_widget *w)
40 {
41 	struct box_data *d = calloc(1, sizeof(struct box_data));
42 	d->type = 'H';
43 	w->internal_data = d;
44 }
45 
wt_box_done(struct stfl_widget * w)46 static void wt_box_done(struct stfl_widget *w)
47 {
48 	free(w->internal_data);
49 }
50 
wt_box_prepare(struct stfl_widget * w,struct stfl_form * f)51 static void wt_box_prepare(struct stfl_widget *w, struct stfl_form *f)
52 {
53 	struct box_data *d = w->internal_data;
54 
55 	w->min_w = 0;
56 	w->min_h = 0;
57 
58 	struct stfl_widget *c = w->first_child;
59 	while (c) {
60 		if (stfl_widget_getkv_int(c, L".display", 1)) {
61 			c->type->f_prepare(c, f);
62 			if (d->type == 'H') {
63 				if (w->min_h < c->min_h)
64 					w->min_h = c->min_h;
65 				w->min_w += c->min_w;
66 			} else {
67 				if (w->min_w < c->min_w)
68 					w->min_w = c->min_w;
69 				w->min_h += c->min_h;
70 			}
71 		}
72 		c = c->next_sibling;
73 	}
74 }
75 
wt_box_draw(struct stfl_widget * w,struct stfl_form * f,WINDOW * win)76 static void wt_box_draw(struct stfl_widget *w, struct stfl_form *f, WINDOW *win)
77 {
78 	struct box_data *d = w->internal_data;
79 
80 	int num_dyn_children = 0;
81 	int min_w = 0, min_h = 0;
82 	int i, j;
83 
84 	struct stfl_widget *c = w->first_child;
85 	while (c)
86 	{
87 		if (stfl_widget_getkv_int(c, L".display", 1))
88 		{
89 			int size_w = stfl_widget_getkv_int(c, L".width", 0);
90 			if (size_w < c->min_w) size_w = c->min_w;
91 
92 			int size_h = stfl_widget_getkv_int(c, L".height", 0);
93 			if (size_h < c->min_h) size_h = c->min_h;
94 
95 			if (wcschr(stfl_widget_getkv_str(c, L".expand", L"vh"),
96 					d->type == 'H' ? 'h' : 'v'))
97 				num_dyn_children++;
98 
99 			if (d->type == 'H') {
100 				min_w += size_w;
101 				if (min_h < size_h)
102 					min_h = size_h;
103 			} else {
104 				min_h += size_h;
105 				if (min_w < size_w)
106 					min_w = size_w;
107 			}
108 		}
109 		c = c->next_sibling;
110 	}
111 
112 	int box_x = w->x, box_y = w->y;
113 	int box_w = w->w, box_h = w->h;
114 
115 	stfl_widget_style(w, f, win);
116 	for (i=box_x; i<box_x+box_w; i++)
117 	for (j=box_y; j<box_y+box_h; j++)
118 		mvwaddch(win, j, i, ' ');
119 
120 	const wchar_t *tie = stfl_widget_getkv_str(w, L"tie", L"lrtb");
121 
122 	if (!wcschr(tie, L'l') && !wcschr(tie, L'r')) box_x += (box_w-min_w)/2;
123 	if (!wcschr(tie, L'l') &&  wcschr(tie, L'r')) box_x += box_w-min_w;
124 	if (!wcschr(tie, L'l') || !wcschr(tie, L'r')) box_w = min_w;
125 
126 	if (!wcschr(tie, L't') && !wcschr(tie, L'b')) box_y += (box_h-min_h)/2;
127 	if (!wcschr(tie, L't') &&  wcschr(tie, L'b')) box_y += box_h-min_h;
128 	if (!wcschr(tie, L't') || !wcschr(tie, L'b')) box_h = min_h;
129 
130 	int sizes_extra = (d->type == 'H' ? box_w - min_w : box_h - min_h);
131 	int cursor = (d->type == 'H' ? box_x : box_y);
132 
133 	c = w->first_child;
134 	for (i=0; c; i++)
135 	{
136 		if (stfl_widget_getkv_int(c, L".display", 1))
137 		{
138 			int size = stfl_widget_getkv_int(c,
139 					d->type == 'H' ? L".width" : L".height", 0);
140 
141 			if (size < (d->type == 'H' ? c->min_w : c->min_h))
142 				size = d->type == 'H' ? c->min_w : c->min_h;
143 
144 			if (wcschr(stfl_widget_getkv_str(c, L".expand", L"vh"),
145 					d->type == 'H' ? 'h' : 'v')) {
146 				int extra = sizes_extra / num_dyn_children--;
147 				sizes_extra -= extra;
148 				size += extra;
149 			}
150 
151 			if (d->type == 'H') {
152 				c->y = box_y;
153 				c->x = cursor;
154 				c->h = box_h;
155 				c->w = size;
156 				cursor += c->w;
157 			} else {
158 				c->x = box_x;
159 				c->y = cursor;
160 				c->w = box_w;
161 				c->h = size;
162 				cursor += c->h;
163 			}
164 
165 			tie = stfl_widget_getkv_str(c, L".tie", L"lrtb");
166 
167 			if (!wcschr(tie, L'l') && !wcschr(tie, L'r')) c->x += (c->w - c->min_w)/2;
168 			if (!wcschr(tie, L'l') &&  wcschr(tie, L'r')) c->x += c->w - c->min_w;
169 			if (!wcschr(tie, L'l') || !wcschr(tie, L'r')) c->w = c->min_w;
170 
171 			if (!wcschr(tie, L't') && !wcschr(tie, L'b')) c->y += (c->h - c->min_h)/2;
172 			if (!wcschr(tie, L't') &&  wcschr(tie, L'b')) c->y += c->h - c->min_h;
173 			if (!wcschr(tie, L't') || !wcschr(tie, L'b')) c->h = c->min_h;
174 
175 			c->type->f_draw(c, f, win);
176 		}
177 		c = c->next_sibling;
178 	}
179 }
180 
wt_box_process(struct stfl_widget * w,struct stfl_widget * fw,struct stfl_form * f,wchar_t ch,int isfunckey)181 static int wt_box_process(struct stfl_widget *w, struct stfl_widget *fw, struct stfl_form *f, wchar_t ch, int isfunckey)
182 {
183 	struct box_data *d = w->internal_data;
184 
185 	if (d->type == 'H')
186 	{
187 		if (stfl_matchbind(w, ch, isfunckey, L"left", L"LEFT"))
188 			return stfl_focus_prev(w, fw, f);
189 		if (stfl_matchbind(w, ch, isfunckey, L"right", L"RIGHT"))
190 			return stfl_focus_next(w, fw, f);
191 	}
192 
193 	if (d->type == 'V')
194 	{
195 		if (stfl_matchbind(w, ch, isfunckey, L"up", L"UP"))
196 			return stfl_focus_prev(w, fw, f);
197 		if (stfl_matchbind(w, ch, isfunckey, L"down", L"DOWN"))
198 			return stfl_focus_next(w, fw, f);
199 	}
200 
201 	return 0;
202 }
203 
204 struct stfl_widget_type stfl_widget_type_vbox = {
205 	L"vbox",
206 	wt_vbox_init,
207 	wt_box_done,
208 	0, // f_enter
209 	0, // f_leave
210 	wt_box_prepare,
211 	wt_box_draw,
212 	wt_box_process
213 };
214 
215 struct stfl_widget_type stfl_widget_type_hbox = {
216 	L"hbox",
217 	wt_hbox_init,
218 	wt_box_done,
219 	0, // f_enter
220 	0, // f_leave
221 	wt_box_prepare,
222 	wt_box_draw,
223 	wt_box_process
224 };
225 
226