Line data Source code
1 : /* Copyright (C) 2006-2012 by George Williams */
2 : /*
3 : * Redistribution and use in source and binary forms, with or without
4 : * modification, are permitted provided that the following conditions are met:
5 :
6 : * Redistributions of source code must retain the above copyright notice, this
7 : * list of conditions and the following disclaimer.
8 :
9 : * Redistributions in binary form must reproduce the above copyright notice,
10 : * this list of conditions and the following disclaimer in the documentation
11 : * and/or other materials provided with the distribution.
12 :
13 : * The name of the author may not be used to endorse or promote products
14 : * derived from this software without specific prior written permission.
15 :
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : */
27 : #include "gdraw.h"
28 : #include "../gdraw/gdrawP.h"
29 : #include "gkeysym.h"
30 : #include "ggadgetP.h"
31 : #include "gwidget.h"
32 : #include "gresource.h"
33 : #include <string.h>
34 : #include <ustring.h>
35 : #include "../fontforge/ffglib.h"
36 : #include <glib/gprintf.h>
37 : #include "xvasprintf.h"
38 :
39 : #define DEL_SPACE 6
40 :
41 : static GBox gmatrixedit_box = GBOX_EMPTY; /* Don't initialize here */
42 : static GBox gmatrixedit_button_box = GBOX_EMPTY; /* Don't initialize here */
43 : static FontInstance *gmatrixedit_font = NULL, *gmatrixedit_titfont = NULL;
44 : static Color gmatrixedit_title_bg = 0x808080, gmatrixedit_title_fg = 0x000000, gmatrixedit_title_divider = 0xffffff;
45 : static Color gmatrixedit_rules = 0x000000;
46 : static Color gmatrixedit_frozencol = 0xff0000,
47 : gmatrixedit_activecol = 0x0000ff, gmatrixedit_activebg=0xffffc0;
48 : static int gmatrixedit_inited = false;
49 :
50 : static struct resed gmatrixedit_re[] = {
51 : {N_("Title Background"), "TitleBG", rt_color, &gmatrixedit_title_bg, N_("Background color of column headers at the top of a matrix edit"), NULL, { 0 }, 0, 0 },
52 : {N_("Title Text Color"), "TitleFG", rt_color, &gmatrixedit_title_fg, N_("Text color of column headers at the top of a matrix edit"), NULL, { 0 }, 0, 0 },
53 : {N_("Title Divider Color"), "TitleDivider", rt_color, &gmatrixedit_title_divider, N_("Color of column dividers in the title section of a matrix edit"), NULL, { 0 }, 0, 0 },
54 : {N_("Rule Color"), "RuleCol", rt_color, &gmatrixedit_rules, N_("Color of column dividers in the main section of a matrix edit"), NULL, { 0 }, 0, 0 },
55 : {N_("Frozen Color"), "FrozenCol", rt_color, &gmatrixedit_frozencol, N_("Color of frozen (unchangeable) entries in the main section of a matrix edit"), NULL, { 0 }, 0, 0 },
56 : {N_("Active Color"), "ActiveCol", rt_color, &gmatrixedit_activecol, N_("Color of the active entry in the main section of a matrix edit"), NULL, { 0 }, 0, 0 },
57 : {N_("Active Background"), "ActiveBG", rt_color, &gmatrixedit_activebg, N_("Background color of the active entry in the main section of a matrix edit"), NULL, { 0 }, 0, 0 },
58 : {N_("Title Font"), "TitleFont", rt_font, &gmatrixedit_titfont, N_("Font used to draw titles of a matrix edit"), NULL, { 0 }, 0, 0 },
59 : RESED_EMPTY
60 : };
61 : static GResInfo gmatrixedit_ri = {
62 : NULL, &ggadget_ri, NULL,NULL,
63 : &gmatrixedit_box,
64 : &gmatrixedit_font,
65 : NULL,
66 : gmatrixedit_re,
67 : N_("Matrix Edit"),
68 : N_("Matrix Edit (sort of like a spreadsheet)"),
69 : "GMatrixEdit",
70 : "Gdraw",
71 : false,
72 : omf_border_type|omf_border_width|omf_border_shape|omf_padding|
73 : omf_main_background|omf_disabled_background,
74 : NULL,
75 : GBOX_EMPTY,
76 : NULL,
77 : NULL,
78 : NULL
79 : };
80 : static GResInfo gmatrixedit2_ri = {
81 : NULL, &ggadget_ri, &gmatrixedit_ri,NULL,
82 : NULL,
83 : NULL,
84 : NULL,
85 : gmatrixedit_re,
86 : N_("Matrix Edit Continued"),
87 : N_("Matrix Edit (sort of like a spreadsheet)"),
88 : "GMatrixEdit",
89 : "Gdraw",
90 : false,
91 : 0,
92 : NULL,
93 : GBOX_EMPTY,
94 : NULL,
95 : NULL,
96 : NULL
97 : };
98 :
99 0 : static void _GMatrixEdit_Init(void) {
100 : FontRequest rq;
101 :
102 0 : if ( gmatrixedit_inited )
103 0 : return;
104 0 : _GGadgetCopyDefaultBox(&gmatrixedit_box);
105 0 : gmatrixedit_box.border_type = bt_none;
106 0 : gmatrixedit_box.border_width = 0;
107 0 : gmatrixedit_box.border_shape = bs_rect;
108 0 : gmatrixedit_box.padding = 0;
109 : /*gmatrixedit_box.flags = 0;*/
110 0 : gmatrixedit_box.main_background = COLOR_TRANSPARENT;
111 0 : gmatrixedit_box.disabled_background = COLOR_TRANSPARENT;
112 0 : GDrawDecomposeFont(_ggadget_default_font,&rq);
113 0 : gmatrixedit_font = GDrawInstanciateFont(NULL,&rq);
114 0 : gmatrixedit_font = _GGadgetInitDefaultBox("GMatrixEdit.",&gmatrixedit_box,gmatrixedit_font);
115 0 : GDrawDecomposeFont(gmatrixedit_font,&rq);
116 0 : rq.point_size = (rq.point_size>=12) ? rq.point_size-2 : rq.point_size>=10 ? rq.point_size-1 : rq.point_size;
117 0 : rq.weight = 700;
118 0 : gmatrixedit_titfont = GResourceFindFont("GMatrixEdit.TitleFont",GDrawInstanciateFont(NULL,&rq));
119 0 : gmatrixedit_title_bg = GResourceFindColor("GMatrixEdit.TitleBG",gmatrixedit_title_bg);
120 0 : gmatrixedit_title_fg = GResourceFindColor("GMatrixEdit.TitleFG",gmatrixedit_title_fg);
121 0 : gmatrixedit_title_divider = GResourceFindColor("GMatrixEdit.TitleDivider",gmatrixedit_title_divider);
122 0 : gmatrixedit_rules = GResourceFindColor("GMatrixEdit.RuleCol",gmatrixedit_rules);
123 0 : gmatrixedit_frozencol = GResourceFindColor("GMatrixEdit.FrozenCol",gmatrixedit_frozencol);
124 0 : gmatrixedit_activecol = GResourceFindColor("GMatrixEdit.ActiveCol",gmatrixedit_activecol);
125 0 : gmatrixedit_activebg = GResourceFindColor("GMatrixEdit.ActiveBG",gmatrixedit_activebg);
126 0 : gmatrixedit_inited = true;
127 :
128 0 : _GGadgetCopyDefaultBox(&gmatrixedit_button_box);
129 0 : gmatrixedit_button_box.border_width = 1;
130 0 : gmatrixedit_button_box.flags |= box_foreground_border_inner;
131 0 : gmatrixedit_button_box.main_background = gmatrixedit_box.main_background;
132 0 : gmatrixedit_button_box.disabled_background = gmatrixedit_box.disabled_background;
133 0 : _GGadgetInitDefaultBox("GMatrixEditButton.",&gmatrixedit_button_box,NULL);
134 : }
135 :
136 0 : static void MatrixDataFree(GMatrixEdit *gme) {
137 : int r,c;
138 :
139 0 : for ( r=0; r<gme->rows; ++r ) for ( c=0; c<gme->cols; ++c ) {
140 0 : if ( gme->col_data[c].me_type == me_string ||
141 0 : gme->col_data[c].me_type == me_bigstr ||
142 0 : gme->col_data[c].me_type == me_stringchoice ||
143 0 : gme->col_data[c].me_type == me_stringchoicetrans ||
144 0 : gme->col_data[c].me_type == me_stringchoicetag ||
145 0 : gme->col_data[c].me_type == me_funcedit ||
146 0 : gme->col_data[c].me_type == me_onlyfuncedit ||
147 0 : gme->col_data[c].me_type == me_button ||
148 0 : gme->col_data[c].me_type == me_func )
149 0 : free( gme->data[r*gme->cols+c].u.md_str );
150 : }
151 0 : free( gme->data );
152 0 : }
153 :
154 0 : static void GMatrixEdit_destroy(GGadget *g) {
155 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
156 : int c, i;
157 :
158 0 : free(gme->newtext);
159 : /* The textfield gme->tf lives in the nested window and doesn't need to be destroyed */
160 0 : if ( gme->vsb!=NULL )
161 0 : GGadgetDestroy(gme->vsb);
162 0 : if ( gme->hsb!=NULL )
163 0 : GGadgetDestroy(gme->hsb);
164 0 : if ( gme->del!=NULL )
165 0 : GGadgetDestroy(gme->del);
166 0 : if ( gme->up!=NULL )
167 0 : GGadgetDestroy(gme->up);
168 0 : if ( gme->down!=NULL )
169 0 : GGadgetDestroy(gme->down);
170 0 : if ( gme->buttonlist!=NULL )
171 0 : for ( i=0; gme->buttonlist[i]!=NULL; ++i )
172 0 : GGadgetDestroy(gme->buttonlist[i]);
173 0 : if ( gme->nested!=NULL ) {
174 0 : GDrawSetUserData(gme->nested,NULL);
175 0 : GDrawDestroyWindow(gme->nested);
176 : }
177 :
178 0 : MatrixDataFree(gme); /* Uses col data */
179 :
180 0 : for ( c=0; c<gme->cols; ++c ) {
181 0 : if ( gme->col_data[c].enum_vals!=NULL )
182 0 : GMenuItemArrayFree(gme->col_data[c].enum_vals);
183 0 : free( gme->col_data[c].title );
184 : }
185 0 : free( gme->col_data );
186 :
187 0 : _ggadget_destroy(g);
188 0 : }
189 :
190 0 : static void GME_FixScrollBars(GMatrixEdit *gme) {
191 : int width;
192 : int lastc;
193 0 : int pagesize = gme->vsb->r.height/(gme->fh+gme->vpad);
194 0 : if ( pagesize<=0 ) pagesize=1;
195 :
196 : /* Editable matrixedits need one extra line, for the <New> button */
197 0 : GScrollBarSetBounds(gme->vsb,0,gme->rows+!gme->no_edit,pagesize);
198 0 : for (lastc=gme->cols-1; lastc>=0 && gme->col_data[lastc].hidden; lastc--);
199 0 : width = gme->col_data[lastc].x + gme->col_data[lastc].width;
200 0 : GScrollBarSetBounds(gme->hsb,0,width,gme->hsb->r.width);
201 0 : }
202 :
203 0 : static void GMatrixEdit_Move(GGadget *g, int32 x, int32 y) {
204 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
205 : int i;
206 :
207 : /* I don't need to move the textfield because it is */
208 : /* nested within the window, and I'm moving the window */
209 0 : if ( gme->vsb!=NULL )
210 0 : _ggadget_move((GGadget *) (gme->vsb),x+(gme->vsb->r.x-g->r.x),
211 0 : y+(gme->vsb->r.y-g->r.y));
212 0 : if ( gme->hsb!=NULL )
213 0 : _ggadget_move((GGadget *) (gme->hsb),x+(gme->hsb->r.x-g->r.x),
214 0 : y+(gme->hsb->r.y-g->r.y));
215 0 : if ( gme->del!=NULL )
216 0 : _ggadget_move((GGadget *) (gme->del),x+(gme->del->r.x-g->r.x),
217 0 : y+(gme->del->r.y-g->r.y));
218 0 : if ( gme->up!=NULL )
219 0 : _ggadget_move((GGadget *) (gme->up),x+(gme->up->r.x-g->r.x),
220 0 : y+(gme->up->r.y-g->r.y));
221 0 : if ( gme->down!=NULL )
222 0 : _ggadget_move((GGadget *) (gme->down),x+(gme->down->r.x-g->r.x),
223 0 : y+(gme->down->r.y-g->r.y));
224 0 : if ( gme->buttonlist!=NULL )
225 0 : for ( i=0; gme->buttonlist[i]!=NULL; ++i )
226 0 : if ( gme->buttonlist[i]!=NULL )
227 0 : _ggadget_move((GGadget *) (gme->buttonlist[i]),x+(gme->buttonlist[i]->r.x-g->r.x),
228 0 : y+(gme->buttonlist[i]->r.y-g->r.y));
229 0 : GDrawMove(gme->nested,x+(g->inner.x-g->r.x),y+(g->inner.y-g->r.y+
230 0 : (gme->has_titles?gme->fh:0)));
231 0 : _ggadget_move(g,x,y);
232 0 : }
233 :
234 0 : static GMenuItem *FindMi(GMenuItem *mi, intpt val ) {
235 : int i;
236 :
237 0 : for ( i=0; mi[i].ti.text!=NULL || mi[i].ti.line; ++i ) {
238 0 : if ( mi[i].ti.userdata == (void *) (intpt) val && mi[i].ti.text!=NULL )
239 0 : return( &mi[i] );
240 : }
241 0 : return( NULL );
242 : }
243 :
244 0 : static int GME_ColWidth(GMatrixEdit *gme, int c) {
245 0 : int width=0, max, cur;
246 0 : FontInstance *old = GDrawSetFont(gme->g.base,gme->font);
247 : char *str, *pt;
248 : int r;
249 : GMenuItem *mi;
250 :
251 0 : if ( gme->col_data[c].hidden )
252 0 : return( 0 );
253 0 : switch ( gme->col_data[c].me_type ) {
254 : case me_int:
255 0 : width = GDrawGetText8Width(gme->g.base,"1234", -1);
256 0 : break;
257 : case me_hex: case me_addr:
258 0 : width = GDrawGetText8Width(gme->g.base,"0xFFFF", -1);
259 0 : break;
260 : case me_uhex:
261 0 : width = GDrawGetText8Width(gme->g.base,"U+FFFF", -1);
262 0 : break;
263 : case me_real:
264 0 : width = GDrawGetText8Width(gme->g.base,"1.234567", -1);
265 0 : break;
266 : case me_enum:
267 0 : max = 0;
268 0 : for ( r=0; r<gme->rows; ++r ) {
269 0 : mi = FindMi(gme->col_data[c].enum_vals,gme->data[r*gme->cols+c].u.md_ival);
270 0 : if ( mi!=NULL ) {
271 0 : if ( mi->ti.text_is_1byte )
272 0 : cur = GDrawGetText8Width(gme->g.base,(char *)mi->ti.text,-1);
273 : else
274 0 : cur = GDrawGetTextWidth(gme->g.base,mi->ti.text,-1);
275 0 : if ( cur>max ) max = cur;
276 : }
277 : }
278 0 : cur = 6 * GDrawGetText8Width(gme->g.base,"n", 1);
279 0 : if ( max<cur )
280 0 : max = cur;
281 0 : width = max;
282 0 : break;
283 : case me_func:
284 : case me_button:
285 : case me_stringchoice: case me_stringchoicetrans: case me_stringchoicetag:
286 : case me_funcedit:
287 : case me_onlyfuncedit:
288 : case me_string: case me_bigstr:
289 0 : max = 0;
290 0 : for ( r=0; r<gme->rows; ++r ) {
291 0 : char *freeme = NULL;
292 0 : str = gme->data[r*gme->cols+c].u.md_str;
293 0 : if ( str==NULL && gme->col_data[c].me_type==me_func )
294 0 : str = freeme = (gme->col_data[c].func)(&gme->g,r,c);
295 0 : if ( str==NULL )
296 0 : continue;
297 : /* use the maximum width of 40 characters to avoid insanely wide
298 : * cells and horizontal scrollbars, the magic number 40 is the max
299 : * length of characters after which we use GME_StrBigEdit below */
300 : char buf[1024];
301 0 : utf8_strncpy(buf, str, 40);
302 0 : pt = strchr(buf,'\n');
303 0 : cur = GDrawGetText8Width(gme->g.base,buf, pt==NULL ? -1: pt-buf);
304 0 : if ( cur>max ) max = cur;
305 0 : free(freeme);
306 : }
307 0 : if ( max < 10*GDrawGetText8Width(gme->g.base,"n", 1) )
308 0 : width = 10*GDrawGetText8Width(gme->g.base,"n", 1);
309 : else
310 0 : width = max;
311 0 : if ( gme->col_data[c].me_type==me_stringchoice ||
312 0 : gme->col_data[c].me_type==me_stringchoicetrans ||
313 0 : gme->col_data[c].me_type==me_stringchoicetag ||
314 0 : gme->col_data[c].me_type==me_onlyfuncedit ||
315 0 : gme->col_data[c].me_type==me_funcedit )
316 0 : width += gme->mark_size + gme->mark_skip;
317 0 : break;
318 : default:
319 0 : width = 0;
320 0 : break;
321 : }
322 0 : if ( gme->col_data[c].title!=NULL ) {
323 0 : GDrawSetFont(gme->g.base,gme->titfont);
324 0 : cur = GDrawGetText8Width(gme->g.base,gme->col_data[c].title, -1);
325 0 : if ( cur>width ) width = cur;
326 : }
327 0 : GDrawSetFont(gme->g.base,old);
328 0 : if ( width>0x7fff )
329 0 : width = 0x7fff;
330 0 : return( width );
331 : }
332 :
333 : static void GME_RedrawTitles(GMatrixEdit *gme);
334 0 : static int GME_AdjustCol(GMatrixEdit *gme,int col) {
335 : int new_width, x,c, changed;
336 : int orig_width, min_width;
337 : int lastc;
338 :
339 0 : changed = false;
340 0 : if ( col==-1 ) {
341 0 : for ( c=0; c<gme->cols; ++c ) if ( !gme->col_data[c].fixed ) {
342 0 : new_width = GME_ColWidth(gme,c);
343 0 : if ( new_width!=gme->col_data[c].width ) {
344 0 : gme->col_data[c].width = new_width;
345 0 : changed = true;
346 : }
347 : }
348 0 : col = 0;
349 0 : } else if ( !gme->col_data[col].fixed ) {
350 0 : new_width = GME_ColWidth(gme,col);
351 0 : if ( new_width!=gme->col_data[col].width ) {
352 0 : gme->col_data[col].width = new_width;
353 0 : changed = true;
354 : }
355 : }
356 0 : if ( changed ) {
357 0 : x = gme->col_data[col].x;
358 0 : for ( c=col; c<gme->cols; ++c ) {
359 0 : gme->col_data[c].x = x;
360 0 : if ( !gme->col_data[c].hidden )
361 0 : x += gme->col_data[c].width + gme->hpad;
362 : }
363 : }
364 0 : for ( lastc=gme->cols-1; lastc>0 && gme->col_data[lastc].hidden; --lastc );
365 0 : if ( !gme->col_data[lastc].fixed ) {
366 0 : orig_width = gme->col_data[lastc].width;
367 0 : min_width = GME_ColWidth(gme,lastc);
368 0 : gme->col_data[lastc].width = (gme->g.inner.width-gme->vsb->r.width-gme->hpad-gme->col_data[lastc].x);
369 0 : if ( gme->col_data[lastc].width<min_width )
370 0 : gme->col_data[lastc].width = min_width;
371 0 : if ( gme->col_data[lastc].width != orig_width )
372 0 : changed = true;
373 : }
374 :
375 0 : if ( changed ) {
376 0 : GME_FixScrollBars(gme);
377 0 : GDrawRequestExpose(gme->nested,NULL,false);
378 0 : GME_RedrawTitles(gme);
379 : }
380 0 : return( changed );
381 : }
382 :
383 0 : static void GMatrixEdit_SetDesiredSize(GGadget *g,GRect *outer,GRect *inner) {
384 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
385 0 : int bp = GBoxBorderWidth(g->base,g->box);
386 :
387 0 : if ( outer!=NULL ) {
388 0 : g->desired_width = outer->width;
389 0 : g->desired_height = outer->height;
390 0 : } else if ( inner!=NULL ) {
391 0 : int extra = 2*bp+ gme->hsb->r.height+ (gme->has_titles?gme->fh:0);
392 0 : if ( gme->del )
393 0 : extra += gme->del->r.height+DEL_SPACE;
394 0 : g->desired_width = inner->width<=0 ? -1 : inner->width+2*bp+gme->vsb->r.width;
395 0 : g->desired_height = inner->height<=0 ? -1 :
396 0 : inner->height<10 ? inner->height*(gme->fh + gme->vpad) + extra :
397 0 : inner->height+extra;
398 : }
399 0 : }
400 :
401 0 : static void GMatrixEdit_GetDesiredSize(GGadget *g,GRect *outer,GRect *inner) {
402 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
403 : int width, height;
404 0 : int bp = GBoxBorderWidth(g->base,g->box);
405 : int c, rows, i;
406 0 : FontInstance *old = GDrawSetFont(gme->g.base,gme->font);
407 0 : int sbwidth = GDrawPointsToPixels(g->base,_GScrollBar_Width);
408 0 : int butwidth = 0;
409 :
410 0 : width = 1;
411 0 : for ( c=0; c<gme->cols; ++c ) {
412 0 : width += GME_ColWidth(gme,c);
413 0 : if ( c!=gme->cols-1 )
414 0 : width += gme->hpad;
415 : }
416 0 : GDrawSetFont(gme->g.base,old);
417 0 : width += sbwidth;
418 :
419 0 : rows = (gme->rows<4) ? 4 : (gme->rows>20) ? 21 : gme->rows+1;
420 0 : height = rows * (gme->fh + gme->vpad);
421 :
422 0 : if ( gme->has_titles )
423 0 : height += gme->fh;
424 0 : height += sbwidth;
425 0 : if ( gme->del ) {
426 0 : height += gme->del->r.height+DEL_SPACE;
427 0 : butwidth += gme->del->r.width + 10;
428 : }
429 0 : if ( gme->up && gme->up->state!=gs_invisible )
430 0 : butwidth += gme->up->r.width+5;
431 0 : if ( gme->down && gme->down->state!=gs_invisible )
432 0 : butwidth += gme->down->r.width+5;
433 0 : if ( gme->buttonlist!=NULL )
434 0 : for ( i=0; gme->buttonlist[i]!=NULL; ++i )
435 0 : if ( gme->buttonlist[i] && gme->buttonlist[i]->state!=gs_invisible )
436 0 : butwidth += gme->buttonlist[i]->r.width+5;
437 0 : if ( butwidth > width )
438 0 : width = butwidth;
439 :
440 0 : if ( g->desired_width>2*bp )
441 0 : width = g->desired_width-2*bp;
442 0 : if ( g->desired_height>2*bp )
443 0 : height = g->desired_height-2*bp;
444 0 : if ( inner!=NULL ) {
445 0 : inner->x = inner->y = 0;
446 0 : inner->width = width;
447 0 : inner->height = height;
448 : }
449 0 : if ( outer!=NULL ) {
450 0 : outer->x = outer->y = 0;
451 0 : outer->width = width + 2*bp;
452 0 : outer->height = height + 2*bp;
453 : }
454 0 : }
455 :
456 : static void GME_PositionEdit(GMatrixEdit *gme);
457 0 : static void GMatrixEdit_Resize(GGadget *g, int32 width, int32 height ) {
458 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
459 0 : int bp = GBoxBorderWidth(g->base,g->box);
460 : int subheight, subwidth;
461 : /*int plus, extra,x,c;*/
462 : int bcnt, i, min_width;
463 : GRect wsize;
464 :
465 0 : width -= 2*bp; height -= 2*bp;
466 :
467 0 : subheight = height -
468 0 : (gme->no_edit && gme->buttonlist==NULL?0:(gme->del->r.height+DEL_SPACE)) -
469 0 : (gme->has_titles?gme->fh:0) -
470 0 : gme->hsb->r.height;
471 0 : subwidth = width - gme->vsb->r.width;
472 0 : GDrawResize(gme->nested,subwidth, subheight);
473 : /* Make sure the dimensions of the internal window are properly set. */
474 : /* We need this because GDrawResize() just notifies WM about the size */
475 : /* changes, but doesn't update the data structures used by FF internally. */
476 : /* This may result into list marks/functional buttons being incorrectly */
477 : /* positioned in their matrix cells when the dialog is displayed. */
478 0 : GDrawGetSize(gme->nested, &wsize);
479 0 : wsize.width = subwidth;
480 0 : wsize.height = subheight;
481 0 : gme->nested->pos = wsize;
482 :
483 0 : GGadgetResize(gme->vsb,gme->vsb->r.width,subheight);
484 0 : GGadgetMove(gme->vsb,gme->g.inner.x + width-2*bp-gme->vsb->r.width,
485 0 : gme->vsb->r.y);
486 0 : GGadgetResize(gme->hsb,subwidth,gme->hsb->r.height);
487 0 : GGadgetMove(gme->hsb,gme->g.inner.x,
488 0 : gme->g.inner.y + height - (gme->del->r.height+DEL_SPACE) - gme->hsb->r.height);
489 0 : GME_FixScrollBars(gme);
490 :
491 0 : bcnt = 1; /* delete */
492 0 : if ( gme->up && gme->up->state!=gs_invisible )
493 0 : bcnt += 2;
494 0 : if ( gme->buttonlist!=NULL ) {
495 0 : for ( i=0; gme->buttonlist[i]!=NULL; ++i )
496 0 : if ( gme->buttonlist[i]->state!=gs_invisible )
497 0 : ++bcnt;
498 : }
499 0 : if ( bcnt==1 && gme->no_edit ) {
500 : /* No delete button to display */
501 0 : } else if ( bcnt==1 ) {
502 0 : GGadgetMove(gme->del,gme->g.inner.x + (width-gme->del->r.width)/2,
503 0 : gme->g.inner.y + height - (gme->del->r.height+DEL_SPACE/2));
504 : } else {
505 0 : int y = gme->g.inner.y + height - (gme->del->r.height+DEL_SPACE/2);
506 0 : int x = gme->g.inner.x + width-5;
507 0 : GGadgetMove(gme->del,gme->g.inner.x + 5, y);
508 0 : if ( gme->up && gme->up->state!=gs_invisible ) {
509 0 : x -= gme->down->r.width;
510 0 : GGadgetMove(gme->down, x, y);
511 0 : x -= 5 + gme->up->r.width;
512 0 : GGadgetMove(gme->up, x, y);
513 0 : x -= 10;
514 : }
515 0 : if ( gme->buttonlist!=NULL ) {
516 0 : for ( i=0; gme->buttonlist[i]!=NULL; ++i )
517 0 : if ( gme->buttonlist[i]->state!=gs_invisible ) {
518 0 : x -= gme->buttonlist[i]->r.width;
519 0 : GGadgetMove(gme->buttonlist[i], x, y);
520 0 : x -= 5;
521 : }
522 : }
523 : }
524 :
525 : /* I thought to leave the columns as they are, but that looks odd */
526 : /* for the last column. Instead put all the extra space in the */
527 : /* last column, but give it some minimal size */
528 0 : min_width = GME_ColWidth(gme,gme->cols-1);
529 0 : gme->col_data[gme->cols-1].width = (subwidth-gme->hpad-gme->col_data[gme->cols-1].x);
530 0 : if ( gme->col_data[gme->cols-1].width<min_width )
531 0 : gme->col_data[gme->cols-1].width = min_width;
532 0 : GME_FixScrollBars(gme);
533 0 : _ggadget_resize(g,width+2*bp, height+2*bp);
534 0 : GME_PositionEdit(gme);
535 0 : GDrawRequestExpose(gme->nested,NULL,false);
536 0 : }
537 :
538 0 : static int GMatrixEdit_Mouse(GGadget *g, GEvent *event) {
539 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
540 0 : int c, nw, i, x, ex = event->u.mouse.x + gme->off_left;
541 :
542 0 : if (( event->type==et_mouseup || event->type==et_mousedown ) &&
543 0 : (event->u.mouse.button>=4 && event->u.mouse.button<=7)) {
544 0 : int isv = event->u.mouse.button<=5;
545 0 : if ( event->u.mouse.state&ksm_shift ) isv = !isv;
546 0 : if ( isv && gme->vsb!=NULL )
547 0 : return( GGadgetDispatchEvent(gme->vsb,event));
548 0 : else if ( !isv && gme->hsb!=NULL )
549 0 : return( GGadgetDispatchEvent(gme->hsb,event));
550 : else
551 0 : return( true );
552 : }
553 :
554 0 : if ( gme->pressed_col>=0 && (event->type==et_mouseup || event->type==et_mousemove)) {
555 0 : c = gme->pressed_col;
556 0 : nw = (ex-gme->g.inner.x-gme->col_data[c].x-gme->hpad/2);
557 0 : if ( ex-gme->g.inner.x < gme->col_data[c].x ) {
558 0 : if ( nw<=0 )
559 0 : nw = 1;
560 : }
561 0 : nw = (ex-gme->g.inner.x-gme->col_data[c].x-gme->hpad/2);
562 0 : x = gme->col_data[c].x;
563 0 : for ( i=c; i<gme->cols; ++i ) {
564 0 : gme->col_data[i].x = x;
565 0 : x += gme->col_data[i].width + gme->hpad;
566 : }
567 0 : gme->col_data[c].width = nw;
568 0 : if ( event->type==et_mouseup )
569 0 : GME_FixScrollBars(gme);
570 0 : GME_RedrawTitles(gme);
571 0 : GME_PositionEdit(gme);
572 0 : GDrawRequestExpose(gme->nested,NULL,false);
573 0 : if ( event->type==et_mouseup ) {
574 0 : GDrawSetCursor(g->base,ct_pointer);
575 0 : gme->pressed_col = -1;
576 : }
577 0 : return( true );
578 : }
579 :
580 0 : if ( !gme->has_titles ||
581 0 : event->u.mouse.x< gme->hsb->r.x || event->u.mouse.x >= gme->hsb->r.x+gme->hsb->r.width ||
582 0 : event->u.mouse.y< gme->g.inner.y || event->u.mouse.y>=gme->g.inner.y+gme->fh ) {
583 0 : if ( gme->lr_pointer ) {
584 0 : gme->lr_pointer = false;
585 0 : GDrawSetCursor(g->base,ct_pointer);
586 : }
587 0 : return( false );
588 : }
589 0 : for ( c=0; c<gme->cols; ++c ) {
590 0 : if ( ex>= gme->g.inner.x + gme->col_data[c].x+gme->col_data[c].width+gme->hpad/2-4 &&
591 0 : ex<= gme->g.inner.x + gme->col_data[c].x+gme->col_data[c].width+gme->hpad/2+4 )
592 0 : break;
593 : }
594 0 : if ( c==gme->cols ) {
595 0 : if ( gme->lr_pointer ) {
596 0 : gme->lr_pointer = false;
597 0 : GDrawSetCursor(g->base,ct_pointer);
598 : }
599 : } else {
600 0 : if ( !gme->lr_pointer ) {
601 0 : gme->lr_pointer = true;
602 0 : GDrawSetCursor(g->base,ct_4way);
603 : }
604 0 : if ( event->type == et_mousedown )
605 0 : gme->pressed_col = c;
606 : }
607 0 : return( true );
608 : }
609 :
610 0 : static int GMatrixEdit_Expose(GWindow pixmap, GGadget *g, GEvent *event) {
611 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
612 : GRect r, old, older;
613 : int c, y, lastc;
614 0 : Color fg = gmatrixedit_title_fg;
615 :
616 0 : if ( gme->g.state!=gs_enabled )
617 0 : fg = gme->g.box->disabled_foreground;
618 :
619 0 : GBoxDrawBorder(pixmap,&g->r,g->box,g->state,false);
620 0 : if ( gme->has_titles ) {
621 0 : r = gme->g.inner;
622 0 : r.height = gme->font_fh;
623 0 : r.width = gme->hsb->r.width;
624 0 : GDrawPushClip(pixmap,&r,&older);
625 0 : GDrawFillRect(pixmap,&r,gmatrixedit_title_bg);
626 0 : y = r.y + gme->font_as;
627 0 : GDrawSetFont(pixmap,gme->titfont);
628 0 : for ( lastc = gme->cols-1; lastc>0 && gme->col_data[lastc].hidden; --lastc );
629 0 : for ( c=0; c<gme->cols; ++c ) {
630 0 : if ( gme->col_data[c].title!=NULL &&
631 0 : !gme->col_data[c].hidden ) {
632 0 : r.x = gme->col_data[c].x + gme->g.inner.x - gme->off_left;
633 0 : r.width = gme->col_data[c].width;
634 0 : GDrawPushClip(pixmap,&r,&old);
635 0 : GDrawDrawText8(pixmap,r.x,y,gme->col_data[c].title,-1,fg);
636 0 : GDrawPopClip(pixmap,&old);
637 : }
638 0 : if ( c!=lastc && !gme->col_data[c].hidden)
639 0 : GDrawDrawLine(pixmap,r.x+gme->col_data[c].width+gme->hpad/2,r.y,
640 0 : r.x+gme->col_data[c].width+gme->hpad/2,r.y+r.height,
641 : gmatrixedit_title_divider);
642 : }
643 0 : GDrawPopClip(pixmap,&older);
644 : }
645 0 : return( true );
646 : }
647 :
648 0 : static void GME_RedrawTitles(GMatrixEdit *gme) {
649 0 : GMatrixEdit_Expose(gme->g.base,&gme->g,NULL);
650 0 : }
651 :
652 0 : static void GMatrixEdit_SetVisible(GGadget *g, int visible ) {
653 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
654 : int i;
655 :
656 0 : if ( gme->vsb!=NULL ) _ggadget_setvisible(gme->vsb,visible);
657 0 : if ( gme->hsb!=NULL ) _ggadget_setvisible(gme->hsb,visible);
658 0 : if ( gme->del!=NULL ) _ggadget_setvisible(gme->del,visible);
659 0 : if ( gme->up!=NULL ) _ggadget_setvisible(gme->up,visible);
660 0 : if ( gme->down!=NULL ) _ggadget_setvisible(gme->down,visible);
661 0 : if ( gme->buttonlist!=NULL )
662 0 : for ( i=0; gme->buttonlist[i]!=NULL; ++i )
663 0 : _ggadget_setvisible(gme->buttonlist[i],visible);
664 :
665 0 : GDrawSetVisible(gme->nested,visible);
666 0 : _ggadget_setvisible(g,visible);
667 0 : }
668 :
669 0 : static void GMatrixEdit_Redraw(GGadget *g ) {
670 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
671 0 : GDrawRequestExpose(gme->nested,NULL,false);
672 0 : _ggadget_redraw(g);
673 0 : }
674 :
675 0 : static char *MD_Text(GMatrixEdit *gme,int r, int c ) {
676 0 : char buffer[20], *str= NULL;
677 0 : struct matrix_data *d = &gme->data[r*gme->cols+c];
678 :
679 0 : switch ( gme->col_data[c].me_type ) {
680 : case me_enum:
681 : /* Fall through into next case */
682 : case me_int:
683 0 : sprintf( buffer,"%d",(int) d->u.md_ival );
684 0 : str = buffer;
685 0 : break;
686 : case me_hex:
687 0 : sprintf( buffer,"0x%x",(int) d->u.md_ival );
688 0 : str = buffer;
689 0 : break;
690 : case me_uhex:
691 0 : sprintf( buffer,"U+%04X",(int) d->u.md_ival );
692 0 : str = buffer;
693 0 : break;
694 : case me_addr:
695 0 : sprintf( buffer,"%p", d->u.md_addr );
696 0 : str = buffer;
697 0 : break;
698 : case me_real:
699 0 : sprintf( buffer,"%g",d->u.md_real );
700 0 : str = buffer;
701 0 : break;
702 : case me_string: case me_bigstr:
703 : case me_funcedit:
704 : case me_onlyfuncedit:
705 : case me_button:
706 : case me_stringchoice: case me_stringchoicetrans: case me_stringchoicetag:
707 0 : str = d->u.md_str;
708 0 : break;
709 : case me_func:
710 0 : str = d->u.md_str;
711 0 : if ( str==NULL )
712 0 : return( (gme->col_data[c].func)(&gme->g,r,c) );
713 0 : break;
714 : }
715 0 : if (!str) str="";
716 0 : return( copy(str));
717 : }
718 :
719 0 : static int GME_RecalcFH(GMatrixEdit *gme) {
720 : int r,c, as, ds;
721 0 : int32 end = -1;
722 : char *str, *ept;
723 : GTextBounds bounds;
724 : GMenuItem *mi;
725 :
726 0 : GDrawSetFont(gme->nested,gme->font);
727 0 : as = gme->font_as; ds = gme->font_fh-as;
728 0 : for ( r=0; r<gme->rows; ++r ) for ( c=0; c<gme->cols; ++c ) {
729 0 : end = -1;
730 0 : switch ( gme->col_data[c].me_type ) {
731 : case me_enum:
732 0 : mi = FindMi(gme->col_data[c].enum_vals,gme->data[r*gme->cols+c].u.md_ival);
733 0 : if ( mi==NULL )
734 0 : continue;
735 0 : str = copy( (char *)mi->ti.text );
736 0 : break;
737 : default:
738 0 : str = MD_Text(gme,r,c);
739 0 : if ( str == NULL )
740 0 : continue;
741 0 : if ( ( ept = strchr(str,'\n') ) != NULL )
742 0 : end = ept - str;
743 0 : break;
744 : }
745 0 : GDrawGetText8Bounds(gme->nested, str, end, &bounds);
746 0 : free(str);
747 0 : if ( bounds.as>as )
748 0 : as = bounds.as;
749 0 : if ( bounds.ds>ds )
750 0 : ds = bounds.ds;
751 : }
752 0 : if ( as!=gme->as || as+ds!=gme->fh ) {
753 0 : gme->fh = as+ds;
754 0 : gme->as = as;
755 0 : return( true );
756 : }
757 0 : return( false );
758 : }
759 :
760 0 : static void GMatrixEdit_SetFont(GGadget *g,FontInstance *new) {
761 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
762 : int as, ds, ld;
763 0 : gme->font = new;
764 0 : GDrawWindowFontMetrics(g->base,gme->font,&as, &ds, &ld);
765 0 : gme->font_as = gme->as = as;
766 0 : gme->font_fh = gme->fh = as+ds;
767 0 : GME_RecalcFH(gme);
768 0 : GME_FixScrollBars(gme);
769 0 : GDrawRequestExpose(gme->nested,NULL,false);
770 0 : }
771 :
772 0 : static FontInstance *GMatrixEdit_GetFont(GGadget *g) {
773 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
774 0 : return( gme->font );
775 : }
776 :
777 0 : static int32 GMatrixEdit_IsSelected(GGadget *g, int32 pos) {
778 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
779 :
780 0 : return( pos==gme->active_row );
781 : }
782 :
783 0 : static int32 GMatrixEdit_GetFirst(GGadget *g) {
784 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
785 :
786 0 : return( gme->active_row );
787 : }
788 :
789 0 : static int GMatrixEdit_FillsWindow(GGadget *g) {
790 0 : return( true );
791 : }
792 :
793 : struct gfuncs gmatrixedit_funcs = {
794 : 0,
795 : sizeof(struct gfuncs),
796 :
797 : GMatrixEdit_Expose,
798 : GMatrixEdit_Mouse,
799 : NULL,
800 : NULL,
801 : NULL,
802 : NULL,
803 : NULL,
804 :
805 : GMatrixEdit_Redraw,
806 : GMatrixEdit_Move,
807 : GMatrixEdit_Resize,
808 : GMatrixEdit_SetVisible,
809 : _ggadget_setenabled,
810 : _ggadget_getsize,
811 : _ggadget_getinnersize,
812 :
813 : GMatrixEdit_destroy,
814 :
815 : NULL,
816 : NULL,
817 : NULL,
818 : NULL,
819 : NULL,
820 : GMatrixEdit_SetFont,
821 : GMatrixEdit_GetFont,
822 :
823 : NULL,
824 : NULL,
825 : NULL,
826 : NULL,
827 : NULL,
828 : NULL,
829 : GMatrixEdit_IsSelected,
830 : GMatrixEdit_GetFirst,
831 : NULL,
832 : NULL,
833 : NULL,
834 :
835 : GMatrixEdit_GetDesiredSize,
836 : GMatrixEdit_SetDesiredSize,
837 : GMatrixEdit_FillsWindow,
838 : NULL
839 : };
840 :
841 0 : static void GME_PositionEdit(GMatrixEdit *gme) {
842 : int x,y,end;
843 : GRect wsize;
844 0 : int c = gme->active_col, r = gme->active_row, lastc;
845 :
846 0 : for ( lastc = gme->cols-1; lastc>0 && gme->col_data[lastc].hidden; --lastc );
847 :
848 0 : if ( gme->edit_active ) {
849 0 : x = gme->col_data[c].x - gme->off_left;
850 0 : y = (r-gme->off_top)*(gme->fh+gme->vpad);
851 0 : end = x + gme->col_data[c].width;
852 :
853 0 : if ( c == lastc ) {
854 0 : GDrawGetSize(gme->nested,&wsize);
855 0 : if ( end>wsize.width )
856 0 : end = wsize.width - x;
857 0 : if ( gme->col_data[c].me_type==me_stringchoice ||
858 0 : gme->col_data[c].me_type==me_stringchoicetrans ||
859 0 : gme->col_data[c].me_type==me_stringchoicetag ||
860 0 : gme->col_data[c].me_type==me_onlyfuncedit ||
861 0 : gme->col_data[c].me_type==me_funcedit )
862 0 : end -= gme->mark_size+gme->mark_skip;
863 : }
864 :
865 0 : GGadgetResize(gme->tf,end-x,gme->fh);
866 0 : GGadgetMove(gme->tf,x,y);
867 : }
868 0 : }
869 :
870 0 : static void GME_StrSmallEdit(GMatrixEdit *gme,char *str, GEvent *event) {
871 0 : gme->edit_active = true;
872 : /* Shift so all of column is in window???? */
873 0 : GME_PositionEdit(gme);
874 0 : GGadgetSetTitle8(gme->tf,str);
875 0 : GGadgetSetVisible(gme->tf,true);
876 0 : GGadgetSetEnabled(gme->tf,true);
877 0 : GCompletionFieldSetCompletion(gme->tf,gme->col_data[gme->active_col].completer);
878 0 : ((GTextField *) (gme->tf))->accepts_tabs = false;
879 0 : ((GTextField *) (gme->tf))->was_completing = gme->col_data[gme->active_col].completer!=NULL;
880 0 : GWidgetIndicateFocusGadget(gme->tf);
881 0 : if ( event->type == et_mousedown )
882 0 : GGadgetDispatchEvent(gme->tf,event);
883 0 : }
884 :
885 0 : static int GME_SetValue(GMatrixEdit *gme,GGadget *g ) {
886 0 : int c = gme->active_col;
887 0 : int r = gme->active_row;
888 : intpt lval;
889 : double dval;
890 0 : char *end="";
891 0 : char *str = GGadgetGetTitle8(g), *pt;
892 : int kludge;
893 :
894 0 : switch ( gme->col_data[c].me_type ) {
895 : case me_enum:
896 : {
897 0 : const unichar_t *ustr = _GGadgetGetTitle(g), *test;
898 : int i;
899 0 : for ( i=0; (test=gme->col_data[c].enum_vals[i].ti.text)!=NULL || gme->col_data[c].enum_vals[i].ti.line ; ++i ) {
900 0 : if ( u_strcmp(ustr,test)==0 ) {
901 0 : if ( (intpt) gme->col_data[c].enum_vals[i].ti.userdata != GME_NoChange )
902 0 : gme->data[r*gme->cols+c].u.md_ival =
903 0 : (intpt) gme->col_data[c].enum_vals[i].ti.userdata;
904 0 : free(str);
905 0 : goto good;
906 : }
907 : }
908 : }
909 : /* Didn't match any of the enums try as a direct integer */
910 : /* Fall through */
911 : case me_int: case me_hex: case me_uhex: case me_addr:
912 0 : if ( gme->validatestr!=NULL )
913 0 : end = (gme->validatestr)(&gme->g,gme->active_row,gme->active_col,gme->wasnew,str);
914 0 : if ( *end=='\0' ) {
915 0 : if ( gme->col_data[c].me_type==me_hex || gme->col_data[c].me_type==me_uhex ) {
916 0 : pt = str;
917 0 : while ( *pt==' ' ) ++pt;
918 0 : if ( (*pt=='u' || *pt=='U') && pt[1]=='+' )
919 0 : pt += 2;
920 0 : else if ( *pt=='0' && (pt[1]=='x' || pt[1]=='X'))
921 0 : pt += 2;
922 0 : lval = strtoul(pt,&end,16);
923 : } else
924 0 : lval = strtol(str,&end,10);
925 : }
926 0 : if ( *end!='\0' ) {
927 0 : GTextFieldSelect(g,end-str,-1);
928 0 : free(str);
929 0 : GDrawBeep(NULL);
930 0 : return( false );
931 : }
932 0 : if ( gme->col_data[c].me_type == me_addr )
933 0 : gme->data[r*gme->cols+c].u.md_addr = (void *) lval;
934 : else
935 0 : gme->data[r*gme->cols+c].u.md_ival = lval;
936 0 : free(str);
937 0 : goto good;
938 : case me_real:
939 0 : if ( gme->validatestr!=NULL )
940 0 : end = (gme->validatestr)(&gme->g,gme->active_row,gme->active_col,gme->wasnew,str);
941 0 : if ( *end=='\0' )
942 0 : dval = strtod(str,&end);
943 0 : if ( *end!='\0' ) {
944 0 : GTextFieldSelect(g,end-str,-1);
945 0 : free(str);
946 0 : GDrawBeep(NULL);
947 0 : return( false );
948 : }
949 0 : gme->data[r*gme->cols+c].u.md_real = dval;
950 0 : free(str);
951 0 : goto good;
952 : case me_stringchoice: case me_stringchoicetrans: case me_stringchoicetag:
953 : case me_funcedit: case me_onlyfuncedit:
954 : case me_string: case me_bigstr: case me_func: case me_button:
955 0 : if ( gme->validatestr!=NULL )
956 0 : end = (gme->validatestr)(&gme->g,gme->active_row,gme->active_col,gme->wasnew,str);
957 0 : if ( *end!='\0' ) {
958 0 : GTextFieldSelect(g,end-str,-1);
959 0 : free(str);
960 0 : GDrawBeep(NULL);
961 0 : return( false );
962 : }
963 :
964 0 : free(gme->data[r*gme->cols+c].u.md_str);
965 0 : gme->data[r*gme->cols+c].u.md_str = str;
966 : /* Used to delete the row if this were a null string. seems extreme */
967 0 : goto good;
968 : default:
969 : /* Eh? Can't happen */
970 0 : GTextFieldSelect(g,0,-1);
971 0 : GDrawBeep(NULL);
972 0 : free(str);
973 0 : return( false );
974 : }
975 : good:
976 0 : kludge = gme->edit_active; gme->edit_active = false;
977 0 : if ( gme->finishedit != NULL )
978 0 : (gme->finishedit)(&gme->g,r,c,gme->wasnew);
979 0 : gme->edit_active = kludge;
980 0 : return( true );
981 : }
982 :
983 0 : static int GME_FinishEdit(GMatrixEdit *gme) {
984 :
985 0 : if ( !gme->edit_active ) {
986 0 : gme->wasnew = false;
987 0 : return( true );
988 : }
989 0 : if ( !GME_SetValue(gme,gme->tf)) {
990 0 : gme->wasnew = false;
991 0 : return( false );
992 : }
993 0 : gme->edit_active = false;
994 0 : GGadgetSetVisible(gme->tf,false);
995 0 : GME_AdjustCol(gme,gme->active_col);
996 0 : if ( GME_RecalcFH(gme) ) {
997 0 : GME_FixScrollBars(gme);
998 0 : GDrawRequestExpose(gme->nested,NULL,false);
999 : }
1000 :
1001 0 : gme->wasnew = false;
1002 0 : return( true );
1003 : }
1004 :
1005 : /* Sometimes our data moves underneath us (if the validate function does */
1006 : /* something weird). See if we can move the current row with the data */
1007 0 : static int GME_FinishEditPreserve(GMatrixEdit *gme,int r) {
1008 : int i;
1009 :
1010 0 : if ( r<gme->rows ) {
1011 0 : for ( i=0; i<gme->rows; ++i )
1012 0 : gme->data[i*gme->cols].current = 0;
1013 0 : gme->data[r*gme->cols].current = 1;
1014 : }
1015 0 : if ( !GME_FinishEdit(gme))
1016 0 : return( -1 );
1017 0 : if ( r==gme->rows )
1018 0 : return( r );
1019 0 : for ( i=0; i<gme->rows; ++i )
1020 0 : if ( gme->data[i*gme->cols].current )
1021 0 : return( i );
1022 :
1023 : /* Quite lost */
1024 0 : return( r );
1025 : }
1026 :
1027 0 : static void GME_EnableDelete(GMatrixEdit *gme) {
1028 0 : int enabled = false;
1029 :
1030 0 : if ( gme->setotherbuttons )
1031 0 : (gme->setotherbuttons)(&gme->g,gme->active_row,gme->active_col);
1032 0 : if ( gme->active_row>=0 && gme->active_row<gme->rows ) {
1033 0 : enabled = true;
1034 0 : if ( gme->candelete!=NULL && !(gme->candelete)(&gme->g,gme->active_row))
1035 0 : enabled = false;
1036 : }
1037 0 : GGadgetSetEnabled(gme->del,enabled);
1038 :
1039 0 : if ( gme->up!=NULL ) {
1040 : enum gme_updown updown;
1041 0 : if ( gme->canupdown != NULL )
1042 0 : updown = (gme->canupdown)((GGadget *) gme,gme->active_row);
1043 : else {
1044 0 : updown = 0;
1045 0 : if ( gme->active_row>=1 && gme->active_row<gme->rows )
1046 0 : updown = ud_up_enabled;
1047 0 : if ( gme->active_row>=0 && gme->active_row<gme->rows-1 )
1048 0 : updown |= ud_down_enabled;
1049 : }
1050 0 : GGadgetSetEnabled(gme->up,updown & ud_up_enabled ? 1 : 0);
1051 0 : GGadgetSetEnabled(gme->down,updown & ud_down_enabled ? 1 : 0);
1052 : }
1053 0 : }
1054 :
1055 0 : static void GME_DeleteActive(GMatrixEdit *gme) {
1056 : int r, c;
1057 :
1058 0 : if ( gme->active_row==-1 || (gme->candelete && !(gme->candelete)(&gme->g,gme->active_row))) {
1059 0 : GGadgetSetEnabled(gme->del,false);
1060 0 : GDrawBeep(NULL);
1061 0 : return;
1062 : }
1063 0 : if ( gme->predelete!=NULL )
1064 0 : (gme->predelete)((GGadget *) gme, gme->active_row );
1065 :
1066 0 : gme->edit_active = false;
1067 0 : GGadgetSetVisible(gme->tf,false);
1068 0 : for ( c=0; c<gme->cols; ++c ) {
1069 0 : if ( gme->col_data[c].me_type == me_string || gme->col_data[c].me_type == me_bigstr ||
1070 0 : gme->col_data[c].me_type == me_func || gme->col_data[c].me_type == me_funcedit ||
1071 0 : gme->col_data[c].me_type == me_onlyfuncedit ||
1072 0 : gme->col_data[c].me_type == me_button ||
1073 0 : gme->col_data[c].me_type == me_stringchoice ||
1074 0 : gme->col_data[c].me_type == me_stringchoicetag ||
1075 0 : gme->col_data[c].me_type == me_stringchoicetrans ) {
1076 0 : free(gme->data[gme->active_row*gme->cols+c].u.md_str);
1077 0 : gme->data[gme->active_row*gme->cols+c].u.md_str = NULL;
1078 : }
1079 : }
1080 0 : for ( r=gme->active_row+1; r<gme->rows; ++r )
1081 0 : memcpy(gme->data+(r-1)*gme->cols,gme->data+r*gme->cols,
1082 0 : gme->cols*sizeof(struct matrix_data));
1083 0 : --gme->rows;
1084 0 : gme->active_col = -1;
1085 0 : if ( gme->active_row>=gme->rows ) gme->active_row = -1;
1086 0 : GScrollBarSetBounds(gme->vsb,0,gme->rows,gme->vsb->inner.height/gme->fh);
1087 0 : GDrawRequestExpose(gme->nested,NULL,false);
1088 0 : GME_EnableDelete(gme);
1089 : }
1090 :
1091 0 : void GMatrixEditUp(GGadget *g) {
1092 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
1093 : GRect r;
1094 : int i;
1095 :
1096 0 : if ( gme->active_row<1 || gme->active_row>=gme->rows )
1097 0 : return;
1098 0 : for ( i=0; i<gme->cols; ++i ) {
1099 0 : struct matrix_data md = gme->data[gme->active_row*gme->cols+i];
1100 0 : gme->data[gme->active_row*gme->cols+i] = gme->data[(gme->active_row-1)*gme->cols+i];
1101 0 : gme->data[(gme->active_row-1)*gme->cols+i] = md;
1102 : }
1103 0 : --gme->active_row;;
1104 0 : GGadgetGetSize(gme->tf,&r);
1105 0 : GGadgetMove(gme->tf,r.x,r.y-(gme->fh+1));
1106 0 : GME_EnableDelete(gme);
1107 0 : if ( gme->rowmotion!=NULL )
1108 0 : (gme->rowmotion)((GGadget *) gme, gme->active_row+1,gme->active_row);
1109 0 : GMatrixEditScrollToRowCol(&gme->g,gme->active_row,gme->active_col);
1110 : }
1111 :
1112 0 : static int _GME_Up(GGadget *g, GEvent *e) {
1113 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1114 0 : GMatrixEditUp( g->data );
1115 : }
1116 0 : return( true );
1117 : }
1118 :
1119 0 : void GMatrixEditDown(GGadget *g) {
1120 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
1121 : GRect r;
1122 : int i;
1123 :
1124 0 : if ( gme->active_row<0 || gme->active_row>=gme->rows-1 )
1125 0 : return;
1126 0 : for ( i=0; i<gme->cols; ++i ) {
1127 0 : struct matrix_data md = gme->data[gme->active_row*gme->cols+i];
1128 0 : gme->data[gme->active_row*gme->cols+i] = gme->data[(gme->active_row+1)*gme->cols+i];
1129 0 : gme->data[(gme->active_row+1)*gme->cols+i] = md;
1130 : }
1131 0 : ++gme->active_row;;
1132 0 : GGadgetGetSize(gme->tf,&r);
1133 0 : GGadgetMove(gme->tf,r.x,r.y-(gme->fh+1));
1134 0 : GME_EnableDelete(gme);
1135 0 : if ( gme->rowmotion!=NULL )
1136 0 : (gme->rowmotion)((GGadget *) gme, gme->active_row-1,gme->active_row);
1137 0 : GMatrixEditScrollToRowCol(&gme->g,gme->active_row,gme->active_col);
1138 0 : return;
1139 : }
1140 :
1141 0 : static int _GME_Down(GGadget *g, GEvent *e) {
1142 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1143 0 : GMatrixEditDown( g->data );
1144 : }
1145 0 : return( true );
1146 : }
1147 :
1148 : #define CID_OK 1001
1149 : #define CID_Cancel 1002
1150 : #define CID_EntryField 1011
1151 :
1152 0 : static int big_e_h(GWindow gw, GEvent *event) {
1153 0 : GMatrixEdit *gme = GDrawGetUserData(gw);
1154 :
1155 0 : if ( event->type==et_close ) {
1156 0 : gme->big_done = true;
1157 0 : } else if ( event->type == et_char ) {
1158 0 : return( false );
1159 0 : } else if ( event->type == et_controlevent && event->u.control.subtype == et_buttonactivate ) {
1160 0 : gme->big_done = true;
1161 0 : if ( GGadgetGetCid(event->u.control.g)==CID_OK ) {
1162 0 : gme->big_done = GME_SetValue(gme,GWidgetGetControl(gw,CID_EntryField) );
1163 0 : if ( gme->big_done )
1164 0 : GME_AdjustCol(gme,gme->active_col);
1165 0 : } else if ( gme->wasnew ) {
1166 : /* They canceled a click which produced a new row */
1167 0 : GME_DeleteActive(gme);
1168 0 : gme->wasnew = false;
1169 : }
1170 : }
1171 0 : return( true );
1172 : }
1173 :
1174 0 : static void GME_StrBigEdit(GMatrixEdit *gme,char *str) {
1175 : GRect pos;
1176 : GWindow gw;
1177 : GWindowAttrs wattrs;
1178 : GGadgetCreateData mgcd[6], boxes[3], *varray[5], *harray[6];
1179 : GTextInfo mlabel[6];
1180 0 : char *title_str = NULL;
1181 :
1182 0 : if ( gme->bigedittitle!=NULL )
1183 0 : title_str = (gme->bigedittitle)(&(gme->g),gme->active_row,gme->active_col);
1184 :
1185 0 : memset(&wattrs,0,sizeof(wattrs));
1186 0 : wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
1187 0 : wattrs.event_masks = ~(1<<et_charup);
1188 0 : wattrs.is_dlg = true;
1189 0 : wattrs.restrict_input_to_me = 1;
1190 0 : wattrs.undercursor = 1;
1191 0 : wattrs.cursor = ct_pointer;
1192 0 : wattrs.utf8_window_title = title_str==NULL ? "Editing..." : title_str;
1193 0 : pos.x = pos.y = 0;
1194 0 : pos.width =GDrawPointsToPixels(NULL,GGadgetScale(500));
1195 0 : pos.height = GDrawPointsToPixels(NULL,400);
1196 0 : gme->big_done = 0;
1197 0 : gw = GDrawCreateTopWindow(NULL,&pos,big_e_h,gme,&wattrs);
1198 0 : free(title_str);
1199 :
1200 0 : memset(&mgcd,0,sizeof(mgcd));
1201 0 : memset(&boxes,0,sizeof(boxes));
1202 0 : memset(&mlabel,0,sizeof(mlabel));
1203 0 : mgcd[0].gd.pos.x = 4; mgcd[0].gd.pos.y = 6;
1204 0 : mgcd[0].gd.pos.width = 492;
1205 0 : mgcd[0].gd.pos.height = 260;
1206 0 : mgcd[0].gd.flags = gg_visible | gg_enabled | gg_textarea_wrap | gg_text_xim;
1207 0 : mgcd[0].gd.cid = CID_EntryField;
1208 0 : mgcd[0].creator = GTextAreaCreate;
1209 0 : varray[0] = &mgcd[0]; varray[1] = NULL;
1210 0 : varray[2] = &boxes[2]; varray[3] = NULL;
1211 0 : varray[4] = NULL;
1212 :
1213 0 : mgcd[1].gd.pos.x = 30-3; mgcd[1].gd.pos.y = GDrawPixelsToPoints(NULL,pos.height)-35-3;
1214 0 : mgcd[1].gd.pos.width = -1; mgcd[1].gd.pos.height = 0;
1215 0 : mgcd[1].gd.flags = gg_visible | gg_enabled | gg_but_default;
1216 0 : if ( _ggadget_use_gettext ) {
1217 0 : mlabel[1].text = (unichar_t *) _("_OK");
1218 0 : mlabel[1].text_is_1byte = true;
1219 : } else
1220 0 : mlabel[1].text = (unichar_t *) _STR_OK;
1221 0 : mlabel[1].text_in_resource = true;
1222 0 : mgcd[1].gd.label = &mlabel[1];
1223 0 : mgcd[1].gd.cid = CID_OK;
1224 0 : mgcd[1].creator = GButtonCreate;
1225 :
1226 0 : mgcd[2].gd.pos.x = -30; mgcd[2].gd.pos.y = mgcd[1].gd.pos.y+3;
1227 0 : mgcd[2].gd.pos.width = -1; mgcd[2].gd.pos.height = 0;
1228 0 : mgcd[2].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
1229 0 : if ( _ggadget_use_gettext ) {
1230 0 : mlabel[2].text = (unichar_t *) _("_Cancel");
1231 0 : mlabel[2].text_is_1byte = true;
1232 : } else
1233 0 : mlabel[2].text = (unichar_t *) _STR_Cancel;
1234 0 : mlabel[2].text_in_resource = true;
1235 0 : mgcd[2].gd.label = &mlabel[2];
1236 0 : mgcd[2].gd.cid = CID_Cancel;
1237 0 : mgcd[2].creator = GButtonCreate;
1238 0 : harray[0] = GCD_Glue; harray[1] = &mgcd[1];
1239 0 : harray[2] = GCD_Glue; harray[3] = &mgcd[2];
1240 0 : harray[4] = GCD_Glue; harray[5] = NULL;
1241 :
1242 0 : boxes[2].gd.flags = gg_visible | gg_enabled;
1243 0 : boxes[2].gd.u.boxelements = harray;
1244 0 : boxes[2].creator = GHBoxCreate;
1245 :
1246 0 : boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
1247 0 : boxes[0].gd.flags = gg_visible | gg_enabled;
1248 0 : boxes[0].gd.u.boxelements = varray;
1249 0 : boxes[0].creator = GHVGroupCreate;
1250 :
1251 0 : GGadgetsCreate(gw,boxes);
1252 0 : GHVBoxSetExpandableRow(boxes[0].ret,0);
1253 0 : GHVBoxSetExpandableCol(boxes[2].ret,gb_expandgluesame);
1254 0 : GHVBoxFitWindow(boxes[0].ret);
1255 0 : GGadgetSetTitle8(mgcd[0].ret,str);
1256 0 : GTextFieldSelect(mgcd[0].ret,0,0);
1257 0 : GTextFieldShow(mgcd[0].ret,0);
1258 :
1259 0 : GDrawSetVisible(gw,true);
1260 0 : while ( !gme->big_done )
1261 0 : GDrawProcessOneEvent(NULL);
1262 0 : GDrawDestroyWindow(gw);
1263 0 : GDrawRequestExpose(gme->nested,NULL,false);
1264 :
1265 0 : gme->wasnew = false;
1266 0 : }
1267 :
1268 0 : static void GME_EnumDispatch(GWindow gw, GMenuItem *mi, GEvent *e) {
1269 0 : GMatrixEdit *gme = GDrawGetUserData(gw);
1270 :
1271 0 : if ( (intpt) mi->ti.userdata == GME_NoChange )
1272 0 : return;
1273 :
1274 0 : gme->data[gme->active_row*gme->cols+gme->active_col].u.md_ival = (intpt) mi->ti.userdata;
1275 :
1276 0 : if ( gme->finishedit != NULL )
1277 0 : (gme->finishedit)(&gme->g,gme->active_row,gme->active_col,gme->wasnew);
1278 0 : GME_AdjustCol(gme,gme->active_col);
1279 0 : gme->wasnew = false;
1280 : }
1281 :
1282 0 : static void GME_FinishChoice(GWindow gw) {
1283 0 : GMatrixEdit *gme = GDrawGetUserData(gw);
1284 :
1285 : /* If wasnew is still set then they didn't pick anything, so remove the row */
1286 0 : if ( gme->wasnew && gme->active_col==0 )
1287 0 : GME_DeleteActive(gme);
1288 0 : gme->wasnew = false;
1289 0 : GDrawRequestExpose(gme->nested,NULL,false);
1290 0 : }
1291 :
1292 0 : static void GME_Choices(GMatrixEdit *gme,GEvent *event,int r,int c) {
1293 0 : GMenuItem *mi = gme->col_data[c].enum_vals;
1294 0 : int val = gme->data[r*gme->cols+c].u.md_ival;
1295 : int i;
1296 :
1297 0 : for ( i=0; mi[i].ti.text!=NULL || mi[i].ti.line || mi[i].ti.image!=NULL; ++i )
1298 0 : mi[i].ti.selected = mi[i].ti.checked = !gme->wasnew && (mi[i].ti.userdata == (void *) (intpt) val);
1299 0 : if ( gme->col_data[c].enable_enum!=NULL )
1300 0 : (gme->col_data[c].enable_enum)(&gme->g,mi,r,c);
1301 0 : _GMenuCreatePopupMenu(gme->nested,event, mi, GME_FinishChoice);
1302 0 : }
1303 :
1304 0 : static void GME_EnumStringDispatch(GWindow gw, GMenuItem *mi, GEvent *e) {
1305 0 : GMatrixEdit *gme = GDrawGetUserData(gw);
1306 0 : int r = gme->active_row, c = gme->active_col;
1307 :
1308 0 : if ( (intpt) mi->ti.userdata == GME_NoChange )
1309 0 : return;
1310 :
1311 0 : free(gme->data[r*gme->cols+c].u.md_str);
1312 0 : if ( gme->col_data[c].me_type==me_stringchoicetrans )
1313 0 : gme->data[r*gme->cols+c].u.md_str = copy( (char *) mi->ti.userdata );
1314 0 : else if ( gme->col_data[c].me_type==me_stringchoicetag ) {
1315 : char buf[8];
1316 0 : buf[0] = ((intpt) mi->ti.userdata)>>24;
1317 0 : buf[1] = ((intpt) mi->ti.userdata)>>16;
1318 0 : buf[2] = ((intpt) mi->ti.userdata)>>8;
1319 0 : buf[3] = ((intpt) mi->ti.userdata)&0xff;
1320 0 : buf[4] = '\0';
1321 0 : gme->data[r*gme->cols+c].u.md_str = copy( buf );
1322 : } else
1323 0 : gme->data[r*gme->cols+c].u.md_str = u2utf8_copy( mi->ti.text );
1324 :
1325 0 : if ( gme->finishedit != NULL )
1326 0 : (gme->finishedit)(&gme->g,r,c,gme->wasnew);
1327 0 : GME_AdjustCol(gme,c);
1328 0 : gme->wasnew = false;
1329 : }
1330 :
1331 0 : static void GME_StringChoices(GMatrixEdit *gme,GEvent *event,int r,int c) {
1332 0 : GMenuItem *mi = gme->col_data[c].enum_vals;
1333 0 : char *val = gme->data[r*gme->cols+c].u.md_str;
1334 : int i;
1335 :
1336 0 : if ( gme->col_data[c].me_type==me_stringchoicetag ) {
1337 : char buf[8];
1338 0 : for ( i=0; mi[i].ti.text!=NULL || mi[i].ti.line || mi[i].ti.image!=NULL; ++i ) {
1339 0 : buf[0] = ((intpt) mi[i].ti.userdata)>>24;
1340 0 : buf[1] = ((intpt) mi[i].ti.userdata)>>16;
1341 0 : buf[2] = ((intpt) mi[i].ti.userdata)>>8;
1342 0 : buf[3] = ((intpt) mi[i].ti.userdata)&0xff;
1343 0 : buf[4] = '\0';
1344 0 : mi[i].ti.selected = mi[i].ti.checked = !gme->wasnew && val!=NULL &&
1345 0 : strcmp(buf,val)==0;
1346 : }
1347 0 : } else if ( gme->col_data[c].me_type==me_stringchoicetrans ) {
1348 0 : for ( i=0; mi[i].ti.text!=NULL || mi[i].ti.line || mi[i].ti.image!=NULL; ++i )
1349 0 : mi[i].ti.selected = mi[i].ti.checked = !gme->wasnew && val!=NULL &&
1350 0 : strcmp((char *) mi[i].ti.userdata,val)==0;
1351 : }
1352 0 : if ( gme->col_data[c].enable_enum!=NULL )
1353 0 : (gme->col_data[c].enable_enum)(&gme->g,mi,r,c);
1354 0 : _GMenuCreatePopupMenu(gme->nested,event, mi, GME_FinishChoice);
1355 0 : }
1356 :
1357 0 : static void GMatrixEdit_StartSubGadgets(GMatrixEdit *gme,int r, int c,GEvent *event) {
1358 : int i, markpos, lastc;
1359 : struct matrix_data *d;
1360 0 : int old_off_left = gme->off_left; /* We sometimes scroll */
1361 : int oldr;
1362 : GRect size;
1363 :
1364 0 : GDrawGetSize(gme->nested,&size);
1365 :
1366 0 : for ( lastc = gme->cols-1; lastc>0 && gme->col_data[lastc].hidden; --lastc );
1367 : /* new row */
1368 0 : if ( c==0 && r==gme->rows && event->type == et_mousedown &&
1369 0 : event->u.mouse.button==1 && !gme->no_edit ) {
1370 0 : if ( gme->rows>=gme->row_max )
1371 0 : gme->data = realloc(gme->data,(gme->row_max+=10)*gme->cols*sizeof(struct matrix_data));
1372 0 : ++gme->rows;
1373 0 : for ( i=0; i<gme->cols; ++i ) {
1374 0 : d = &gme->data[r*gme->cols+i];
1375 0 : memset(d,0,sizeof(*d));
1376 0 : switch ( gme->col_data[i].me_type ) {
1377 : case me_string: case me_bigstr:
1378 : case me_stringchoice: case me_stringchoicetrans: case me_stringchoicetag:
1379 : case me_funcedit:
1380 : case me_onlyfuncedit:
1381 0 : d->u.md_str = copy("");
1382 0 : break;
1383 : case me_enum:
1384 0 : d->u.md_ival = (int) (intptr_t) gme->col_data[i].enum_vals[0].ti.userdata;
1385 0 : break;
1386 : }
1387 : }
1388 0 : if ( gme->initrow!=NULL )
1389 0 : (gme->initrow)(&gme->g,r);
1390 0 : GME_FixScrollBars(gme);
1391 0 : GDrawRequestExpose(gme->nested,NULL,false);
1392 0 : gme->wasnew = true;
1393 : }
1394 :
1395 0 : if ( c==gme->cols || r>=gme->rows || gme->col_data[c].disabled )
1396 0 : return;
1397 0 : oldr = gme->active_row;
1398 0 : gme->active_col = c; gme->active_row = r;
1399 0 : if ( r!=oldr && oldr!=-1 ) {
1400 : GRect r;
1401 0 : r.x = gme->col_data[c].x - gme->off_left; r.width = gme->col_data[c].width;
1402 0 : r.y = (oldr-gme->off_top)*(gme->fh+gme->vpad); r.height = gme->fh+gme->vpad;
1403 0 : if ( r.y+r.height>0 )
1404 0 : GDrawRequestExpose(gme->nested,&r,false);
1405 : }
1406 0 : GME_EnableDelete(gme);
1407 :
1408 0 : GMatrixEditScrollToRowCol(&gme->g,r,c);
1409 0 : d = &gme->data[r*gme->cols+c];
1410 :
1411 0 : markpos = ( c == lastc && gme->col_data[c].x + gme->col_data[c].width > size.width ) ?
1412 0 : size.width - gme->col_data[c].x : gme->col_data[c].width;
1413 0 : markpos -= (gme->mark_size+gme->mark_skip);
1414 0 : if ( markpos < 0 ) markpos = 0;
1415 0 : if ( event->type==et_mousedown && event->u.mouse.button==3 ) {
1416 0 : if ( gme->popupmenu!=NULL )
1417 0 : (gme->popupmenu)(&gme->g,event,r,c);
1418 0 : } else if ( d->frozen ) {
1419 0 : GDrawBeep(NULL);
1420 0 : } else if ( gme->no_edit ) {
1421 : /* Twiddle toes */;
1422 0 : } else if ( gme->col_data[c].me_type==me_enum ) {
1423 0 : GME_Choices(gme,event,r,c);
1424 0 : } else if ( gme->col_data[c].me_type==me_button ) {
1425 0 : char *ret = (gme->col_data[c].func)(&gme->g,r,c);
1426 0 : if ( ret!=NULL ) {
1427 : /* I don't bother validating it because I expect the function to */
1428 : /* do that for me */
1429 0 : free(gme->data[r*gme->cols+c].u.md_str);
1430 0 : gme->data[r*gme->cols+c].u.md_str = ret;
1431 0 : GDrawRequestExpose(gme->nested,NULL,false);
1432 : }
1433 0 : } else if ( ((gme->col_data[c].me_type==me_funcedit ||
1434 0 : gme->col_data[c].me_type==me_onlyfuncedit ) &&
1435 0 : event->type==et_mousedown &&
1436 0 : event->u.mouse.x>gme->col_data[c].x + markpos - old_off_left ) ||
1437 0 : (gme->col_data[c].me_type==me_onlyfuncedit &&
1438 0 : event->type==et_mousedown &&
1439 0 : (gme->wasnew || event->u.mouse.clicks==2)) ) {
1440 0 : char *ret = (gme->col_data[c].func)(&gme->g,r,c);
1441 0 : if ( ret!=NULL ) {
1442 : /* I don't bother validating it because I expect the function to */
1443 : /* do that for me */
1444 0 : free(gme->data[r*gme->cols+c].u.md_str);
1445 0 : gme->data[r*gme->cols+c].u.md_str = ret;
1446 0 : if ( gme->finishedit != NULL )
1447 0 : (gme->finishedit)(&gme->g,r,c,gme->wasnew);
1448 0 : GDrawRequestExpose(gme->nested,NULL,false);
1449 0 : gme->wasnew = false; // This is an attempted hack by somebody (Frank) who admittedly has no idea what is happening in all of this sparsely commented code.
1450 : }
1451 0 : } else if ( gme->col_data[c].me_type==me_onlyfuncedit ) {
1452 : /* Don't allow other editing */
1453 0 : } else if ( (gme->col_data[c].me_type==me_stringchoice ||
1454 0 : gme->col_data[c].me_type==me_stringchoicetrans ||
1455 0 : gme->col_data[c].me_type==me_stringchoicetag) &&
1456 0 : event->type==et_mousedown &&
1457 0 : event->u.mouse.x>gme->col_data[c].x + markpos - old_off_left ) {
1458 0 : GME_StringChoices(gme,event,r,c);
1459 : } else {
1460 0 : char *str = MD_Text(gme,gme->active_row,gme->active_col);
1461 0 : if ( str==NULL )
1462 0 : str = copy("");
1463 0 : if ( str!=NULL &&
1464 0 : (g_utf8_strlen(str, -1)>40 || strchr(str,'\n')!=NULL || gme->col_data[c].me_type == me_bigstr))
1465 0 : GME_StrBigEdit(gme,str);
1466 : else
1467 0 : GME_StrSmallEdit(gme,str,event);
1468 0 : free(str);
1469 : }
1470 : }
1471 :
1472 0 : static void GMatrixEdit_MouseEvent(GMatrixEdit *gme,GEvent *event) {
1473 0 : int r = event->u.mouse.y/(gme->fh+gme->vpad) + gme->off_top;
1474 0 : int x = event->u.mouse.x + gme->off_left;
1475 : int c, i;
1476 :
1477 0 : if ( gme->edit_active && event->type==et_mousemove )
1478 0 : return;
1479 0 : for ( c=0; c<gme->cols; ++c ) {
1480 0 : if ( gme->col_data[c].hidden )
1481 0 : continue;
1482 0 : if ( x>=gme->col_data[c].x && x<=gme->col_data[c].x+gme->col_data[c].width )
1483 0 : break;
1484 : }
1485 0 : if ( event->type==et_mousemove && gme->reportmousemove!=NULL ) {
1486 0 : (gme->reportmousemove)(&gme->g,r,c);
1487 0 : return;
1488 : }
1489 0 : if ( gme->edit_active ) {
1490 0 : if ( (r = GME_FinishEditPreserve(gme,r))== -1 )
1491 0 : return;
1492 : }
1493 0 : if ( event->type==et_mousedown )
1494 0 : GMatrixEdit_StartSubGadgets(gme,r,c,event);
1495 0 : else if ( event->type==et_mousemove ) {
1496 0 : if ( c<gme->cols && gme->col_data[c].me_type==me_stringchoicetrans &&
1497 0 : gme->col_data[c].enum_vals!=NULL &&
1498 0 : r<gme->rows ) {
1499 0 : char *str = gme->data[r*gme->cols+c].u.md_str;
1500 0 : GMenuItem *enums = gme->col_data[c].enum_vals;
1501 0 : for ( i=0; enums[i].ti.text!=NULL || enums[i].ti.line ; ++i ) {
1502 0 : if ( enums[i].ti.userdata!=NULL && strcmp(enums[i].ti.userdata,str)==0 ) {
1503 0 : if ( enums[i].ti.text_is_1byte )
1504 0 : GGadgetPreparePopup8(gme->nested,(char *) enums[i].ti.text);
1505 : else
1506 0 : GGadgetPreparePopup(gme->nested,enums[i].ti.text);
1507 0 : break;
1508 : }
1509 : }
1510 0 : } else if ( c<gme->cols && gme->col_data[c].me_type==me_stringchoicetag &&
1511 0 : gme->col_data[c].enum_vals!=NULL &&
1512 0 : r<gme->rows ) {
1513 0 : char *str = gme->data[r*gme->cols+c].u.md_str, buf[8];
1514 0 : GMenuItem *enums = gme->col_data[c].enum_vals;
1515 0 : for ( i=0; enums[i].ti.text!=NULL || enums[i].ti.line ; ++i ) {
1516 0 : buf[0] = ((intpt) enums[i].ti.userdata)>>24;
1517 0 : buf[1] = ((intpt) enums[i].ti.userdata)>>16;
1518 0 : buf[2] = ((intpt) enums[i].ti.userdata)>>8;
1519 0 : buf[3] = ((intpt) enums[i].ti.userdata)&0xff;
1520 0 : buf[4] = '\0';
1521 0 : if ( enums[i].ti.userdata!=NULL && strcmp(buf,str)==0 ) {
1522 0 : if ( enums[i].ti.text_is_1byte )
1523 0 : GGadgetPreparePopup8(gme->nested,(char *) enums[i].ti.text);
1524 : else
1525 0 : GGadgetPreparePopup(gme->nested,enums[i].ti.text);
1526 0 : break;
1527 : }
1528 : }
1529 0 : } else if ( gme->g.popup_msg!=NULL )
1530 0 : GGadgetPreparePopup(gme->nested,gme->g.popup_msg);
1531 : }
1532 : }
1533 :
1534 0 : static void GMatrixEdit_SubExpose(GMatrixEdit *gme,GWindow pixmap,GEvent *event) {
1535 : int r,c, lastc, kludge;
1536 : char *buf, *str, *pt;
1537 : GRect size;
1538 : GRect clip, old;
1539 : Color fg, mkbg;
1540 : struct matrix_data *data;
1541 : GMenuItem *mi;
1542 :
1543 0 : GDrawGetSize(gme->nested,&size);
1544 0 : if ( gme->g.state!=gs_enabled )
1545 0 : GDrawFillRect(pixmap,&size,gme->g.box->disabled_background);
1546 :
1547 0 : GDrawDrawLine(pixmap,0,0,0,size.height,gmatrixedit_rules);
1548 : /* Make sure the last visible column ends at (or after) the edge */
1549 0 : for ( lastc = gme->cols-1; lastc>0 && gme->col_data[lastc].hidden; --lastc );
1550 0 : if ( lastc>=0 && gme->col_data[lastc].x+gme->col_data[lastc].width < size.width ) {
1551 0 : gme->col_data[lastc].width = size.width - gme->col_data[lastc].x;
1552 0 : for ( c=lastc+1; c<gme->cols; ++c )
1553 0 : gme->col_data[c].x = size.width;
1554 : }
1555 0 : for ( c=0; c<gme->cols-1; ++c ) if ( !gme->col_data[c].hidden )
1556 0 : GDrawDrawLine(pixmap,
1557 0 : gme->col_data[c].x+gme->col_data[c].width+gme->hpad/2-gme->off_left,0,
1558 0 : gme->col_data[c].x+gme->col_data[c].width+gme->hpad/2-gme->off_left,size.height,
1559 : gmatrixedit_rules);
1560 0 : GDrawDrawLine(pixmap,0,0,size.width,0,gmatrixedit_rules);
1561 0 : for ( r=gme->off_top; r<=gme->rows && (r-gme->off_top)*(gme->fh+gme->vpad)<=gme->g.inner.height; ++r )
1562 0 : GDrawDrawLine(pixmap,
1563 0 : 0, (r-gme->off_top)*(gme->fh+gme->vpad)-1,
1564 0 : size.width,(r-gme->off_top)*(gme->fh+gme->vpad)-1,
1565 : gmatrixedit_rules);
1566 :
1567 :
1568 0 : GDrawSetFont(pixmap,gme->font);
1569 0 : for ( r=event->u.expose.rect.y/(gme->fh+gme->vpad);
1570 0 : r<=(event->u.expose.rect.y+event->u.expose.rect.height+gme->fh+gme->vpad-1)/gme->fh &&
1571 0 : r+gme->off_top<=gme->rows;
1572 0 : ++r ) {
1573 : int y, lastc;
1574 0 : clip.y = r*(gme->fh+gme->vpad);
1575 0 : y = clip.y + gme->font_as; /* I know this looks odd, but it seems to work when we grab a glyph from another font with cairo */
1576 0 : clip.height = gme->fh;
1577 0 : for ( lastc = gme->cols-1; lastc>0 && gme->col_data[lastc].hidden; --lastc );
1578 : /* Compensate for the top border line */
1579 0 : if ( clip.y <= 0 ) {
1580 0 : clip.y = 1; clip.height += ( clip.y - 1 );
1581 : }
1582 :
1583 0 : for ( c=0; c<gme->cols; ++c ) {
1584 0 : if ( gme->col_data[c].hidden )
1585 0 : continue;
1586 0 : if ( gme->col_data[c].x + gme->col_data[c].width < gme->off_left && gme->col_data[c].width > gme->hpad)
1587 0 : continue;
1588 0 : clip.x = gme->col_data[c].x - gme->off_left;
1589 0 : clip.width = gme->col_data[c].width;
1590 0 : if ( gme->col_data[c].me_type==me_button ) {
1591 : int temp;
1592 0 : clip.height += 2;
1593 0 : GBoxDrawBackground(pixmap,&clip,&gmatrixedit_button_box,
1594 0 : gme->col_data[c].disabled ? gs_disabled : gs_enabled, false);
1595 0 : GBoxDrawBorder(pixmap,&clip,&gmatrixedit_button_box,
1596 0 : gme->col_data[c].disabled ? gs_disabled : gs_enabled, false);
1597 0 : clip.height -= 2;
1598 0 : temp = GBoxBorderWidth(pixmap,&gmatrixedit_button_box)+2;
1599 0 : clip.x += temp;
1600 0 : clip.width -= temp;
1601 0 : } else if ( gme->col_data[c].disabled && gme->g.box->disabled_background!=COLOR_TRANSPARENT )
1602 0 : GDrawFillRect(pixmap,&clip,gme->g.box->disabled_background);
1603 0 : else if ( gme->active_row==r+gme->off_top )
1604 0 : GDrawFillRect(pixmap,&clip,gmatrixedit_activebg);
1605 0 : if ( gme->col_data[c].me_type == me_stringchoice ||
1606 0 : gme->col_data[c].me_type == me_stringchoicetrans ||
1607 0 : gme->col_data[c].me_type == me_stringchoicetag ||
1608 0 : gme->col_data[c].me_type == me_onlyfuncedit ||
1609 0 : gme->col_data[c].me_type == me_funcedit ) {
1610 :
1611 0 : if ( c == lastc ) {
1612 0 : if ( clip.x < size.width && clip.x + clip.width > size.width )
1613 0 : clip.width = size.width - clip.x;
1614 0 : else if ( clip.x >= size.width )
1615 0 : clip.width = 0;
1616 : }
1617 0 : if ( clip.width >= (gme->mark_size+gme->mark_skip) )
1618 0 : clip.width -= (gme->mark_size+gme->mark_skip);
1619 : else
1620 0 : clip.width = 0;
1621 : }
1622 0 : if ( clip.width>0 ) {
1623 0 : GDrawPushClip(pixmap,&clip,&old);
1624 0 : str = NULL;
1625 0 : if ( r+gme->off_top==gme->rows ) {
1626 0 : if ( !gme->no_edit ) {
1627 0 : if ( gme->newtext!=NULL )
1628 0 : buf = xasprintf( "<%s>", gme->newtext );
1629 0 : else if ( _ggadget_use_gettext )
1630 0 : buf = xasprintf( "<%s>", S_("Row|New") );
1631 : else {
1632 0 : gchar *tmp = g_ucs4_to_utf8( (const gunichar *) GStringGetResource( _STR_New, NULL ),
1633 : -1, NULL, NULL, NULL );
1634 0 : buf = xasprintf( "<%s>", tmp );
1635 0 : g_free( tmp ); tmp = NULL;
1636 : }
1637 0 : GDrawDrawText8( pixmap, gme->col_data[0].x - gme->off_left,y,
1638 : (char *) buf, -1, gmatrixedit_activecol );
1639 0 : free( buf ) ; buf = NULL ;
1640 : }
1641 : } else {
1642 0 : data = &gme->data[(r+gme->off_top)*gme->cols+c];
1643 0 : fg = gme->g.state==gs_disabled?gme->g.box->disabled_foreground:
1644 0 : data->frozen ? gmatrixedit_frozencol:
1645 0 : gme->g.box->main_foreground==COLOR_DEFAULT?GDrawGetDefaultForeground(GDrawGetDisplayOfWindow(pixmap)):
1646 0 : gme->g.box->main_foreground;
1647 0 : switch ( gme->col_data[c].me_type ) {
1648 : case me_enum:
1649 0 : mi = FindMi(gme->col_data[c].enum_vals,data->u.md_ival);
1650 0 : if ( mi!=NULL ) {
1651 0 : if ( mi->ti.text_is_1byte )
1652 0 : GDrawDrawText8(pixmap,clip.x,y,(char *)mi->ti.text,-1,fg);
1653 : else
1654 0 : GDrawDrawText(pixmap,clip.x,y,mi->ti.text,-1,fg);
1655 0 : break;
1656 : }
1657 : /* Fall through into next case */
1658 : default:
1659 0 : kludge = gme->edit_active; gme->edit_active = false;
1660 0 : str = MD_Text(gme,r+gme->off_top,c);
1661 0 : if ( str==NULL && gme->col_data[c].me_type==me_button )
1662 0 : str = copy("...");
1663 0 : gme->edit_active = kludge;
1664 0 : break;
1665 : }
1666 0 : if ( str!=NULL ) {
1667 0 : pt = strchr(str,'\n');
1668 0 : GDrawDrawText8(pixmap,clip.x,y,str,pt==NULL?-1:pt-str,fg);
1669 0 : free(str);
1670 : }
1671 : }
1672 0 : GDrawPopClip(pixmap,&old);
1673 : }
1674 0 : if ( gme->col_data[c].me_type == me_stringchoice ||
1675 0 : gme->col_data[c].me_type == me_stringchoicetrans ||
1676 0 : gme->col_data[c].me_type == me_stringchoicetag ||
1677 0 : gme->col_data[c].me_type == me_onlyfuncedit ||
1678 0 : gme->col_data[c].me_type == me_funcedit ) {
1679 : GRect mr;
1680 0 : mr.x = clip.x + clip.width; mr.width = gme->mark_size+gme->mark_skip;
1681 0 : mr.y = clip.y; mr.height = clip.height;
1682 :
1683 0 : mkbg = gme->active_row==r+gme->off_top ?
1684 0 : gmatrixedit_activebg : GDrawGetDefaultBackground(GDrawGetDisplayOfWindow(pixmap));
1685 0 : GDrawFillRect(pixmap,&mr,mkbg);
1686 0 : GListMarkDraw(pixmap,
1687 0 : mr.x + gme->mark_skip + (gme->mark_size - gme->mark_length)/2,
1688 : clip.y,
1689 : clip.height,
1690 : gme->g.state);
1691 : }
1692 0 : if ( r+gme->off_top==gme->rows )
1693 0 : return;
1694 : }
1695 : }
1696 : }
1697 :
1698 0 : static int matrixeditsub_e_h(GWindow gw, GEvent *event) {
1699 0 : GMatrixEdit *gme = (GMatrixEdit *) GDrawGetUserData(gw);
1700 : int r,c;
1701 :
1702 0 : GGadgetPopupExternalEvent(event);
1703 0 : if (( event->type==et_mouseup || event->type==et_mousedown ) &&
1704 0 : (event->u.mouse.button>=4 && event->u.mouse.button<=7)) {
1705 0 : int isv = event->u.mouse.button<=5;
1706 0 : if ( event->u.mouse.state&ksm_shift ) isv = !isv;
1707 0 : if ( isv && gme->vsb!=NULL )
1708 0 : return( GGadgetDispatchEvent(gme->vsb,event));
1709 0 : else if ( !isv && gme->hsb!=NULL )
1710 0 : return( GGadgetDispatchEvent(gme->hsb,event));
1711 : else
1712 0 : return( true );
1713 : }
1714 :
1715 0 : switch ( event->type ) {
1716 : case et_expose:
1717 0 : GDrawSetLineWidth(gw,0);
1718 0 : GMatrixEdit_SubExpose(gme,gw,event);
1719 0 : break;
1720 : case et_mousedown:
1721 : case et_mouseup:
1722 0 : if ( gme->g.state == gs_disabled )
1723 0 : return( false );
1724 : case et_mousemove:
1725 0 : GMatrixEdit_MouseEvent(gme,event);
1726 0 : break;
1727 : case et_char:
1728 0 : if ( gme->g.state == gs_disabled )
1729 0 : return( false );
1730 0 : r = gme->active_row;
1731 0 : switch ( event->u.chr.keysym ) {
1732 : case GK_Up: case GK_KP_Up:
1733 0 : if ( (!gme->edit_active || GME_FinishEdit(gme)) &&
1734 0 : gme->active_row>0 )
1735 0 : GMatrixEdit_StartSubGadgets(gme,gme->active_row-1,gme->active_col,event);
1736 0 : return( true );
1737 : break;
1738 : case GK_Down: case GK_KP_Down:
1739 0 : if ( (!gme->edit_active || GME_FinishEdit(gme)) &&
1740 0 : gme->active_row<gme->rows-(gme->active_col!=0) )
1741 0 : GMatrixEdit_StartSubGadgets(gme,gme->active_row+1,gme->active_col,event);
1742 0 : return( true );
1743 : break;
1744 : case GK_Left: case GK_KP_Left:
1745 : case GK_BackTab:
1746 : backtab:
1747 0 : if ( (!gme->edit_active || (r=GME_FinishEditPreserve(gme,r))!=-1) &&
1748 0 : gme->active_col>0 ) {
1749 0 : for ( c = gme->active_col-1; c>=0 && gme->col_data[c].hidden; --c );
1750 0 : if ( c>=0 )
1751 0 : GMatrixEdit_StartSubGadgets(gme,r,c,event);
1752 : }
1753 0 : return( true );
1754 : break;
1755 : case GK_Tab:
1756 0 : if ( event->u.chr.state&ksm_shift )
1757 0 : goto backtab;
1758 : /* Else fall through */
1759 : case GK_Right: case GK_KP_Right:
1760 0 : if ( (!gme->edit_active || (r=GME_FinishEditPreserve(gme,r))!=-1) &&
1761 0 : gme->active_col<gme->cols-1 ) {
1762 0 : for ( c = gme->active_col+1; c<gme->cols && gme->col_data[c].hidden; ++c );
1763 0 : if ( c<gme->cols )
1764 0 : GMatrixEdit_StartSubGadgets(gme,r,c,event);
1765 : }
1766 0 : return( true );
1767 : break;
1768 : case GK_Return: case GK_KP_Enter:
1769 0 : if ( gme->edit_active && (r=GME_FinishEditPreserve(gme,r))!=-1 ) {
1770 : GEvent dummy;
1771 0 : memset(&dummy,0,sizeof(dummy));
1772 0 : dummy.w = event->w;
1773 0 : dummy.type = et_mousedown;
1774 0 : dummy.u.mouse.state = event->u.chr.state;
1775 0 : dummy.u.mouse.x = gme->off_left+gme->col_data[0].x+1;
1776 0 : dummy.u.mouse.y = gme->off_top + (r+1)*(gme->fh+gme->vpad);
1777 0 : dummy.u.mouse.button = 1;
1778 0 : GMatrixEdit_StartSubGadgets(gme,r+1,0,&dummy);
1779 : }
1780 0 : return( true );
1781 : }
1782 0 : if ( gme->handle_key!=NULL )
1783 0 : return( (gme->handle_key)(&gme->g,event) );
1784 0 : return( false );
1785 : break;
1786 : case et_destroy:
1787 0 : if ( gme!=NULL )
1788 0 : gme->nested = NULL;
1789 0 : break;
1790 : case et_controlevent:
1791 0 : if ( gme->reporttextchanged!=NULL )
1792 0 : (gme->reporttextchanged)(&gme->g,gme->active_row,gme->active_col,gme->tf);
1793 0 : break;
1794 : }
1795 0 : return( true );
1796 : }
1797 :
1798 0 : static void GME_HScroll(GMatrixEdit *gme,struct sbevent *sb) {
1799 0 : int newpos = gme->off_left;
1800 : GRect size;
1801 0 : int hend = gme->col_data[gme->cols-1].x + gme->col_data[gme->cols-1].width;
1802 :
1803 0 : GDrawGetSize(gme->nested,&size);
1804 0 : switch( sb->type ) {
1805 : case et_sb_top:
1806 0 : newpos = 0;
1807 0 : break;
1808 : case et_sb_uppage:
1809 0 : newpos -= 9*size.width/10;
1810 0 : break;
1811 : case et_sb_up:
1812 0 : newpos -= size.width/15;
1813 0 : break;
1814 : case et_sb_down:
1815 0 : newpos += size.width/15;
1816 0 : break;
1817 : case et_sb_downpage:
1818 0 : newpos += 9*size.width/10;
1819 0 : break;
1820 : case et_sb_bottom:
1821 0 : newpos = hend;
1822 0 : break;
1823 : case et_sb_thumb:
1824 : case et_sb_thumbrelease:
1825 0 : newpos = sb->pos;
1826 0 : break;
1827 : }
1828 :
1829 0 : if ( newpos + size.width > hend )
1830 0 : newpos = hend - size.width;
1831 0 : if ( newpos<0 )
1832 0 : newpos = 0;
1833 0 : if ( newpos!=gme->off_left ) {
1834 0 : int lastc, diff = gme->off_left-newpos;
1835 : GRect clip;
1836 0 : gme->off_left = newpos;
1837 0 : GScrollBarSetPos(gme->hsb,newpos);
1838 :
1839 0 : clip.y = 1;
1840 0 : clip.height = size.height - 1;
1841 0 : for ( lastc = gme->cols-1; lastc>0 && gme->col_data[lastc].hidden; --lastc );
1842 :
1843 0 : gme->off_left = newpos;
1844 0 : GScrollBarSetPos(gme->hsb,newpos);
1845 0 : clip.x = 1; clip.y = 1; clip.width = size.width-1; clip.height = size.height-1;
1846 :
1847 0 : if (( gme->col_data[lastc].me_type == me_stringchoice ||
1848 0 : gme->col_data[lastc].me_type == me_stringchoicetrans ||
1849 0 : gme->col_data[lastc].me_type == me_stringchoicetag ||
1850 0 : gme->col_data[lastc].me_type == me_onlyfuncedit ||
1851 0 : gme->col_data[lastc].me_type == me_funcedit ) &&
1852 0 : gme->col_data[lastc].x <= gme->off_left + size.width - (gme->mark_size + gme->mark_skip) ) {
1853 0 : int xdiff = gme->off_left + size.width - (gme->mark_size + gme->mark_skip) - gme->col_data[lastc].x;
1854 : /* Catch the moment when we should stop scrolling the list mark area */
1855 0 : if ( xdiff + diff < 0 ) {
1856 0 : GDrawScroll( gme->nested,&clip,xdiff + diff,0 );
1857 0 : diff = -xdiff;
1858 : }
1859 0 : clip.width -= (gme->mark_size + gme->mark_skip);
1860 : }
1861 0 : GDrawScroll( gme->nested,&clip,diff,0 );
1862 0 : GME_PositionEdit(gme);
1863 0 : GME_RedrawTitles(gme);
1864 : }
1865 0 : }
1866 :
1867 0 : static void GME_VScroll(GMatrixEdit *gme,struct sbevent *sb) {
1868 0 : int newpos = gme->off_top;
1869 : int page;
1870 : GRect size;
1871 :
1872 0 : GDrawGetSize(gme->nested,&size);
1873 0 : page = size.height/(gme->fh+gme->vpad);
1874 :
1875 0 : switch( sb->type ) {
1876 : case et_sb_top:
1877 0 : newpos = 0;
1878 0 : break;
1879 : case et_sb_uppage:
1880 0 : newpos -= 9*page/10;
1881 0 : break;
1882 : case et_sb_up:
1883 0 : newpos--;
1884 0 : break;
1885 : case et_sb_down:
1886 0 : newpos++;
1887 0 : break;
1888 : case et_sb_downpage:
1889 0 : newpos += 9*page/10;
1890 0 : break;
1891 : case et_sb_bottom:
1892 0 : newpos = gme->rows+1;
1893 0 : break;
1894 : case et_sb_thumb:
1895 : case et_sb_thumbrelease:
1896 0 : newpos = sb->pos;
1897 0 : break;
1898 : }
1899 0 : if ( newpos + page > gme->rows+1 )
1900 0 : newpos = gme->rows+1 - page;
1901 0 : if ( newpos<0 )
1902 0 : newpos = 0;
1903 0 : if ( newpos!=gme->off_top ) {
1904 0 : int diff = (newpos-gme->off_top)*(gme->fh+gme->vpad);
1905 : GRect r;
1906 0 : gme->off_top = newpos;
1907 0 : GScrollBarSetPos(gme->vsb,newpos);
1908 0 : r.x = 1; r.y = 1; r.width = size.width-1; r.height = size.height-1;
1909 0 : GDrawScroll(gme->nested,&r,0,diff);
1910 0 : GME_PositionEdit(gme);
1911 0 : GDrawRequestExpose(gme->nested,&size,false);
1912 : }
1913 0 : }
1914 :
1915 0 : static int _GME_HScroll(GGadget *g, GEvent *e) {
1916 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_scrollbarchange ) {
1917 0 : GMatrixEdit *gme = (GMatrixEdit *) g->data;
1918 0 : GME_HScroll(gme,&e->u.control.u.sb);
1919 : }
1920 0 : return( true );
1921 : }
1922 :
1923 0 : static int _GME_VScroll(GGadget *g, GEvent *e) {
1924 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_scrollbarchange ) {
1925 0 : GMatrixEdit *gme = (GMatrixEdit *) g->data;
1926 0 : GME_VScroll(gme,&e->u.control.u.sb);
1927 : }
1928 0 : return( true );
1929 : }
1930 :
1931 0 : static int _GME_DeleteActive(GGadget *g, GEvent *e) {
1932 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
1933 0 : GMatrixEdit *gme = (GMatrixEdit *) g->data;
1934 0 : GME_DeleteActive(gme);
1935 : }
1936 0 : return( true );
1937 : }
1938 :
1939 0 : static GMenuItem *GMenuItemFromTI(GTextInfo *ti,int is_enum) {
1940 : int cnt;
1941 : GMenuItem *mi;
1942 :
1943 0 : for ( cnt=0; ti[cnt].text!=NULL || ti[cnt].line; ++cnt );
1944 0 : mi = calloc((cnt+1),sizeof(GMenuItem));
1945 0 : for ( cnt=0; ti[cnt].text!=NULL || ti[cnt].line; ++cnt ) {
1946 0 : mi[cnt].ti = ti[cnt];
1947 0 : if ( ti[cnt].bg == ti[cnt].fg )
1948 0 : mi[cnt].ti.bg = mi[cnt].ti.fg = COLOR_DEFAULT;
1949 0 : if ( mi[cnt].ti.text!=NULL ) {
1950 0 : if ( ti[cnt].text_is_1byte )
1951 0 : mi[cnt].ti.text = (unichar_t *) copy( (char *) mi[cnt].ti.text );
1952 : else
1953 0 : mi[cnt].ti.text = u_copy( mi[cnt].ti.text );
1954 0 : mi[cnt].ti.checkable = true;
1955 0 : mi[cnt].invoke = is_enum ? GME_EnumDispatch : GME_EnumStringDispatch;
1956 : }
1957 : }
1958 0 : return( mi );
1959 : }
1960 :
1961 : /* GMatrixElement: External interface *************************************** */
1962 0 : GGadget *GMatrixEditCreate(struct gwindow *base, GGadgetData *gd,void *data) {
1963 0 : struct matrixinit *matrix = gd->u.matrix;
1964 0 : GMatrixEdit *gme = calloc(1,sizeof(GMatrixEdit));
1965 : int r, c, bp;
1966 : int x;
1967 : GRect outer;
1968 : GRect pos;
1969 : GWindowAttrs wattrs;
1970 0 : int sbwidth = GDrawPointsToPixels(base,_GScrollBar_Width);
1971 : GGadgetData sub_gd;
1972 : GTextInfo label;
1973 : int as, ds, ld;
1974 :
1975 0 : if ( !gmatrixedit_inited )
1976 0 : _GMatrixEdit_Init();
1977 :
1978 0 : gme->g.funcs = &gmatrixedit_funcs;
1979 0 : _GGadget_Create(&gme->g,base,gd,data,&gmatrixedit_box);
1980 0 : gme->g.takes_input = true; gme->g.takes_keyboard = false; gme->g.focusable = false;
1981 :
1982 0 : gme->font = gmatrixedit_font;
1983 0 : gme->titfont = gmatrixedit_titfont;
1984 0 : GDrawWindowFontMetrics(base,gme->font,&as, &ds, &ld);
1985 0 : gme->font_as = gme->as = as;
1986 0 : gme->font_fh = gme->fh = as+ds;
1987 :
1988 0 : gme->rows = matrix->initial_row_cnt; gme->cols = matrix->col_cnt;
1989 0 : gme->row_max = gme->rows;
1990 0 : gme->hpad = gme->vpad = GDrawPointsToPixels(base,2);
1991 :
1992 0 : gme->col_data = calloc(gme->cols,sizeof(struct col_data));
1993 0 : for ( c=0; c<gme->cols; ++c ) {
1994 0 : gme->col_data[c].me_type = matrix->col_init[c].me_type;
1995 0 : gme->col_data[c].func = matrix->col_init[c].func;
1996 0 : if ( matrix->col_init[c].enum_vals!=NULL )
1997 0 : gme->col_data[c].enum_vals = GMenuItemFromTI(matrix->col_init[c].enum_vals,
1998 0 : matrix->col_init[c].me_type==me_enum );
1999 : else
2000 0 : gme->col_data[c].enum_vals = NULL;
2001 0 : gme->col_data[c].enable_enum = matrix->col_init[c].enable_enum;
2002 0 : gme->col_data[c].title = copy( matrix->col_init[c].title );
2003 0 : if ( gme->col_data[c].title!=NULL ) gme->has_titles = true;
2004 0 : gme->col_data[c].fixed = false;
2005 : }
2006 :
2007 0 : gme->data = calloc(gme->rows*gme->cols,sizeof(struct matrix_data));
2008 0 : memcpy(gme->data,matrix->matrix_data,gme->rows*gme->cols*sizeof(struct matrix_data));
2009 0 : for ( c=0; c<gme->cols; ++c ) {
2010 0 : enum me_type me_type = gme->col_data[c].me_type;
2011 0 : if ( me_type==me_string || me_type==me_bigstr || me_type==me_func ||
2012 0 : me_type==me_button || me_type==me_onlyfuncedit ||
2013 0 : me_type==me_funcedit || me_type==me_stringchoice ||
2014 0 : me_type==me_stringchoicetrans || me_type==me_stringchoicetag ) {
2015 0 : for ( r=0; r<gme->rows; ++r )
2016 0 : gme->data[r*gme->cols+c].u.md_str = copy(gme->data[r*gme->cols+c].u.md_str);
2017 : }
2018 : }
2019 :
2020 0 : gme->mark_length = GDrawPointsToPixels(base,_GListMarkSize);
2021 0 : gme->mark_size = gme->mark_length +
2022 0 : 2*GBoxBorderWidth(base,&_GListMark_Box);
2023 0 : gme->mark_skip = GDrawPointsToPixels(base,_GGadget_TextImageSkip);
2024 :
2025 : /* Can't do this earlier. It depends on matrix_data being set */
2026 0 : x = 1;
2027 0 : for ( c=0; c<gme->cols; ++c ) {
2028 0 : gme->col_data[c].x = x;
2029 0 : gme->col_data[c].width = GME_ColWidth(gme,c);
2030 0 : x += gme->col_data[c].width + gme->hpad;
2031 : }
2032 :
2033 0 : gme->pressed_col = -1;
2034 0 : gme->active_col = gme->active_row = -1;
2035 0 : gme->initrow = matrix->initrow;
2036 0 : gme->finishedit = matrix->finishedit;
2037 0 : gme->candelete = matrix->candelete;
2038 0 : gme->popupmenu = matrix->popupmenu;
2039 0 : gme->handle_key = matrix->handle_key;
2040 0 : gme->bigedittitle = matrix->bigedittitle;
2041 :
2042 0 : GMatrixEdit_GetDesiredSize(&gme->g,&outer,NULL);
2043 0 : if ( gme->g.r.width==0 )
2044 0 : gme->g.r.width = outer.width;
2045 : else
2046 0 : gme->g.desired_width = gme->g.r.width;
2047 0 : if ( gme->g.r.height==0 )
2048 0 : gme->g.r.height = outer.height;
2049 : else
2050 0 : gme->g.desired_height = gme->g.r.height;
2051 0 : bp = GBoxBorderWidth(gme->g.base,gme->g.box);
2052 0 : gme->g.inner.x = gme->g.r.x + bp;
2053 0 : gme->g.inner.y = gme->g.r.y + bp;
2054 0 : gme->g.inner.width = gme->g.r.width -2*bp;
2055 0 : gme->g.inner.height = gme->g.r.height -2*bp;
2056 :
2057 0 : memset(&sub_gd,0,sizeof(sub_gd));
2058 0 : memset(&label,0,sizeof(label));
2059 0 : sub_gd.pos.x = sub_gd.pos.y = 1; sub_gd.pos.width = sub_gd.pos.height = 0;
2060 0 : label.text = (unichar_t *) _("Delete");
2061 0 : label.text_is_1byte = true;
2062 0 : sub_gd.flags = gg_visible | gg_pos_in_pixels;
2063 0 : sub_gd.label = &label;
2064 0 : sub_gd.handle_controlevent = _GME_DeleteActive;
2065 0 : gme->del = GButtonCreate(base,&sub_gd,gme);
2066 0 : gme->del->contained = true;
2067 :
2068 0 : if ( gme->g.r.height<10 ) {
2069 0 : int extra = 2*bp+ sbwidth + (gme->has_titles?gme->fh:0) +
2070 0 : gme->del->r.height+DEL_SPACE;
2071 0 : gme->g.r.height = extra + gme->g.r.height*(gme->fh + gme->vpad);
2072 0 : gme->g.inner.height = gme->g.r.height - 2*bp;
2073 : }
2074 :
2075 0 : memset(&wattrs,0,sizeof(wattrs));
2076 0 : if ( gme->g.box->main_background!=COLOR_TRANSPARENT )
2077 0 : wattrs.mask = wam_events|wam_cursor|wam_backcol;
2078 : else
2079 0 : wattrs.mask = wam_events|wam_cursor;
2080 0 : wattrs.event_masks = ~(1<<et_charup);
2081 0 : wattrs.cursor = ct_pointer;
2082 0 : wattrs.background_color = gme->g.box->main_background;
2083 0 : pos = gme->g.inner;
2084 0 : pos.width -= sbwidth;
2085 0 : pos.height -= sbwidth + gme->del->inner.height+DEL_SPACE;
2086 0 : if ( gme->has_titles ) {
2087 0 : pos.y += gme->fh;
2088 0 : pos.height -= gme->fh;
2089 : }
2090 0 : gme->nested = GWidgetCreateSubWindow(base,&pos,matrixeditsub_e_h,gme,&wattrs);
2091 :
2092 0 : GGadgetMove(gme->del,
2093 0 : (gme->g.inner.width-gme->del->r.width)/2,
2094 0 : gme->g.inner.height-gme->del->r.height-DEL_SPACE/2);
2095 :
2096 0 : sub_gd.pos = pos;
2097 0 : sub_gd.pos.x = pos.x+pos.width; sub_gd.pos.width = sbwidth;
2098 0 : sub_gd.flags = (gd->flags & (gg_visible | gg_enabled)) | gg_sb_vert | gg_pos_in_pixels;
2099 0 : sub_gd.handle_controlevent = _GME_VScroll;
2100 0 : gme->vsb = GScrollBarCreate(base,&sub_gd,gme);
2101 0 : gme->vsb->contained = true;
2102 :
2103 0 : sub_gd.pos = pos;
2104 0 : sub_gd.pos.y = pos.y+pos.height; sub_gd.pos.height = sbwidth;
2105 0 : sub_gd.flags = gg_visible | gg_enabled | gg_pos_in_pixels;
2106 0 : sub_gd.handle_controlevent = _GME_HScroll;
2107 0 : gme->hsb = GScrollBarCreate(base,&sub_gd,gme);
2108 0 : gme->hsb->contained = true;
2109 :
2110 0 : GME_RecalcFH(gme);
2111 : {
2112 : static GBox small = GBOX_EMPTY;
2113 : static unichar_t nullstr[1] = { 0 };
2114 :
2115 0 : small.main_background = gmatrixedit_activebg;
2116 0 : small.main_foreground = gmatrixedit_activecol;
2117 0 : memset(&sub_gd,'\0',sizeof(sub_gd));
2118 0 : memset(&label,'\0',sizeof(label));
2119 :
2120 0 : label.text = nullstr;
2121 0 : label.font = gme->font;
2122 0 : sub_gd.pos.height = gme->fh;
2123 0 : sub_gd.pos.width = 40;
2124 0 : sub_gd.label = &label;
2125 0 : sub_gd.box = &small;
2126 0 : sub_gd.flags = gg_enabled | gg_pos_in_pixels | gg_dontcopybox | gg_text_xim;
2127 0 : gme->tf = GTextCompletionCreate(gme->nested,&sub_gd,gme);
2128 0 : ((GTextField *) (gme->tf))->accepts_tabs = false;
2129 : }
2130 :
2131 0 : if ( gme->g.state!=gs_invisible )
2132 0 : GDrawSetVisible(gme->nested,true);
2133 0 : return( &gme->g );
2134 : }
2135 :
2136 0 : void GMatrixEditSet(GGadget *g,struct matrix_data *data, int rows, int copy_it) {
2137 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2138 : int r,c;
2139 :
2140 0 : if ( data==gme->data ) {
2141 0 : if ( rows<gme->rows )
2142 0 : gme->rows = rows;
2143 0 : GME_RecalcFH(gme);
2144 : } else {
2145 0 : MatrixDataFree(gme);
2146 :
2147 0 : gme->rows = gme->row_max = rows;
2148 0 : if ( !copy_it ) {
2149 0 : gme->data = data;
2150 : } else {
2151 0 : gme->data = calloc(rows*gme->cols,sizeof(struct matrix_data));
2152 0 : memcpy(gme->data,data,rows*gme->cols*sizeof(struct matrix_data));
2153 0 : for ( c=0; c<gme->cols; ++c ) {
2154 0 : enum me_type me_type = gme->col_data[c].me_type;
2155 0 : if ( me_type==me_string || me_type==me_bigstr || me_type==me_func ||
2156 0 : me_type==me_button || me_type==me_onlyfuncedit ||
2157 0 : me_type==me_funcedit || me_type==me_stringchoice ||
2158 0 : me_type==me_stringchoicetrans || me_type==me_stringchoicetag ) {
2159 0 : for ( r=0; r<rows; ++r )
2160 0 : gme->data[r*gme->cols+c].u.md_str = copy(gme->data[r*gme->cols+c].u.md_str);
2161 : }
2162 : }
2163 : }
2164 0 : GME_RecalcFH(gme);
2165 :
2166 0 : gme->active_row = gme->active_col = -1;
2167 0 : GME_EnableDelete(gme);
2168 0 : if ( !GME_AdjustCol(gme,-1)) {
2169 0 : GME_FixScrollBars(gme);
2170 0 : GDrawRequestExpose(gme->nested,NULL,false);
2171 : }
2172 : }
2173 0 : }
2174 :
2175 0 : void GMatrixEditDeleteRow(GGadget *g,int row) {
2176 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2177 :
2178 0 : if ( row!=-1 )
2179 0 : gme->active_row = row;
2180 0 : GME_DeleteActive(gme);
2181 0 : }
2182 :
2183 0 : int GMatrixEditStringDlg(GGadget *g,int row,int col) {
2184 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2185 : char *str;
2186 :
2187 0 : if ( gme->edit_active ) {
2188 0 : if ( !GME_FinishEdit(gme) )
2189 0 : return(false);
2190 : }
2191 0 : if ( row!=-1 )
2192 0 : gme->active_row = row;
2193 0 : if ( col!=-1 )
2194 0 : gme->active_col = col;
2195 0 : str = MD_Text(gme,row,col);
2196 0 : GME_StrBigEdit(gme,str);
2197 0 : free(str);
2198 0 : return( true );
2199 : }
2200 :
2201 0 : struct matrix_data *GMatrixEditGet(GGadget *g, int *rows) {
2202 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2203 :
2204 0 : if ( gme->edit_active && !GME_FinishEdit(gme) ) {
2205 0 : *rows = 0;
2206 0 : return( NULL );
2207 : }
2208 :
2209 0 : *rows = gme->rows;
2210 0 : return( gme->data );
2211 : }
2212 :
2213 0 : struct matrix_data *_GMatrixEditGet(GGadget *g, int *rows) {
2214 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2215 :
2216 : /* Does not try to parse the active textfield, if any */
2217 0 : *rows = gme->rows;
2218 0 : return( gme->data );
2219 : }
2220 :
2221 0 : GGadget *_GMatrixEditGetActiveTextField(GGadget *g) {
2222 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2223 0 : if ( gme->edit_active )
2224 0 : return( gme->tf );
2225 :
2226 0 : return( NULL );
2227 : }
2228 :
2229 0 : int GMatrixEditGetActiveRow(GGadget *g) {
2230 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2231 :
2232 0 : return( gme->active_row );
2233 : }
2234 :
2235 0 : int GMatrixEditGetActiveCol(GGadget *g) {
2236 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2237 :
2238 0 : return( gme->active_col );
2239 : }
2240 :
2241 0 : void GMatrixEditSetNewText(GGadget *g, char *text) {
2242 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2243 :
2244 0 : free(gme->newtext);
2245 0 : gme->newtext = copy(text);
2246 0 : }
2247 :
2248 0 : void GMatrixEditSetOtherButtonEnable(GGadget *g, void (*sob)(GGadget *g, int r, int c)) {
2249 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2250 :
2251 0 : gme->setotherbuttons = sob;
2252 0 : }
2253 :
2254 0 : void GMatrixEditSetMouseMoveReporter(GGadget *g, void (*rmm)(GGadget *g, int r, int c)) {
2255 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2256 :
2257 0 : gme->reportmousemove = rmm;
2258 0 : }
2259 :
2260 0 : void GMatrixEditSetTextChangeReporter(GGadget *g, void (*tcr)(GGadget *g, int r, int c, GGadget *text)) {
2261 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2262 :
2263 0 : gme->reporttextchanged = tcr;
2264 0 : }
2265 :
2266 0 : void GMatrixEditSetValidateStr(GGadget *g, char *(*validate)(GGadget *g, int r, int c, int wasnew, char *str)) {
2267 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2268 :
2269 0 : gme->validatestr = validate;
2270 0 : }
2271 :
2272 0 : void GMatrixEditSetUpDownVisible(GGadget *g, int visible) {
2273 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2274 : GGadgetCreateData gcd[3];
2275 : GTextInfo label[2];
2276 : int i;
2277 :
2278 0 : if ( gme->up==NULL ) {
2279 0 : if ( !visible )
2280 0 : return;
2281 :
2282 0 : memset(gcd,0,sizeof(gcd));
2283 0 : memset(label,0,sizeof(label));
2284 0 : i = 0;
2285 :
2286 : /* I want the 2 pronged arrow, but gdraw can't find a nice one */
2287 : /* label[i].text = (unichar_t *) "⇑"; *//* Up Arrow */
2288 0 : label[i].text = (unichar_t *) "↑"; /* Up Arrow */
2289 0 : label[i].text_is_1byte = true;
2290 0 : gcd[i].gd.label = &label[i];
2291 0 : gcd[i].gd.flags = gg_visible /*| gg_enabled*/ ;
2292 0 : gcd[i].gd.handle_controlevent = _GME_Up;
2293 0 : gcd[i].data = gme;
2294 0 : gcd[i++].creator = GButtonCreate;
2295 :
2296 : /* I want the 2 pronged arrow, but gdraw can't find a nice one */
2297 : /* label[i].text = (unichar_t *) "⇓"; *//* Down Arrow */
2298 0 : label[i].text = (unichar_t *) "↓"; /* Down Arrow */
2299 0 : label[i].text_is_1byte = true;
2300 0 : gcd[i].gd.label = &label[i];
2301 0 : gcd[i].gd.flags = gg_visible /*| gg_enabled*/ ;
2302 0 : gcd[i].gd.handle_controlevent = _GME_Down;
2303 0 : gcd[i].data = gme;
2304 0 : gcd[i++].creator = GButtonCreate;
2305 0 : GGadgetsCreate(g->base,gcd);
2306 :
2307 0 : gme->up = gcd[0].ret;
2308 0 : gme->down = gcd[1].ret;
2309 0 : gme->up->contained = gme->down->contained = true;
2310 : } else {
2311 0 : GGadgetSetVisible(gme->up,visible);
2312 0 : GGadgetSetVisible(gme->down,visible);
2313 : }
2314 : }
2315 :
2316 0 : void GMatrixEditAddButtons(GGadget *g, GGadgetCreateData *gcd) {
2317 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2318 0 : int i, base=0;
2319 :
2320 0 : if ( gme->buttonlist!=NULL ) {
2321 0 : for ( base=0; gme->buttonlist[base]!=NULL; ++base );
2322 : }
2323 0 : for ( i=0; gcd[i].creator!=NULL; ++i );
2324 0 : gme->buttonlist = realloc(gme->buttonlist,(i+base+1)*sizeof(GGadget *));
2325 0 : GGadgetsCreate(g->base,gcd);
2326 0 : for ( i=0; gcd[i].creator!=NULL; ++i ) {
2327 0 : gme->buttonlist[base+i] = gcd[i].ret;
2328 0 : gcd[i].ret->contained = true;
2329 : }
2330 0 : gme->buttonlist[base+i] = NULL;
2331 0 : }
2332 :
2333 0 : void GMatrixEditEnableColumn(GGadget *g, int col, int enabled) {
2334 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2335 : /* User must do a refresh of the gadget. Don't want to do it always */
2336 : /* because multiple calls might cause a flicker */
2337 :
2338 0 : if ( col<0 || col>=gme->cols )
2339 0 : return;
2340 0 : gme->col_data[col].disabled = !enabled;
2341 : }
2342 :
2343 0 : void GMatrixEditShowColumn(GGadget *g, int col, int visible) {
2344 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2345 :
2346 0 : if ( col<0 || col>=gme->cols )
2347 0 : return;
2348 0 : gme->col_data[col].hidden = !visible;
2349 0 : gme->col_data[col].fixed = false;
2350 0 : GME_AdjustCol(gme,-1);
2351 : }
2352 :
2353 0 : void GMatrixEditSetColumnChoices(GGadget *g, int col, GTextInfo *ti) {
2354 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2355 :
2356 0 : if ( gme->col_data[col].enum_vals!=NULL )
2357 0 : GMenuItemArrayFree(gme->col_data[col].enum_vals);
2358 0 : if ( ti!=NULL )
2359 0 : gme->col_data[col].enum_vals = GMenuItemFromTI(ti,
2360 0 : gme->col_data[col].me_type==me_enum );
2361 : else
2362 0 : gme->col_data[col].enum_vals = NULL;
2363 0 : }
2364 :
2365 0 : GMenuItem *GMatrixEditGetColumnChoices(GGadget *g, int col) {
2366 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2367 :
2368 0 : return( gme->col_data[col].enum_vals );
2369 : }
2370 :
2371 0 : int GMatrixEditGetColCnt(GGadget *g) {
2372 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2373 0 : return( gme->cols );
2374 : }
2375 :
2376 0 : void GMatrixEditScrollToRowCol(GGadget *g,int r, int c) {
2377 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2378 0 : int rows_shown = gme->vsb->r.height/(gme->fh+gme->vpad);
2379 0 : int context = rows_shown/3;
2380 0 : int needs_expose = true;
2381 0 : int width = gme->hsb->r.width;
2382 : int i;
2383 : GRect size;
2384 :
2385 0 : if ( r<0 ) r = 0; else if ( r>=gme->rows ) r = gme->rows-1;
2386 0 : if ( r<gme->off_top || r>=gme->off_top+rows_shown ) {
2387 0 : gme->off_top = r-context;
2388 0 : if ( gme->off_top<0 )
2389 0 : gme->off_top = 0;
2390 0 : needs_expose = true;
2391 : }
2392 0 : if ( c<0 ) c = 0; else if ( c>=gme->cols ) c = gme->cols-1;
2393 0 : for ( i=0; i<gme->cols; ++i ) {
2394 0 : if ( gme->col_data[i].x-gme->off_left>=0 )
2395 0 : break;
2396 : }
2397 0 : if ( c<i ) {
2398 0 : if ( c>0 && gme->col_data[c-1].width + gme->col_data[c].width<width )
2399 0 : gme->off_left = gme->col_data[c-1].x;
2400 : else
2401 0 : gme->off_left = gme->col_data[c ].x;
2402 0 : needs_expose = true;
2403 : } else {
2404 0 : for ( ; i<gme->cols; ++i ) {
2405 0 : if ( gme->col_data[i].x+gme->col_data[i].width-gme->off_left>width )
2406 0 : break;
2407 : }
2408 0 : if ( c>=i && gme->col_data[c].x!=gme->off_left ) {
2409 0 : gme->off_left = gme->col_data[c].x;
2410 0 : needs_expose = true;
2411 : }
2412 : }
2413 0 : if ( needs_expose ) {
2414 0 : int hend = gme->col_data[gme->cols-1].x + gme->col_data[gme->cols-1].width;
2415 :
2416 0 : GDrawGetSize(gme->nested,&size);
2417 0 : if ( gme->off_left>hend-size.width )
2418 0 : gme->off_left = hend-size.width;
2419 0 : if ( gme->off_left<0 )
2420 0 : gme->off_left = 0;
2421 0 : GScrollBarSetPos(gme->hsb,gme->off_left);
2422 0 : GScrollBarSetPos(gme->vsb,gme->off_top);
2423 0 : GGadgetRedraw(&gme->g);
2424 : /* Used to request expose only if the row or column we are scrolling to */
2425 : /* was outside of the visible area. However we need expose anyway, because */
2426 : /* otherwise it is impossible to properly highlight fields in the active row. */
2427 : /* So the rectangle associated with the expose event is now the only thing which */
2428 : /* makes some difference. */
2429 : } else {
2430 0 : GGadgetGetSize(gme->tf,&size);
2431 0 : GDrawRequestExpose(gme->nested,&size,false);
2432 : }
2433 0 : }
2434 :
2435 0 : void GMatrixEditSetColumnCompletion(GGadget *g, int col,
2436 : GTextCompletionHandler completion) {
2437 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2438 :
2439 0 : gme->col_data[col].completer = completion;
2440 0 : }
2441 :
2442 0 : void GMatrixEditSetBeforeDelete(GGadget *g, void (*predelete)(GGadget *g, int r)) {
2443 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2444 :
2445 0 : gme->predelete = predelete;
2446 0 : }
2447 :
2448 0 : void GMatrixEditSetRowMotionCallback(GGadget *g, void (*rowmotion)(GGadget *g, int oldr, int newr)) {
2449 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2450 :
2451 0 : gme->rowmotion = rowmotion;
2452 0 : }
2453 :
2454 0 : void GMatrixEditSetCanUpDown(GGadget *g, enum gme_updown (*canupdown)(GGadget *g, int r)) {
2455 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2456 :
2457 0 : gme->canupdown = canupdown;
2458 0 : }
2459 :
2460 0 : void GMatrixEditActivateRowCol(GGadget *g, int r, int c) {
2461 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2462 :
2463 0 : gme->active_row = r;
2464 0 : gme->active_col = c;
2465 0 : GME_EnableDelete(gme);
2466 0 : GDrawRequestExpose(gme->nested,NULL,false);
2467 0 : }
2468 :
2469 0 : void GMatrixEditSetEditable(GGadget *g, int editable ) {
2470 0 : GMatrixEdit *gme = (GMatrixEdit *) g;
2471 :
2472 0 : gme->no_edit = !editable;
2473 0 : GGadgetSetVisible(gme->del,editable);
2474 0 : GMatrixEdit_Resize(&gme->g,gme->g.r.width,gme->g.r.height);
2475 0 : GDrawRequestExpose(gme->nested,NULL,false);
2476 0 : }
2477 :
2478 0 : GResInfo *_GMatrixEditRIHead(void) {
2479 : /* GRect size; */
2480 :
2481 0 : _GMatrixEdit_Init();
2482 : /* GDrawGetSize(GDrawGetRoot(NULL),&size);*/
2483 : if ( true /* size.height<900*/ ) {
2484 0 : gmatrixedit_ri.next = &gmatrixedit2_ri;
2485 0 : gmatrixedit_ri.extras = NULL;
2486 0 : gmatrixedit_ri.seealso1 = &gmatrixedit2_ri;
2487 : }
2488 :
2489 0 : return( &gmatrixedit_ri );
2490 : }
|