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