1 //
2 // "$Id: Fl_Tile.cxx 5606 2007-01-18 10:01:24Z matt $"
3 //
4 // Tile widget for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2005 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 // USA.
22 //
23 // Please report all bugs and problems on the following page:
24 //
25 // http://www.fltk.org/str.php
26 //
27
28 // Group of 2 or 4 "tiles" that can be resized by dragging border
29 // The size of the first child determines where the resize border is.
30 // The resizebox is used to limit where the border can be dragged to.
31
32 #include <FL/Fl.H>
33 #include <FL/Fl_Tile.H>
34 #include <FL/Fl_Window.H>
35 #include <stdlib.h>
36
37 // Drag the edges that were initially at oldx,oldy to newx,newy:
38 // pass zero as oldx or oldy to disable drag in that direction:
39
position(int oix,int oiy,int newx,int newy)40 void Fl_Tile::position(int oix, int oiy, int newx, int newy) {
41 Fl_Widget*const* a = array();
42 short* p = sizes();
43 p += 8; // skip group & resizable's saved size
44 for (int i=children(); i--; p += 4) {
45 Fl_Widget* o = *a++;
46 if (o == resizable()) continue;
47 int X = o->x();
48 int R = X+o->w();
49 if (oix) {
50 int t = p[0];
51 if (t == oix || t>oix && X<newx || t<oix && X>newx) X = newx;
52 t = p[1];
53 if (t == oix || t>oix && R<newx || t<oix && R>newx) R = newx;
54 }
55 int Y = o->y();
56 int B = Y+o->h();
57 if (oiy) {
58 int t = p[2];
59 if (t == oiy || t>oiy && Y<newy || t<oiy && Y>newy) Y = newy;
60 t = p[3];
61 if (t == oiy || t>oiy && B<newy || t<oiy && B>newy) B = newy;
62 }
63 o->damage_resize(X,Y,R-X,B-Y);
64 }
65 }
66
67 // move the lower-right corner (sort of):
resize(int X,int Y,int W,int H)68 void Fl_Tile::resize(int X,int Y,int W,int H) {
69 //Fl_Group::resize(X, Y, W, H);
70 //return;
71 // remember how much to move the child widgets:
72 int dx = X-x();
73 int dy = Y-y();
74 int dw = W-w();
75 int dh = H-h();
76 short* p = sizes();
77 // resize this (skip the Fl_Group resize):
78 Fl_Widget::resize(X,Y,W,H);
79 // find bottom-right of resiable:
80 int OR = p[5];
81 int NR = X+W-(p[1]-OR);
82 int OB = p[7];
83 int NB = Y+H-(p[3]-OB);
84 // move everything to be on correct side of new resizable:
85 Fl_Widget*const* a = array();
86 p += 8;
87 for (int i=children(); i--;) {
88 Fl_Widget* o = *a++;
89 int xx = o->x()+dx;
90 int R = xx+o->w();
91 if (*p++ >= OR) xx += dw; else if (xx > NR) xx = NR;
92 if (*p++ >= OR) R += dw; else if (R > NR) R = NR;
93 int yy = o->y()+dy;
94 int B = yy+o->h();
95 if (*p++ >= OB) yy += dh; else if (yy > NB) yy = NB;
96 if (*p++ >= OB) B += dh; else if (B > NB) B = NB;
97 o->resize(xx,yy,R-xx,B-yy);
98 // do *not* call o->redraw() here! If you do, and the tile is inside a
99 // scroll, it'll set the damage areas wrong for all children!
100 }
101 }
102
set_cursor(Fl_Tile * t,Fl_Cursor c)103 static void set_cursor(Fl_Tile*t, Fl_Cursor c) {
104 static Fl_Cursor cursor;
105 if (cursor == c || !t->window()) return;
106 cursor = c;
107 #ifdef __sgi
108 t->window()->cursor(c,FL_RED,FL_WHITE);
109 #else
110 t->window()->cursor(c);
111 #endif
112 }
113
114 static Fl_Cursor cursors[4] = {
115 FL_CURSOR_DEFAULT,
116 FL_CURSOR_WE,
117 FL_CURSOR_NS,
118 FL_CURSOR_MOVE};
119
handle(int event)120 int Fl_Tile::handle(int event) {
121 static int sdrag;
122 static int sdx, sdy;
123 static int sx, sy;
124 #define DRAGH 1
125 #define DRAGV 2
126 #define GRABAREA 4
127
128 int mx = Fl::event_x();
129 int my = Fl::event_y();
130
131 switch (event) {
132
133 case FL_MOVE:
134 case FL_ENTER:
135 case FL_PUSH: {
136 int mindx = 100;
137 int mindy = 100;
138 int oldx = 0;
139 int oldy = 0;
140 Fl_Widget*const* a = array();
141 short* q = sizes();
142 short* p = q+8;
143 for (int i=children(); i--; p += 4) {
144 Fl_Widget* o = *a++;
145 if (o == resizable()) continue;
146 if (p[1]<q[1] && o->y()<=my+GRABAREA && o->y()+o->h()>=my-GRABAREA) {
147 int t = mx - (o->x()+o->w());
148 if (abs(t) < mindx) {
149 sdx = t;
150 mindx = abs(t);
151 oldx = p[1];
152 }
153 }
154 if (p[3]<q[3] && o->x()<=mx+GRABAREA && o->x()+o->w()>=mx-GRABAREA) {
155 int t = my - (o->y()+o->h());
156 if (abs(t) < mindy) {
157 sdy = t;
158 mindy = abs(t);
159 oldy = p[3];
160 }
161 }
162 }
163 sdrag = 0; sx = sy = 0;
164 if (mindx <= GRABAREA) {sdrag = DRAGH; sx = oldx;}
165 if (mindy <= GRABAREA) {sdrag |= DRAGV; sy = oldy;}
166 set_cursor(this, cursors[sdrag]);
167 if (sdrag) return 1;
168 return Fl_Group::handle(event);
169 }
170
171 case FL_LEAVE:
172 set_cursor(this, FL_CURSOR_DEFAULT);
173 break;
174
175 case FL_DRAG:
176 // This is necessary if CONSOLIDATE_MOTION in Fl_x.cxx is turned off:
177 // if (damage()) return 1; // don't fall behind
178 case FL_RELEASE: {
179 if (!sdrag) return 0; // should not happen
180 Fl_Widget* r = resizable(); if (!r) r = this;
181 int newx;
182 if (sdrag&DRAGH) {
183 newx = Fl::event_x()-sdx;
184 if (newx < r->x()) newx = r->x();
185 else if (newx > r->x()+r->w()) newx = r->x()+r->w();
186 } else
187 newx = sx;
188 int newy;
189 if (sdrag&DRAGV) {
190 newy = Fl::event_y()-sdy;
191 if (newy < r->y()) newy = r->y();
192 else if (newy > r->y()+r->h()) newy = r->y()+r->h();
193 } else
194 newy = sy;
195 position(sx,sy,newx,newy);
196 if (event == FL_DRAG) set_changed();
197 do_callback();
198 return 1;}
199
200 }
201
202 return Fl_Group::handle(event);
203 }
204
205 //
206 // End of "$Id: Fl_Tile.cxx 5606 2007-01-18 10:01:24Z matt $".
207 //
208