1 //
2 // "$Id: Fl_Tile.cxx 7903 2010-11-28 21:06:39Z matt $"
3 //
4 // Tile widget for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
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 
29 // Group of 2 or 4 "tiles" that can be resized by dragging border
30 // The size of the first child determines where the resize border is.
31 // The resizebox is used to limit where the border can be dragged to.
32 
33 #include <FL/Fl.H>
34 #include <FL/Fl_Tile.H>
35 #include <FL/Fl_Window.H>
36 #include <stdlib.h>
37 
38 // Drag the edges that were initially at oldx,oldy to newx,newy:
39 // pass zero as oldx or oldy to disable drag in that direction:
40 /**
41   Drag the intersection at from_x,from_y to to_x,to_y.
42   This redraws all the necessary children.
43 */
position(int oix,int oiy,int newx,int newy)44 void Fl_Tile::position(int oix, int oiy, int newx, int newy) {
45   Fl_Widget*const* a = array();
46   int *p = sizes();
47   p += 8; // skip group & resizable's saved size
48   for (int i=children(); i--; p += 4) {
49     Fl_Widget* o = *a++;
50     if (o == resizable()) continue;
51     int X = o->x();
52     int R = X+o->w();
53     if (oix) {
54       int t = p[0];
55       if (t == oix || (t>oix && X<newx) || (t<oix && X>newx) ) X = newx;
56       t = p[1];
57       if (t == oix || (t>oix && R<newx) || (t<oix && R>newx) ) R = newx;
58     }
59     int Y = o->y();
60     int B = Y+o->h();
61     if (oiy) {
62       int t = p[2];
63       if (t == oiy || (t>oiy && Y<newy) || (t<oiy && Y>newy) ) Y = newy;
64       t = p[3];
65       if (t == oiy || (t>oiy && B<newy) || (t<oiy && B>newy) ) B = newy;
66     }
67     o->damage_resize(X,Y,R-X,B-Y);
68   }
69 }
70 
71 // move the lower-right corner (sort of):
resize(int X,int Y,int W,int H)72 void Fl_Tile::resize(int X,int Y,int W,int H) {
73   //Fl_Group::resize(X, Y, W, H);
74   //return;
75   // remember how much to move the child widgets:
76   int dx = X-x();
77   int dy = Y-y();
78   int dw = W-w();
79   int dh = H-h();
80   int *p = sizes();
81   // resize this (skip the Fl_Group resize):
82   Fl_Widget::resize(X,Y,W,H);
83   // find bottom-right of resiable:
84   int OR = p[5];
85   int NR = X+W-(p[1]-OR);
86   int OB = p[7];
87   int NB = Y+H-(p[3]-OB);
88   // move everything to be on correct side of new resizable:
89   Fl_Widget*const* a = array();
90   p += 8;
91   for (int i=children(); i--;) {
92     Fl_Widget* o = *a++;
93     int xx = o->x()+dx;
94     int R = xx+o->w();
95     if (*p++ >= OR) xx += dw; else if (xx > NR) xx = NR;
96     if (*p++ >= OR) R += dw; else if (R > NR) R = NR;
97     int yy = o->y()+dy;
98     int B = yy+o->h();
99     if (*p++ >= OB) yy += dh; else if (yy > NB) yy = NB;
100     if (*p++ >= OB) B += dh; else if (B > NB) B = NB;
101     o->resize(xx,yy,R-xx,B-yy);
102     // do *not* call o->redraw() here! If you do, and the tile is inside a
103     // scroll, it'll set the damage areas wrong for all children!
104   }
105 }
106 
set_cursor(Fl_Tile * t,Fl_Cursor c)107 static void set_cursor(Fl_Tile*t, Fl_Cursor c) {
108   static Fl_Cursor cursor;
109   if (cursor == c || !t->window()) return;
110   cursor = c;
111 #ifdef __sgi
112   t->window()->cursor(c,FL_RED,FL_WHITE);
113 #else
114   t->window()->cursor(c);
115 #endif
116 }
117 
118 static Fl_Cursor cursors[4] = {
119   FL_CURSOR_DEFAULT,
120   FL_CURSOR_WE,
121   FL_CURSOR_NS,
122   FL_CURSOR_MOVE};
123 
handle(int event)124 int Fl_Tile::handle(int event) {
125   static int sdrag;
126   static int sdx, sdy;
127   static int sx, sy;
128 #define DRAGH 1
129 #define DRAGV 2
130 #define GRABAREA 4
131 
132   int mx = Fl::event_x();
133   int my = Fl::event_y();
134 
135   switch (event) {
136 
137   case FL_MOVE:
138   case FL_ENTER:
139   case FL_PUSH:
140     // don't potentially change the mouse cursor if inactive:
141     if (!active()) break; // will cascade inherited handle()
142     {
143     int mindx = 100;
144     int mindy = 100;
145     int oldx = 0;
146     int oldy = 0;
147     Fl_Widget*const* a = array();
148     int *q = sizes();
149     int *p = q+8;
150     for (int i=children(); i--; p += 4) {
151       Fl_Widget* o = *a++;
152       if (o == resizable()) continue;
153       if (p[1]<q[1] && o->y()<=my+GRABAREA && o->y()+o->h()>=my-GRABAREA) {
154 	int t = mx - (o->x()+o->w());
155 	if (abs(t) < mindx) {
156 	  sdx = t;
157 	  mindx = abs(t);
158 	  oldx = p[1];
159 	}
160       }
161       if (p[3]<q[3] && o->x()<=mx+GRABAREA && o->x()+o->w()>=mx-GRABAREA) {
162 	int t = my - (o->y()+o->h());
163 	if (abs(t) < mindy) {
164 	  sdy = t;
165 	  mindy = abs(t);
166 	  oldy = p[3];
167 	}
168       }
169     }
170     sdrag = 0; sx = sy = 0;
171     if (mindx <= GRABAREA) {sdrag = DRAGH; sx = oldx;}
172     if (mindy <= GRABAREA) {sdrag |= DRAGV; sy = oldy;}
173     set_cursor(this, cursors[sdrag]);
174     if (sdrag) return 1;
175     return Fl_Group::handle(event);
176   }
177 
178   case FL_LEAVE:
179     set_cursor(this, FL_CURSOR_DEFAULT);
180     break;
181 
182   case FL_DRAG:
183     // This is necessary if CONSOLIDATE_MOTION in Fl_x.cxx is turned off:
184     // if (damage()) return 1; // don't fall behind
185   case FL_RELEASE: {
186     if (!sdrag) return 0; // should not happen
187     Fl_Widget* r = resizable(); if (!r) r = this;
188     int newx;
189     if (sdrag&DRAGH) {
190       newx = Fl::event_x()-sdx;
191       if (newx < r->x()) newx = r->x();
192       else if (newx > r->x()+r->w()) newx = r->x()+r->w();
193     } else
194       newx = sx;
195     int newy;
196     if (sdrag&DRAGV) {
197       newy = Fl::event_y()-sdy;
198       if (newy < r->y()) newy = r->y();
199       else if (newy > r->y()+r->h()) newy = r->y()+r->h();
200     } else
201       newy = sy;
202     position(sx,sy,newx,newy);
203     if (event == FL_DRAG) set_changed();
204     do_callback();
205     return 1;}
206 
207   }
208 
209   return Fl_Group::handle(event);
210 }
211 
212 //
213 // End of "$Id: Fl_Tile.cxx 7903 2010-11-28 21:06:39Z matt $".
214 //
215