1 //
2 // flruler -- draw an onscreen ruler for GUI design measurements
3 //
4 // Version 1.05
5 // Copyright (C) 2006 Greg Ercolano
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of
10 // the License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 // 02111-1307 USA
21 //
22 // Please report bugs to erco@seriss.com -- you /must/ include
23 // the words 'flruler bug report' in the Subject: of your message.
24 //
25
26 #include <FL/Fl.H>
27 #include <FL/Fl_Double_Window.H>
28 #include <FL/fl_draw.H>
29 #include <stdlib.h> // exit
30 #include <stdio.h> // sprintf
31
32 #if !defined(__APPLE__) && !defined(_WIN32)
33 #include <unistd.h> // fork
34 #endif
35
36 #include "flruler.H"
37
38 #ifdef __APPLE__
39 // OSX
40 #define XSIZE 100 // XXX: 100px min window size OSX w/fltk 1.1.7
41 #define YSIZE 53
42 #define FONTSIZE 9 // 8 too small on osx
43 #else
44 // NON-OSX
45 #define XSIZE 67
46 #define YSIZE 53
47 #define FONTSIZE 8 // nice on linux
48 #endif
49
50 // Ruler widget
51 class RulerWindow : public Fl_Double_Window {
52 int horizontal, reverse;
53 int xsize, ysize;
54 // DRAW A LINE AT X/Y
55 // Obeys 'reverse'
56 //
Line(int X1,int Y1,int X2,int Y2)57 void Line(int X1,int Y1,int X2,int Y2) {
58 if ( reverse ) {
59 X1 = w() - X1 - 1;
60 X2 = w() - X2 - 1;
61 Y1 = h() - Y1 - 1;
62 Y2 = h() - Y2 - 1;
63 }
64 fl_line(X1,Y1,X2,Y2);
65 }
66 // DRAW TEXT CENTERED AT X/Y
67 // Obeys 'reverse'
68 //
TextCenter(const char * s,int X,int Y)69 void TextCenter(const char *s,int X,int Y) {
70 if ( reverse && horizontal ) {
71 X = w()-X-1;
72 } else if ( reverse && ! horizontal ) {
73 Y = h()-Y-1;
74 }
75 // CENTER TEXT
76 X = X - ((int)fl_width(s) / 2);
77 Y = Y + ((int)fl_height() / 2) - 1;
78 fl_draw(s,X,Y);
79 }
80 // FLTK: DRAW THE SCREEN
draw()81 void draw() {
82 int RIGHT = w()-1;
83 int BOTTOM = h()-1;
84 char s[80];
85 fl_color(133); // ORANGE, 132, 92
86 fl_rectf(0,0,w(),h());
87 fl_color(FL_BLACK);
88 fl_font(FL_HELVETICA, FONTSIZE);
89 if ( horizontal ) {
90 // Draw horizontal ruler markings
91 for ( int X=0; X<=w(); X+=2 ) {
92 if ( X % 10 == 0 ) {
93 if ( X % 50 == 0 ) {
94 Line(X,0,X,20);
95 Line(X,BOTTOM-20,X,BOTTOM);
96 } else {
97 Line(X,0,X,10);
98 Line(X,BOTTOM-10,X,BOTTOM);
99 sprintf(s,"%d",(X % 100) / 10);
100 TextCenter(s,X,15);
101 TextCenter(s,X,BOTTOM-15-1);
102 }
103 } else {
104 Line(X,0,X,5);
105 Line(X,BOTTOM-5,X,BOTTOM);
106 }
107 if ( X % 50 == 0 ) {
108 sprintf(s,"%d",X);
109 TextCenter(s,X,BOTTOM/2);
110 }
111 }
112 } else {
113 // Draw vertical ruler markings
114 for ( int Y=0; Y<=h(); Y+=2 ) {
115 if ( Y % 10 == 0 ) {
116 if ( Y % 50 == 0 ) {
117 Line(0,Y,20,Y);
118 Line(RIGHT-20,Y,RIGHT,Y);
119 } else {
120 Line(0,Y,10,Y);
121 Line(RIGHT-10,Y,BOTTOM,Y);
122 sprintf(s,"%d",(Y % 100) / 10);
123 TextCenter(s,15,Y);
124 TextCenter(s,RIGHT-15-1,Y);
125 }
126 } else {
127 Line(0,Y,5,Y);
128 Line(RIGHT-5,Y,RIGHT,Y);
129 }
130 if ( Y % 50 == 0 ) {
131 sprintf(s,"%d",Y);
132 TextCenter(s,RIGHT/2,Y);
133 }
134 }
135 }
136 }
137 // FLTK: EVENT HANDLER
138 int handle(int e);
139
140 public:
141 // CHANGE HORIZONTAL ORIENTATION
142 // val: 1=horiz, 0=vertical
143 // rx: recommended x position for new orientation
144 // ry: recommended y position for new orientation
145 //
146 void Horizontal(int val, int rx=-1, int ry=-1) {
147 horizontal = val;
148 if ( horizontal ) {
149 if ( rx == -1 ) rx = 0;
150 if ( ry == -1 ) ry = Fl::event_y_root();
151 resize(rx, ry, xsize, YSIZE);
152 } else {
153 if ( rx == -1 ) rx = Fl::event_x_root();
154 if ( ry == -1 ) ry = 0;
155 resize(rx, ry, XSIZE, ysize);
156 }
157 redraw();
158 }
159 // CHANGE FORWARD/REVERSE ORIENTATION
Reverse(int val)160 void Reverse(int val) {
161 reverse = val;
162 redraw();
163 }
164 // CTOR
RulerWindow(int W,int H,int hval,int rval)165 RulerWindow(int W,int H,int hval,int rval):Fl_Double_Window(W,H,0) {
166 end();
167 resizable(this);
168 border(0);
169 show();
170 xsize = Fl::w();
171 ysize = Fl::h();
172 Horizontal(hval);
173 Reverse(rval);
174 }
175 // CTOR
RulerWindow(int X,int Y,int W,int H,int hval,int rval)176 RulerWindow(int X,int Y,int W,int H,int hval, int rval):Fl_Double_Window(X,Y,W,H,0) {
177 end();
178 resizable(this);
179 border(0);
180 show();
181 xsize = Fl::w();
182 ysize = Fl::h();
183 Horizontal(hval);
184 Reverse(rval);
185 }
186 };
187
188 // FLTK: EVENT HANDLER
handle(int e)189 int RulerWindow::handle(int e) {
190 static int xoff = 0, yoff = 0, drag = 0;
191 int ret = Fl_Double_Window::handle(e);
192 switch ( e ) {
193 case FL_KEYBOARD:
194 case FL_PUSH:
195 drag = 0;
196 switch ( Fl::event_key() ) {
197 // PREPARE FOR WINDOW DRAG
198 case FL_Button+FL_LEFT_MOUSE:
199 switch ( Fl::event_clicks() ) {
200 case 1: // invert dir
201 case 3:
202 Reverse(reverse ^ 1);
203 break;
204 case 2: // invert horiz/vert
205 Horizontal(horizontal ^ 1);
206 Reverse(0);
207 break;
208 case 4:
209 Horizontal(horizontal ^ 1);
210 Reverse(1);
211 break;
212 }
213 xoff = x() - Fl::event_x_root();
214 yoff = y() - Fl::event_y_root();
215 drag = 1;
216 break;
217
218 // COPY RULER
219 case FL_Button+FL_MIDDLE_MOUSE:
220 case 'c':
221 case 'C':
222 new RulerWindow(Fl::event_x_root(),Fl::event_y_root(),1,1,horizontal,reverse);
223 return(1);
224 // PUT ZERO AT LEFT
225 case FL_Left:
226 Horizontal(1);
227 Reverse(0);
228 return(1);
229 // PUT ZERO AT RIGHT
230 case FL_Right:
231 Horizontal(1);
232 Reverse(1);
233 return(1);
234 // PUT ZERO AT TOP
235 case FL_Up:
236 Horizontal(0);
237 Reverse(0);
238 return(1);
239 // PUT ZERO AT BOTTOM
240 case FL_Down:
241 Horizontal(0);
242 Reverse(1);
243 return(1);
244 // RESIZE ruler window
245 case '-': // shrink
246 case 65453: // numeric keypad's '-' key
247 if (horizontal) {
248 xsize = xsize * 9 / 10;
249 if (xsize < 150) xsize = 150;
250 size(xsize,YSIZE);
251 } else {
252 ysize = ysize * 9 / 10;
253 if (ysize < 150) ysize = 150;
254 size(XSIZE,ysize);
255 }
256 return(1);
257 case '+': // enlarge
258 case '=':
259 case 65451: // numeric keypad's '+' key
260 if (horizontal) {
261 xsize = xsize * 10 / 9;
262 if (xsize > Fl::w()) xsize = Fl::w();
263 size(xsize,YSIZE);
264 } else {
265 ysize = ysize * 10 / 9;
266 if (ysize > Fl::h()) ysize = Fl::h();
267 size(XSIZE,ysize);
268 }
269 return(1);
270 // QUIT
271 case FL_Escape: // fltk close window
272 case FL_CTRL+'x': // cut
273 case FL_CTRL+'w': // close window
274 hide();
275 return(1);
276 // QUIT APPLICATION
277 case 'q':
278 case FL_CTRL+'q':
279 case FL_ALT+'q':
280 exit(1);
281 }
282 ret = 1;
283 break;
284 case FL_DRAG:
285 if ( drag ) {
286 // LET USER DRAG WINDOW AROUND THE SCREEN
287 position(xoff + Fl::event_x_root(), yoff + Fl::event_y_root());
288 redraw();
289 }
290 ret = 1;
291 break;
292 case FL_RELEASE:
293 ret = 1;
294 drag = 0;
295 break;
296 }
297 return(ret);
298 }
299
300 // FORK APP OFF AS CHILD PROCESS
301 // Doesn't work in OSX or WIN32
Fork()302 void Fork() {
303 #if !defined(__APPLE__) && !defined(_WIN32)
304 if ( fork() > 0 ) exit(0);
305 #endif
306 }
307
308 /// MAIN
main(int argc,char * argv[])309 int main(int argc, char *argv[]) {
310 for ( int t=1; t<argc; t++ ) {
311 if ( argv[t][0] == '-' ) {
312 switch ( argv[t][1] ) {
313 case 'h':
314 fprintf(stderr, "%s", G_help);
315 exit(1);
316 }
317 }
318 }
319 Fork();
320 int w = Fl::w();
321 int h = YSIZE;
322 RulerWindow win(w,h,1,0);
323 return(Fl::run());
324 }
325