2 // "$Id: table-spreadsheet.cxx 8183 2011-01-04 17:31:56Z AlbrechtS $"
4 // Simple example of an interactive spreadsheet using Fl_Table.
5 // Uses Mr. Satan's technique of instancing an Fl_Input around.
7 // Copyright 1998-2010 by Bill Spitzak and others.
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Library General Public
11 // License as published by the Free Software Foundation; either
12 // version 2 of the License, or (at your option) any later version.
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Library General Public License for more details.
19 // You should have received a copy of the GNU Library General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24 // Please report all bugs and problems on the following page:
26 // http://www.fltk.org/str.php
31 #include <FL/Fl_Double_Window.H>
32 #include <FL/Fl_Table.H>
33 #include <FL/Fl_Int_Input.H>
34 #include <FL/fl_draw.H>
36 const int MAX_COLS
= 10;
37 const int MAX_ROWS
= 10;
39 class Spreadsheet
: public Fl_Table
{
40 Fl_Int_Input
*input
; // single instance of Fl_Int_Input widget
41 int values
[MAX_ROWS
][MAX_COLS
]; // array of data for cells
42 int row_edit
, col_edit
; // row/col being modified
45 void draw_cell(TableContext context
,int=0,int=0,int=0,int=0,int=0,int=0);
46 void event_callback2(); // table's event callback (instance)
47 static void event_callback(Fl_Widget
*,void *v
) { // table's event callback (static)
48 ((Spreadsheet
*)v
)->event_callback2();
50 static void input_cb(Fl_Widget
*,void* v
) { // input widget's callback
51 ((Spreadsheet
*)v
)->set_value_hide();
55 Spreadsheet(int X
,int Y
,int W
,int H
,const char* L
=0) : Fl_Table(X
,Y
,W
,H
,L
) {
56 callback(&event_callback
, (void*)this);
57 when(FL_WHEN_NOT_CHANGED
|when());
58 // Create input widget that we'll use whenever user clicks on a cell
59 input
= new Fl_Int_Input(W
/2,H
/2,0,0);
61 input
->callback(input_cb
, (void*)this);
62 input
->when(FL_WHEN_ENTER_KEY_ALWAYS
); // callback triggered when user hits Enter
63 input
->maximum_size(5);
64 for (int c
= 0; c
< MAX_COLS
; c
++)
65 for (int r
= 0; r
< MAX_ROWS
; r
++)
66 values
[r
][c
] = c
+ (r
*MAX_COLS
); // initialize cells
71 // Apply value from input widget to values[row][col] array and hide (done editing)
72 void set_value_hide() {
73 values
[row_edit
][col_edit
] = atoi(input
->value());
75 window()->cursor(FL_CURSOR_DEFAULT
); // XXX: if we don't do this, cursor can disappear!
77 // Start editing a new cell: move the Fl_Int_Input widget to specified row/column
78 // Preload the widget with the cell's current value,
79 // and make the widget 'appear' at the cell's location.
81 void start_editing(int R
, int C
) {
82 row_edit
= R
; // Now editing this row/col
85 find_cell(CONTEXT_CELL
, R
,C
, X
,Y
,W
,H
); // Find X/Y/W/H of cell
86 input
->resize(X
,Y
,W
,H
); // Move Fl_Input widget there
87 char s
[30]; sprintf(s
, "%d", values
[R
][C
]); // Load input widget with cell's current value
89 input
->position(0,strlen(s
)); // Select entire input field
90 input
->show(); // Show the input widget, now that we've positioned it
93 // Tell the input widget it's done editing, and to 'hide'
95 if (input
->visible()) { // input widget visible, ie. edit in progress?
96 set_value_hide(); // Transfer its current contents to cell and hide
99 // Return the sum of all rows in this column
100 int sum_rows(int C
) {
102 for (int r
=0; r
<rows()-1; ++r
) // -1: don't include cell data in 'totals' column
106 // Return the sum of all cols in this row
107 int sum_cols(int R
) {
109 for (int c
=0; c
<cols()-1; ++c
) // -1: don't include cell data in 'totals' column
113 // Return the sum of all cells in table
116 for (int c
=0; c
<cols()-1; ++c
) // -1: don't include cell data in 'totals' column
117 for (int r
=0; r
<rows()-1; ++r
) // -1: ""
123 // Handle drawing all cells in table
124 void Spreadsheet::draw_cell(TableContext context
, int R
,int C
, int X
,int Y
,int W
,int H
) {
127 case CONTEXT_STARTPAGE
: // table about to redraw
130 case CONTEXT_COL_HEADER
: // table wants us to draw a column heading (C is column)
131 fl_font(FL_HELVETICA
| FL_BOLD
, 14); // set font for heading to bold
132 fl_push_clip(X
,Y
,W
,H
); // clip region for text
134 fl_draw_box(FL_THIN_UP_BOX
, X
,Y
,W
,H
, col_header_color());
136 if (C
== cols()-1) { // Last column? show 'TOTAL'
137 fl_draw("TOTAL", X
,Y
,W
,H
, FL_ALIGN_CENTER
);
138 } else { // Not last column? show column letter
139 sprintf(s
, "%c", 'A' + C
);
140 fl_draw(s
, X
,Y
,W
,H
, FL_ALIGN_CENTER
);
146 case CONTEXT_ROW_HEADER
: // table wants us to draw a row heading (R is row)
147 fl_font(FL_HELVETICA
| FL_BOLD
, 14); // set font for row heading to bold
148 fl_push_clip(X
,Y
,W
,H
);
150 fl_draw_box(FL_THIN_UP_BOX
, X
,Y
,W
,H
, row_header_color());
152 if (R
== rows()-1) { // Last row? Show 'Total'
153 fl_draw("TOTAL", X
,Y
,W
,H
, FL_ALIGN_CENTER
);
154 } else { // Not last row? show row#
155 sprintf(s
, "%d", R
+1);
156 fl_draw(s
, X
,Y
,W
,H
, FL_ALIGN_CENTER
);
162 case CONTEXT_CELL
: { // table wants us to draw a cell
163 if (R
== row_edit
&& C
== col_edit
&& input
->visible()) {
164 return; // dont draw for cell with input widget over it
167 if ( C
< cols()-1 && R
< rows()-1 ) {
168 fl_draw_box(FL_THIN_UP_BOX
, X
,Y
,W
,H
, FL_WHITE
);
170 fl_draw_box(FL_THIN_UP_BOX
, X
,Y
,W
,H
, 0xbbddbb00); // money green
173 fl_push_clip(X
+3, Y
+3, W
-6, H
-6);
176 if (C
== cols()-1 || R
== rows()-1) { // Last row or col? Show total
177 fl_font(FL_HELVETICA
| FL_BOLD
, 14); // ..in bold font
178 if (C
== cols()-1 && R
== rows()-1) { // Last row+col? Total all cells
179 sprintf(s
, "%d", sum_all());
180 } else if (C
== cols()-1) { // Row subtotal
181 sprintf(s
, "%d", sum_cols(R
));
182 } else if (R
== rows()-1) { // Col subtotal
183 sprintf(s
, "%d", sum_rows(C
));
185 fl_draw(s
, X
+3,Y
+3,W
-6,H
-6, FL_ALIGN_RIGHT
);
186 } else { // Not last row or col? Show cell contents
187 fl_font(FL_HELVETICA
, 14); // ..in regular font
188 sprintf(s
, "%d", values
[R
][C
]);
189 fl_draw(s
, X
+3,Y
+3,W
-6,H
-6, FL_ALIGN_RIGHT
);
201 // Callback whenever someone clicks on different parts of the table
202 void Spreadsheet::event_callback2() {
203 int R
= callback_row();
204 int C
= callback_col();
205 TableContext context
= callback_context();
208 case CONTEXT_CELL
: { // A table event occurred on a cell
209 switch (Fl::event()) { // see what FLTK event caused it
210 case FL_PUSH
: // mouse click?
211 done_editing(); // finish editing previous
212 if (R
!= rows()-1 && C
!= cols()-1 ) // only edit cells not in total's columns
213 start_editing(R
,C
); // start new edit
216 case FL_KEYBOARD
: // key press in table?
217 if ( Fl::event_key() == FL_Escape
) exit(0); // ESC closes app
218 if (C
== cols()-1 || R
== rows()-1) return; // no editing of totals column
219 done_editing(); // finish any previous editing
220 start_editing(R
,C
); // start new edit
221 if (Fl::event() == FL_KEYBOARD
&& Fl::e_text
[0] != '\r') {
222 input
->handle(Fl::event()); // pass keypress to input widget
229 case CONTEXT_TABLE
: // A table event occurred on dead zone in table
230 case CONTEXT_ROW_HEADER
: // A table event occurred on row/column header
231 case CONTEXT_COL_HEADER
:
232 done_editing(); // done editing, hide
241 Fl_Double_Window
*win
= new Fl_Double_Window(862, 322, "Fl_Table Spreadsheet");
242 Spreadsheet
*table
= new Spreadsheet(10, 10, win
->w()-20, win
->h()-20);
244 table
->row_header(1);
245 table
->row_header_width(70);
246 table
->row_resize(1);
247 table
->rows(MAX_ROWS
+1); // +1: leaves room for 'total row'
248 table
->row_height_all(25);
250 table
->col_header(1);
251 table
->col_header_height(25);
252 table
->col_resize(1);
253 table
->cols(MAX_COLS
+1); // +1: leaves room for 'total column'
254 table
->col_width_all(70);
257 win
->resizable(table
);
263 // End of "$Id: table-spreadsheet.cxx 8183 2011-01-04 17:31:56Z AlbrechtS $".