Hardcoded patterns
[grace.git] / src / ssd_ui.c
blob05973208f09fabe6bd343fdbf3be28f8b647d494
1 /*
2 * Grace - GRaphing, Advanced Computation and Exploration of data
3 *
4 * Home page: http://plasma-gate.weizmann.ac.il/Grace/
5 *
6 * Copyright (c) 1996-2005 Grace Development Team
7 *
8 * Maintained by Evgeny Stambulchik
9 *
11 * All Rights Reserved
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 /* SSData UI */
30 #include <stdlib.h>
31 #include <string.h>
33 #include "events.h"
34 #include "utils.h"
35 #include "explorer.h"
36 #include "xprotos.h"
37 #include "globals.h"
39 /* default cell value precision */
40 #define CELL_PREC 8
42 /* default cell value format */
43 #define CELL_FORMAT FORMAT_GENERAL
45 /* default cell width */
46 #define CELL_WIDTH 12
48 /* string cell width */
49 #define STRING_CELL_WIDTH 128
51 /* minimum size of the spreadsheet matrix */
52 #define EXTRA_SS_ROWS 20
53 #define EXTRA_SS_COLS 3
55 #define VISIBLE_SS_ROWS 18
56 #define VISIBLE_SS_COLS 3
58 static int do_hotlinkfile_proc(FSBStructure *fsb, char *filename, void *data)
60 SSDataUI *ui = (SSDataUI *) data;
62 TextSetString(ui->hotfile, filename);
64 return TRUE;
68 * create file selection pop up to choose the file for hotlink
70 static void create_hotfiles_popup(Widget but, void *data)
72 static FSBStructure *fsb = NULL;
74 set_wait_cursor();
76 if (fsb == NULL) {
77 fsb = CreateFSBDialog(app_shell, "Hotlinked file");
78 AddFSBDialogCB(fsb, do_hotlinkfile_proc, data);
79 FSBDialogSetPattern(fsb, "*.dat");
80 WidgetManage(fsb->FSB);
83 DialogRaise(fsb->FSB);
85 unset_wait_cursor();
89 * We use a stack of static buffers to work around asynchronous
90 * refresh/redraw events
92 #define STACKLEN (VISIBLE_SS_ROWS*VISIBLE_SS_COLS)
94 static char *get_cell_content(SSDataUI *ui, int row, int column, int *format)
96 static char buf[STACKLEN][32];
97 static int stackp = 0;
99 int nrows = ssd_get_nrows(ui->q);
100 ss_column *col = ssd_get_col(ui->q, column);
101 char *s;
103 if (col && row >= 0 && row < nrows) {
104 unsigned int prec;
105 *format = col->format;
106 switch (col->format) {
107 case FFORMAT_STRING:
108 s = ((char **) col->data)[row];
109 break;
110 default:
111 prec = project_get_prec(get_parent_project(ui->q));
112 sprintf(buf[stackp], "%.*g", prec, ((double *) col->data)[row]);
113 s = buf[stackp];
114 stackp++;
115 stackp %= STACKLEN;
117 /* get rid of spaces */
118 while (s && *s == ' ') {
119 s++;
122 break;
124 } else {
125 s = "";
128 return s;
131 static int drawcellCB(TableEvent *event)
133 SSDataUI *ui = (SSDataUI *) event->anydata;
134 int format;
136 event->value_type = TABLE_CELL_STRING;
137 event->value = get_cell_content(ui, event->row, event->col, &format);
139 return TRUE;
142 static int enterCB(TableEvent *event)
144 SSDataUI *ui = (SSDataUI *) event->anydata;
146 int ncols = ssd_get_ncols(ui->q);
148 if (event->col >= 0 && event->col <= ncols) {
149 TableDeselectAllCells(ui->mw);
150 return TRUE;
151 } else {
152 return FALSE;
156 static int leaveCB(TableEvent *event)
158 SSDataUI *ui = (SSDataUI *) event->anydata;
160 int nrows = ssd_get_nrows(ui->q);
161 int ncols = ssd_get_ncols(ui->q);
162 int format;
163 double value;
165 int changed = FALSE;
167 GraceApp *gapp = gapp_from_quark(ui->q);
169 if (event->row < 0 || event->col < 0 || event->col > ncols) {
170 return TRUE;
173 if (event->row >= nrows && !string_is_empty(event->value)) {
174 if (ssd_set_nrows(ui->q, event->row + 1) == RETURN_SUCCESS) {
175 changed = TRUE;
179 if (event->col == ncols && !string_is_empty(event->value)) {
180 if (parse_date_or_number(get_parent_project(ui->q),
181 event->value, FALSE, get_date_hint(gapp), &value) == RETURN_SUCCESS) {
182 format = FFORMAT_NUMBER;
183 } else {
184 format = FFORMAT_STRING;
186 if (ssd_add_col(ui->q, format)) {
187 ncols++;
188 changed = TRUE;
192 if (event->col < ncols) {
193 char *old_value = get_cell_content(ui, event->row, event->col, &format);
194 if (!strings_are_equal(old_value, event->value)) {
195 switch (format) {
196 case FFORMAT_STRING:
197 if (ssd_set_string(ui->q, event->row, event->col, event->value) ==
198 RETURN_SUCCESS) {
199 quark_dirtystate_set(ui->q, TRUE);
200 changed = TRUE;
202 break;
203 default:
204 if (graal_eval_expr(grace_get_graal(gapp->grace),
205 event->value, &value, gproject_get_top(gapp->gp)) == RETURN_SUCCESS) {
207 unsigned int prec;
208 char buf[32];
209 double val;
211 prec = project_get_prec(get_parent_project(ui->q));
212 sprintf(buf, "%.*g", prec, value);
214 if (parse_date_or_number(get_parent_project(ui->q),
215 buf, FALSE, get_date_hint(gapp), &val) == RETURN_SUCCESS) {
217 if (ssd_set_value(ui->q, event->row, event->col, val) == RETURN_SUCCESS) {
218 quark_dirtystate_set(ui->q, TRUE);
219 changed = TRUE;
222 } else {
223 errmsg("Can't parse input value");
224 return FALSE;
226 break;
231 if (changed) {
232 snapshot_and_update(gapp->gp, FALSE);
235 return TRUE;
238 static int labelCB(TableEvent *event)
240 SSDataUI *ui = (SSDataUI *) event->anydata;
241 static int last_row, last_column;
242 int i;
244 if (!event || event->type != MOUSE_PRESS) {
245 return TRUE;
248 if (event->button == LEFT_BUTTON) {
249 TableCommitEdit(ui->mw, TRUE);
251 if (event->row_label) {
252 if (event->modifiers & CONTROL_MODIFIER) {
253 if (TableIsRowSelected(ui->mw, event->row)) {
254 TableDeselectRow(ui->mw, event->row);
255 } else {
256 TableSelectRow(ui->mw, event->row);
258 last_row = event->row;
259 } else
260 if ((event->modifiers & SHIFT_MODIFIER) && last_row >= 0) {
261 for (i = MIN2(last_row, event->row); i <= MAX2(last_row, event->row); i++) {
262 TableSelectRow(ui->mw, i);
264 } else {
265 TableDeselectAllCells(ui->mw);
266 TableSelectRow(ui->mw, event->row);
267 last_row = event->row;
270 last_column = -1;
271 } else {
272 if (event->modifiers & CONTROL_MODIFIER) {
273 if (TableIsColSelected(ui->mw, event->col)) {
274 TableDeselectCol(ui->mw, event->col);
275 } else {
276 TableSelectCol(ui->mw, event->col);
278 last_column = event->col;
279 } else
280 if ((event->modifiers & SHIFT_MODIFIER) && last_column >= 0) {
281 for (i = MIN2(last_column, event->col); i <= MAX2(last_column, event->col); i++) {
282 TableSelectCol(ui->mw, i);
284 } else {
285 TableDeselectAllCells(ui->mw);
286 TableSelectCol(ui->mw, event->col);
287 last_column = event->col;
290 last_row = -1;
294 if (event->button == RIGHT_BUTTON) {
295 ss_column *col;
296 if (!event->row_label) {
297 ui->cb_column = event->col;
300 col = ssd_get_col(ui->q, ui->cb_column);
301 WidgetSetSensitive(ui->delete_btn, col != NULL);
302 WidgetSetSensitive(ui->index_btn, col != NULL && ui->cb_column != 0 &&
303 (col->format == FFORMAT_NUMBER || col->format == FFORMAT_DATE));
304 WidgetSetSensitive(ui->unindex_btn, ui->cb_column == 0 && col != NULL &&
305 ssd_is_indexed(ui->q));
307 PopupMenuShow(ui->popup, event->udata);
310 return TRUE;
313 static void col_delete_cb(Widget but, void *udata)
315 SSDataUI *ui = (SSDataUI *) udata;
316 if (ssd_delete_col(ui->q, ui->cb_column) == RETURN_SUCCESS) {
317 snapshot_and_update(gapp->gp, TRUE);
321 static void index_cb(Widget but, void *udata)
323 SSDataUI *ui = (SSDataUI *) udata;
324 if (ssd_set_index(ui->q, ui->cb_column) == RETURN_SUCCESS) {
325 snapshot_and_update(gapp->gp, TRUE);
329 static void unindex_cb(Widget but, void *udata)
331 SSDataUI *ui = (SSDataUI *) udata;
332 if (ssd_set_indexed(ui->q, FALSE) == RETURN_SUCCESS) {
333 snapshot_and_update(gapp->gp, TRUE);
337 static void col_cb(ListStructure *sel, int n, int *values, void *data)
339 SSDataUI *ui = (SSDataUI *) data;
340 Quark *ssd = (Quark *) sel->anydata;
342 if (ssd && n == 1) {
343 int col = values[0];
344 WidgetSetSensitive(ui->col_label->text, TRUE);
345 TextSetString(ui->col_label, ssd_get_col_label(ssd, col));
346 } else {
347 WidgetSetSensitive(ui->col_label->text, FALSE);
351 SSDataUI *create_ssd_ui(ExplorerUI *eui)
353 SSDataUI *ui;
355 Widget tab, fr, rc, rc1, wbut;
357 ui = xmalloc(sizeof(SSDataUI));
358 if (!ui) {
359 return NULL;
361 memset(ui, 0, sizeof(SSDataUI));
363 /* ------------ Tabs -------------- */
365 tab = CreateTab(eui->scrolled_window);
366 AddHelpCB(tab, "doc/UsersGuide.html#ssd-properties");
368 /* ------------ Main tab -------------- */
369 ui->main_tp = CreateTabPage(tab, "Data");
371 ui->mw = CreateTable("SSD", ui->main_tp,
372 EXTRA_SS_ROWS, EXTRA_SS_COLS,
373 VISIBLE_SS_ROWS, VISIBLE_SS_COLS);
374 TableSSDInit(ui->mw);
375 TableSetDefaultColWidth(ui->mw, CELL_WIDTH);
376 TableSetDefaultColLabelAlignment(ui->mw, ALIGN_CENTER);
378 AddTableDrawCellCB(ui->mw, drawcellCB, ui);
379 AddTableLeaveCellCB(ui->mw, leaveCB, ui);
380 AddTableEnterCellCB(ui->mw, enterCB, ui);
381 AddTableLabelActivateCB(ui->mw, labelCB, ui);
383 ui->popup = CreatePopupMenu(ui->mw);
384 ui->delete_btn = CreateMenuButton(ui->popup, "Delete column", '\0', col_delete_cb, ui);
385 ui->index_btn = CreateMenuButton(ui->popup, "Set as index", '\0', index_cb, ui);
386 ui->unindex_btn = CreateMenuButton(ui->popup, "Unset index", '\0', unindex_cb, ui);
389 /* ------------ Column props -------------- */
390 ui->column_tp = CreateTabPage(tab, "Columns");
391 ui->col_sel = CreateColChoice(ui->column_tp, "Column:", LIST_TYPE_SINGLE);
392 AddListChoiceCB(ui->col_sel, col_cb, ui);
394 ui->col_label = CreateCSText(ui->column_tp, "Label:");
395 WidgetSetSensitive(ui->col_label->text, FALSE);
396 AddTextActivateCB(ui->col_label, text_explorer_cb, eui);
399 /* ------------ Hotlink tab -------------- */
400 ui->hotlink_tp = CreateTabPage(tab, "Hotlink");
402 fr = CreateFrame(ui->hotlink_tp, "Hotlink");
403 rc = CreateVContainer(fr);
404 rc1 = CreateHContainer(rc);
405 ui->hotlink = CreateToggleButton(rc1, "Enabled");
406 ui->hotsrc = CreateOptionChoiceVA(rc1, "Source type:",
407 "Disk", SOURCE_DISK,
408 "Pipe", SOURCE_PIPE,
409 NULL);
410 rc1 = CreateHContainer(rc);
411 ui->hotfile = CreateText2(rc1, "File name:", 20);
412 wbut = CreateButton(rc1, "Browse...");
413 AddButtonCB(wbut, create_hotfiles_popup, ui);
415 SelectTabPage(tab, ui->main_tp);
417 ui->top = tab;
419 return ui;
422 void update_ssd_ui(SSDataUI *ui, Quark *q)
424 if (ui && q) {
425 int i, nc, nr, new_nc, new_nr, ncols, nrows, nfixed_cols;
426 int delta_nc, delta_nr;
427 int *maxlengths;
428 char **rowlabels, **collabels;
430 if (ui->q != q) {
431 TableDeselectAllCells(ui->mw);
434 ui->q = q;
436 ncols = ssd_get_ncols(q);
437 nrows = ssd_get_nrows(q);
439 new_nc = ncols + EXTRA_SS_COLS;
440 new_nr = nrows + EXTRA_SS_ROWS;
442 if (ssd_is_indexed(q)) {
443 nfixed_cols = 1;
444 } else {
445 nfixed_cols = 0;
448 nr = TableGetNrows(ui->mw);
449 nc = TableGetNcols(ui->mw);
451 delta_nr = new_nr - nr;
452 delta_nc = new_nc - nc;
454 if (delta_nr > 0) {
455 TableAddRows(ui->mw, delta_nr);
456 } else if (delta_nr < 0) {
457 TableDeleteRows(ui->mw, -delta_nr);
460 rowlabels = xmalloc(new_nr*sizeof(char *));
461 for (i = 0; i < new_nr; i++) {
462 char buf[32];
463 sprintf(buf, "%d", i + 1);
464 rowlabels[i] = copy_string(NULL, buf);
466 TableSetRowLabels(ui->mw, rowlabels);
467 for (i = 0; i < new_nr; i++) {
468 xfree(rowlabels[i]);
470 xfree(rowlabels);
472 maxlengths = xmalloc(new_nc*SIZEOF_INT);
473 collabels = xmalloc(new_nc*sizeof(char *));
475 for (i = 0; i < new_nc; i++) {
476 ss_column *col = ssd_get_col(q, i);
477 if (col && col->format == FFORMAT_STRING) {
478 maxlengths[i] = STRING_CELL_WIDTH;
479 } else {
480 maxlengths[i] = 2*CELL_WIDTH;
482 if (col && !string_is_empty(col->label)) {
483 collabels[i] = copy_string(NULL, col->label);
484 } else {
485 unsigned int coli;
486 char buf[32];
488 coli = i;
489 sprintf(buf, "%c", coli%26 + 'A');
490 while ((coli /= 26)) {
491 memmove(&buf[1], buf, strlen(buf) + 1);
492 buf[0] = coli%26 + 'A' - 1;
495 collabels[i] = copy_string(NULL, buf);
499 if (delta_nc > 0) {
500 TableAddCols(ui->mw, delta_nc);
501 } else if (delta_nc < 0) {
502 TableDeleteCols(ui->mw, -delta_nc);
505 TableSetColMaxlengths(ui->mw, maxlengths);
506 TableSetColLabels(ui->mw, collabels);
507 TableSetFixedCols(ui->mw, nfixed_cols);
508 TableUpdateVisibleRowsCols(ui->mw);
510 xfree(maxlengths);
511 for (i = 0; i < new_nc; i++) {
512 xfree(collabels[i]);
514 xfree(collabels);
516 UpdateColChoice(ui->col_sel, q);
520 int set_ssd_data(SSDataUI *ui, Quark *q, void *caller)
522 int retval = RETURN_SUCCESS;
524 if (ui && q) {
525 if (!caller) {
526 /* commit the last entered cell changes */
527 TableCommitEdit(ui->mw, FALSE);
530 if (!caller || caller == ui->col_label) {
531 int col;
532 if (GetSingleListChoice(ui->col_sel, &col) == RETURN_SUCCESS) {
533 char *s = TextGetString(ui->col_label);
534 ssd_set_col_label(q, col, s);
535 xfree(s);
537 /* FIXME: this is an overkill */
538 update_ssd_ui(ui, q);
543 return retval;