Scale.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  1. /*
  2. Copyright 1989, 1998 The Open Group
  3. Permission to use, copy, modify, distribute, and sell this software and its
  4. documentation for any purpose is hereby granted without fee, provided that
  5. the above copyright notice appear in all copies and that both that
  6. copyright notice and this permission notice appear in supporting
  7. documentation.
  8. The above copyright notice and this permission notice shall be included
  9. in all copies or substantial portions of the Software.
  10. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  11. OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  12. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  13. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
  14. OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  15. ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  16. OTHER DEALINGS IN THE SOFTWARE.
  17. Except as contained in this notice, the name of The Open Group shall
  18. not be used in advertising or otherwise to promote the sale, use or
  19. other dealings in this Software without prior written authorization
  20. from The Open Group.
  21. */
  22. /*
  23. * Author: Davor Matic, MIT X Consortium
  24. */
  25. #include "config.h"
  26. #include <stdio.h>
  27. #include <ctype.h>
  28. #include <math.h>
  29. #include <stdlib.h>
  30. #include <X11/IntrinsicP.h>
  31. #include <X11/StringDefs.h>
  32. #include <X11/Xos.h>
  33. #include <X11/Xaw/XawInit.h>
  34. #include "CutPaste.h"
  35. #include "ScaleP.h"
  36. #ifdef HAVE_LRINT
  37. #define myrint(x) lrint(x)
  38. #else
  39. #define myrint(x) floor(x + 0.5)
  40. #endif
  41. #define streq(a,b) (strcmp( (a), (b) ) == 0)
  42. #ifndef min
  43. #define min(x, y) ((x) > (y) ? (y) : (x))
  44. #endif
  45. #ifndef max
  46. #define max(x, y) ((x) < (y) ? (y) : (x))
  47. #endif
  48. #define DefaultBufferSize 1024
  49. #define DefaultScaleFactor NULL
  50. #define Offset(field) XtOffsetOf(ScaleRec, scale.field)
  51. static XtResource resources[] = {
  52. {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  53. Offset(foreground_pixel), XtRString, (XtPointer) XtDefaultForeground},
  54. {XtNgravity, XtCGravity, XtRGravity, sizeof(XtGravity),
  55. Offset(gravity), XtRImmediate, (XtPointer) "ForgetGravity"},
  56. {XtNinternalWidth, XtCWidth, XtRDimension, sizeof(Dimension),
  57. Offset(internal_width), XtRImmediate, (XtPointer) 2},
  58. {XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension),
  59. Offset(internal_height), XtRImmediate, (XtPointer) 2},
  60. {XtNresize, XtCResize, XtRBoolean, sizeof(Boolean),
  61. Offset(resize), XtRImmediate, (XtPointer) True},
  62. {XtNautoscale, XtCAutoscale, XtRBoolean, sizeof(Boolean),
  63. Offset(autoscale), XtRImmediate, (XtPointer) True},
  64. {XtNproportional, XtCProportional, XtRBoolean, sizeof(Boolean),
  65. Offset(proportional), XtRImmediate, (XtPointer) True},
  66. {XtNscaleX, XtCScaleFactor, XtRString, sizeof(String),
  67. Offset(scale_x_str), XtRImmediate, (XtPointer) DefaultScaleFactor},
  68. {XtNscaleY, XtCScaleFactor, XtRString, sizeof(String),
  69. Offset(scale_y_str), XtRImmediate, (XtPointer) DefaultScaleFactor},
  70. {XtNaspectRatio, XtCAspectRatio, XtRString, sizeof(String),
  71. Offset(aspect_ratio_str), XtRImmediate, (XtPointer) "1.0"},
  72. {XtNprecision, XtCPrecision, XtRString, sizeof(String),
  73. Offset(precision_str), XtRImmediate, (XtPointer) "0.001"},
  74. {XtNimage, XtCImage, XtRImage, sizeof(XImage*),
  75. Offset(image), XtRImmediate, (XtPointer) NULL},
  76. {XtNpasteBuffer, XtCPasteBuffer, XtRBoolean, sizeof(Boolean),
  77. Offset(paste_buffer), XtRImmediate, (XtPointer) False},
  78. {XtNbufferSize, XtCBufferSize, XtRCardinal, sizeof(Cardinal),
  79. Offset(buffer_size), XtRImmediate, (XtPointer) DefaultBufferSize},
  80. {XtNuserData, XtCuserData, XtRuserData, sizeof(XtPointer),
  81. Offset(userData), XtRImmediate, (XtPointer) NULL},
  82. { XtNvisual, XtCvisual, XtRVisual, sizeof(Visual*),
  83. Offset(visual), XtRImmediate, CopyFromParent}
  84. };
  85. #undef Offset
  86. static void ClassInitialize ( void );
  87. static void GetGC ( ScaleWidget sw );
  88. static void GetInitialScaleValues ( ScaleWidget sw );
  89. static void GetRectangleBuffer ( ScaleWidget sw, Cardinal buffer_size );
  90. static void Initialize ( Widget request, Widget new, ArgList args,
  91. Cardinal *num_args );
  92. static void BuildTable ( ScaleWidget sw );
  93. static void FlushRectangles ( ScaleWidget sw, Drawable drawable, GC gc );
  94. static void FillRectangle ( ScaleWidget sw, Drawable drawable, GC gc,
  95. Position x, Position y,
  96. Dimension width, Dimension height );
  97. static void ScaleImage ( ScaleWidget sw, Drawable drawable,
  98. Position img_x, Position img_y,
  99. Position dst_x, Position dst_y,
  100. Dimension img_width, Dimension img_height );
  101. static int FindPixel ( ScaleWidget sw, Position x, Position y,
  102. Position *img_x, Position *img_y, Pixel *img_pixel );
  103. static void Redisplay ( Widget w, XEvent *event, Region region );
  104. static void TryResize ( ScaleWidget sw );
  105. static void Precision ( ScaleWidget sw );
  106. static void Proportional ( ScaleWidget sw );
  107. static void GetScaledSize ( ScaleWidget sw );
  108. static void GetScaleValues ( ScaleWidget sw );
  109. static void Unscale ( ScaleWidget sw );
  110. static void Autoscale ( ScaleWidget sw );
  111. static void PositionImage ( ScaleWidget sw );
  112. static void Resize ( Widget w );
  113. static void Realize ( Widget wid, Mask *vmask, XSetWindowAttributes *attr );
  114. static void Destroy ( Widget w );
  115. static Boolean SetValues ( Widget current, Widget request, Widget new,
  116. ArgList args, Cardinal *num_args );
  117. static XtActionsRec actions[] =
  118. {
  119. {"unscale", SWUnscale},
  120. {"autoscale", SWAutoscale},
  121. {"initial-size", SWInitialSize},
  122. {"paste", RequestSelection},
  123. {"cut", GrabSelection}
  124. };
  125. static char translations[] =
  126. "\
  127. <Key>u: unscale()\n\
  128. <Key>a: autoscale()\n\
  129. <Key>i: initial-size()\n\
  130. ";
  131. ScaleClassRec scaleClassRec = {
  132. { /* core fields */
  133. /* superclass */ (WidgetClass) &simpleClassRec,
  134. /* class_name */ "Scale",
  135. /* widget_size */ sizeof(ScaleRec),
  136. /* class_initialize */ ClassInitialize,
  137. /* class_part_initialize */ NULL,
  138. /* class_inited */ FALSE,
  139. /* initialize */ Initialize,
  140. /* initialize_hook */ NULL,
  141. /* realize */ Realize,
  142. /* actions */ actions,
  143. /* num_actions */ XtNumber(actions),
  144. /* resources */ resources,
  145. /* num_resources */ XtNumber(resources),
  146. /* xrm_class */ NULLQUARK,
  147. /* compress_motion */ TRUE,
  148. /* compress_exposure */ XtExposeCompressMaximal|
  149. XtExposeGraphicsExposeMerged,
  150. /* compress_enterleave */ TRUE,
  151. /* visible_interest */ TRUE,
  152. /* destroy */ Destroy,
  153. /* resize */ Resize,
  154. /* expose */ Redisplay,
  155. /* set_values */ SetValues,
  156. /* set_values_hook */ NULL,
  157. /* set_values_almost */ XtInheritSetValuesAlmost,
  158. /* get_values_hook */ NULL,
  159. /* accept_focus */ NULL,
  160. /* version */ XtVersion,
  161. /* callback_private */ NULL,
  162. /* tm_table */ translations,
  163. /* query_geometry */ XtInheritQueryGeometry,
  164. /* display_accelerator */ XtInheritDisplayAccelerator,
  165. /* extension */ NULL
  166. },
  167. {
  168. /* change_sensitive */ XtInheritChangeSensitive,
  169. }
  170. };
  171. WidgetClass scaleWidgetClass = (WidgetClass) &scaleClassRec;
  172. /*
  173. * Private Procedures
  174. */
  175. static void
  176. ClassInitialize(void)
  177. {
  178. }
  179. static void
  180. GetGC(ScaleWidget sw)
  181. {
  182. XGCValues values;
  183. values.foreground = sw->scale.foreground_pixel;
  184. values.background = sw->core.background_pixel;
  185. values.function = GXcopy;
  186. sw->scale.gc = XtGetGC((Widget) sw,
  187. GCForeground |
  188. GCBackground |
  189. GCFunction,
  190. &values);
  191. }
  192. static void
  193. GetInitialScaleValues(ScaleWidget sw)
  194. {
  195. if (sw->scale.proportional) {
  196. sw->scale.scale_x = sw->scale.scale_y =
  197. ((sw->scale.aspect_ratio > 1.0) ?
  198. sw->scale.aspect_ratio : 1.0 / sw->scale.aspect_ratio) *
  199. (sw->scale.precision > 1.0 ?
  200. sw->scale.precision : 1.0);
  201. Proportional(sw); /* need to cut them down to proper values */
  202. }
  203. else
  204. sw->scale.scale_x = sw->scale.scale_y = 1.0;
  205. }
  206. static void
  207. GetRectangleBuffer(ScaleWidget sw, Cardinal buffer_size)
  208. /*
  209. * This procedure will realloc a new rectangles buffer.
  210. * If the new buffer size is less than nrectangles, some
  211. * information will be lost.
  212. */
  213. {
  214. if (buffer_size == 0) {
  215. buffer_size = DefaultBufferSize;
  216. XtWarning("buffer size has to be a positive number greater than zero");
  217. }
  218. sw->scale.rectangles = (XRectangle *)
  219. XtRealloc((char *) sw->scale.rectangles,
  220. buffer_size * sizeof(XRectangle));
  221. sw->scale.buffer_size = buffer_size;
  222. }
  223. /* ARGSUSED */
  224. static void
  225. Initialize(Widget request, Widget new, ArgList args, Cardinal *num_args)
  226. {
  227. ScaleWidget new_sw = (ScaleWidget) new;
  228. new_sw->scale.table.x = (Position *) NULL;
  229. new_sw->scale.table.y = (Position *) NULL;
  230. new_sw->scale.table.width = (Dimension *) NULL;
  231. new_sw->scale.table.height = (Dimension *) NULL;
  232. new_sw->scale.nrectangles = 0;
  233. new_sw->scale.rectangles = (XRectangle *) NULL;
  234. GetRectangleBuffer(new_sw, new_sw->scale.buffer_size);
  235. GetGC(new_sw);
  236. if (new_sw->scale.image != NULL) {
  237. if (new_sw->core.width == 0)
  238. new_sw->core.width =
  239. new_sw->scale.image->width + 2 * new_sw->scale.internal_width;
  240. if (new_sw->core.height == 0)
  241. new_sw->core.height =
  242. new_sw->scale.image->height + 2 *new_sw->scale.internal_height;
  243. }
  244. else {
  245. if (new_sw->core.width == 0)
  246. new_sw->core.width = 1 + 2 * new_sw->scale.internal_width;
  247. if (new_sw->core.height == 0)
  248. new_sw->core.height = 1 + 2 * new_sw->scale.internal_height;
  249. new_sw->scale.image = XCreateImage(XtDisplay(new),
  250. DefaultVisual(XtDisplay(new),
  251. DefaultScreen(XtDisplay(new))),
  252. 1, XYBitmap, 0,
  253. XtCalloc(1, sizeof(char)),
  254. 1, 1, 8, 0);
  255. }
  256. if ((new_sw->scale.aspect_ratio =
  257. atof(new_sw->scale.aspect_ratio_str)) < 0.0) {
  258. new_sw->scale.aspect_ratio = 1.0;
  259. XtWarning("AspectRatio has to be a positive number. (forced to 1.0)");
  260. }
  261. if ((new_sw->scale.precision =
  262. atof(new_sw->scale.precision_str)) < 0.0) {
  263. new_sw->scale.precision = 0.001;
  264. XtWarning("Precision has to be a positive number. (forced to 0.001)");
  265. }
  266. if (new_sw->scale.scale_x_str == DefaultScaleFactor
  267. ||
  268. new_sw->scale.scale_y_str == DefaultScaleFactor)
  269. GetInitialScaleValues(new_sw);
  270. else {
  271. if ((new_sw->scale.scale_x =
  272. atof(new_sw->scale.scale_x_str)) < 0.0) {
  273. new_sw->scale.scale_x = 1.0;
  274. XtWarning("ScaleValue has to be a positive number. (forced to 1.0)");
  275. }
  276. if ((new_sw->scale.scale_y =
  277. atof(new_sw->scale.scale_y_str)) < 0.0) {
  278. new_sw->scale.scale_y = 1.0;
  279. XtWarning("ScaleValue has to be a positive number. (forced to 1.0)");
  280. }
  281. }
  282. }
  283. static void
  284. BuildTable(ScaleWidget sw)
  285. /*
  286. * This procedure builds scaling table for image in the scale struct
  287. * Requires image, scale_x and scale_y to be set properly
  288. */
  289. {
  290. Position x, y;
  291. XtFree((char *) sw->scale.table.x);
  292. XtFree((char *) sw->scale.table.y);
  293. XtFree((char *) sw->scale.table.width);
  294. XtFree((char *) sw->scale.table.height);
  295. sw->scale.table.x =
  296. (Position *) XtMalloc(sizeof(Position) * sw->scale.image->width);
  297. sw->scale.table.y =
  298. (Position *) XtMalloc(sizeof(Position) * sw->scale.image->height);
  299. sw->scale.table.width =
  300. (Dimension *) XtMalloc(sizeof(Dimension) * sw->scale.image->width);
  301. sw->scale.table.height =
  302. (Dimension *) XtMalloc(sizeof(Dimension) * sw->scale.image->height);
  303. /* Build the scaling table */
  304. for (x = 0; x < sw->scale.image->width; x++) {
  305. sw->scale.table.x[(int) x] = (Position) myrint(sw->scale.scale_x * x);
  306. sw->scale.table.width[(int) x] = (Dimension)
  307. myrint(sw->scale.scale_x *(x + 1)) - myrint(sw->scale.scale_x * x);
  308. }
  309. for (y = 0; y < sw->scale.image->height; y++) {
  310. sw->scale.table.y[(int) y] = (Position) myrint(sw->scale.scale_y * y);
  311. sw->scale.table.height[(int) y] = (Dimension)
  312. myrint(sw->scale.scale_y *(y + 1)) - myrint(sw->scale.scale_y * y);
  313. }
  314. }
  315. static void
  316. FlushRectangles(ScaleWidget sw, Drawable drawable, GC gc)
  317. {
  318. XFillRectangles(XtDisplay(sw), drawable, gc,
  319. sw->scale.rectangles, sw->scale.nrectangles);
  320. sw->scale.nrectangles = 0;
  321. }
  322. static void
  323. FillRectangle(ScaleWidget sw, Drawable drawable, GC gc,
  324. Position x, Position y, Dimension width, Dimension height)
  325. {
  326. if (sw->scale.nrectangles == sw->scale.buffer_size)
  327. FlushRectangles(sw, drawable, gc);
  328. sw->scale.rectangles[(int) sw->scale.nrectangles].x = x;
  329. sw->scale.rectangles[(int) sw->scale.nrectangles].y = y;
  330. sw->scale.rectangles[(int) sw->scale.nrectangles].width = width;
  331. sw->scale.rectangles[(int) sw->scale.nrectangles].height = height;
  332. ++sw->scale.nrectangles;
  333. }
  334. static void
  335. ScaleImage(ScaleWidget sw, Drawable drawable, Position img_x, Position img_y,
  336. Position dst_x, Position dst_y,
  337. Dimension img_width, Dimension img_height)
  338. /*
  339. * This procedure scales image into the specified drawable
  340. * It assumes scaling table was already built
  341. */
  342. {
  343. GC gc;
  344. XGCValues gcv;
  345. Position x, y;
  346. Pixel pixel;
  347. /* Clip the img coordinates */
  348. img_x = min(max(img_x, 0), (Position) sw->scale.image->width - 1);
  349. img_y = min(max(img_y, 0), (Position) sw->scale.image->height - 1);
  350. img_width =
  351. min(img_width, (Dimension)(sw->scale.image->width - (Dimension)img_x));
  352. img_height =
  353. min(img_height, (Dimension)(sw->scale.image->height - (Dimension)img_y));
  354. if (sw->scale.scale_x == 1.0 && sw->scale.scale_y == 1.0)
  355. XPutImage(XtDisplay(sw), drawable, sw->scale.gc, sw->scale.image,
  356. img_x, img_y, dst_x, dst_y,
  357. img_width, img_height);
  358. else {
  359. dst_x = dst_x - sw->scale.table.x[(int) img_x];
  360. dst_y = dst_y - sw->scale.table.y[(int) img_y];
  361. gc = XCreateGC(XtDisplay(sw), drawable, 0, NULL);
  362. gcv.function = GXcopy;
  363. XChangeGC(XtDisplay(sw), gc, GCFunction, &gcv);
  364. /* make sure gc knows the right background */
  365. gcv.background = sw->core.background_pixel;
  366. XChangeGC(XtDisplay(sw), gc, GCBackground, &gcv);
  367. /* Set the background of drawable. If the most frequent color
  368. is the background color it can speed up scaling process. */
  369. gcv.foreground = gcv.background;
  370. XChangeGC(XtDisplay(sw), gc, GCForeground, &gcv);
  371. XFillRectangle(XtDisplay(sw), drawable, gc,
  372. sw->scale.table.x[(int) img_x] + dst_x,
  373. sw->scale.table.y[(int) img_y] + dst_y,
  374. sw->scale.table.x[(int) img_x + img_width - 1] -
  375. sw->scale.table.x[(int) img_x],
  376. sw->scale.table.y[(int) img_y + img_height - 1] -
  377. sw->scale.table.y[(int) img_y]);
  378. if (sw->scale.image->format == XYBitmap) {
  379. for (x = img_x; x < img_x + (Position)img_width; x++)
  380. for (y = img_y; y < img_y + (Position)img_height; y++) {
  381. pixel = XGetPixel(sw->scale.image, x, y);
  382. if (pixel) /* Do not draw background */
  383. FillRectangle(sw, drawable, sw->scale.gc,
  384. sw->scale.table.x[(int) x] + dst_x,
  385. sw->scale.table.y[(int) y] + dst_y,
  386. sw->scale.table.width[(int) x],
  387. sw->scale.table.height[(int) y]);
  388. }
  389. FlushRectangles(sw, drawable, sw->scale.gc);
  390. }
  391. else {
  392. for (x = img_x; x < img_x + (Position)img_width; x++)
  393. for (y = img_y; y < img_y + (Position)img_height; y++) {
  394. pixel = XGetPixel(sw->scale.image, x, y);
  395. if (pixel != gcv.background) { /* Do not draw background */
  396. if (gcv.foreground != pixel) { /* Change fg to pixel */
  397. gcv.foreground = pixel;
  398. XChangeGC(XtDisplay(sw), gc, GCForeground, &gcv);
  399. }
  400. XFillRectangle(XtDisplay(sw), drawable, gc,
  401. sw->scale.table.x[(int) x] + dst_x,
  402. sw->scale.table.y[(int) y] + dst_y,
  403. sw->scale.table.width[(int) x],
  404. sw->scale.table.height[(int) y]);
  405. }
  406. }
  407. }
  408. XFreeGC(XtDisplay(sw), gc);
  409. }
  410. }
  411. static int
  412. FindPixel(ScaleWidget sw, Position x, Position y,
  413. Position *img_x, Position *img_y, Pixel *img_pixel)
  414. /* (x,y) == (0,0) where image starts in sw window*/
  415. {
  416. if (*img_x < 0 || *img_x >= sw->scale.image->width
  417. ||
  418. *img_y < 0 || *img_y >= sw->scale.image->height)
  419. return (-1);
  420. if (sw->scale.table.x[(int) *img_x] >= x) {
  421. --*img_x;
  422. return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  423. }
  424. if (sw->scale.table.x[(int) *img_x] +
  425. (Position)sw->scale.table.width[(int) *img_x] < x) {
  426. ++*img_x;
  427. return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  428. }
  429. if (sw->scale.table.y[(int) *img_y] >= y) {
  430. --*img_y;
  431. return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  432. }
  433. if (sw->scale.table.y[(int) *img_y] +
  434. (Position)sw->scale.table.height[(int) *img_y] < y) {
  435. ++*img_y;
  436. return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  437. }
  438. *img_pixel = XGetPixel(sw->scale.image, *img_x, *img_y);
  439. return (0);
  440. }
  441. int
  442. SWGetImagePixel(Widget w, Position x, Position y,
  443. Position *img_x, Position *img_y, Pixel *img_pixel)
  444. {
  445. ScaleWidget sw = (ScaleWidget) w;
  446. x -= sw->scale.x;
  447. y -= sw->scale.y;
  448. *img_x = (Position) floor(x / sw->scale.scale_x);
  449. *img_y = (Position) floor(y / sw->scale.scale_y);
  450. return FindPixel(sw, x, y, img_x, img_y, img_pixel);
  451. }
  452. /* ARGSUSED */
  453. static void
  454. Redisplay(Widget w, XEvent *event, Region region)
  455. {
  456. ScaleWidget sw = (ScaleWidget) w;
  457. Position x, y, img_x, img_y;
  458. Dimension width, height;
  459. if (event->type == Expose) {
  460. if (event->xexpose.x < sw->scale.x) {
  461. x = 0;
  462. width = event->xexpose.width -
  463. (sw->scale.x - event->xexpose.x);
  464. }
  465. else {
  466. x = event->xexpose.x - sw->scale.x;
  467. width = event->xexpose.width;
  468. }
  469. if (event->xexpose.y < sw->scale.y) {
  470. y = 0;
  471. height = event->xexpose.height -
  472. (sw->scale.y - event->xexpose.y);
  473. }
  474. else {
  475. y = event->xexpose.y - sw->scale.y;
  476. height = event->xexpose.height;
  477. }
  478. img_x = min(max((Position) floor((float) x
  479. / (float) sw->scale.scale_x), 0),
  480. (Position) sw->scale.image->width - 1);
  481. img_y = min(max((Position) floor((float) y
  482. / (float) sw->scale.scale_y), 0),
  483. (Position) sw->scale.image->height - 1);
  484. if (sw->core.visible) {
  485. ScaleImage(sw, XtWindow(w),
  486. img_x, img_y,
  487. sw->scale.x + sw->scale.table.x[(int) img_x],
  488. sw->scale.y + sw->scale.table.y[(int) img_y],
  489. (Dimension) ceil((float) width
  490. / sw->scale.scale_x) + 1,
  491. (Dimension) ceil((float) height
  492. / sw->scale.scale_y) + 1);
  493. }
  494. }
  495. }
  496. static void
  497. TryResize(ScaleWidget sw)
  498. {
  499. Dimension width, height;
  500. XtGeometryResult result;
  501. width = (Dimension)
  502. floor(sw->scale.image->width * sw->scale.scale_x)
  503. + 2 * sw->scale.internal_width;
  504. height = (Dimension)
  505. floor(sw->scale.image->height * sw->scale.scale_y)
  506. + 2 * sw->scale.internal_height;
  507. while ((result =
  508. /* SUPPRESS 530 */XtMakeResizeRequest((Widget)sw,width,height,&width,&height))
  509. == XtGeometryAlmost);
  510. if (result != XtGeometryNo) {
  511. sw->core.width = width;
  512. sw->core.height = height;
  513. }
  514. }
  515. static void
  516. Precision(ScaleWidget sw)
  517. {
  518. if (sw->scale.scale_x != 1.0)
  519. sw->scale.scale_x = floor(sw->scale.scale_x / sw->scale.precision)
  520. * sw->scale.precision;
  521. if (sw->scale.scale_y != 1.0)
  522. sw->scale.scale_y = floor(sw->scale.scale_y / sw->scale.precision)
  523. * sw->scale.precision;
  524. }
  525. static void
  526. Proportional(ScaleWidget sw)
  527. {
  528. float scale_x, scale_y;
  529. scale_x = sw->scale.scale_y / sw->scale.aspect_ratio;
  530. scale_y = sw->scale.scale_x * sw->scale.aspect_ratio;
  531. if (scale_x <= sw->scale.scale_x && scale_y <= sw->scale.scale_y) {
  532. if (scale_x > scale_y)
  533. sw->scale.scale_x = scale_x;
  534. else
  535. sw->scale.scale_y = scale_y;
  536. }
  537. else if (scale_x <= sw->scale.scale_x)
  538. sw->scale.scale_x = scale_x;
  539. else if (scale_y <= sw->scale.scale_y)
  540. sw->scale.scale_y = scale_y;
  541. else {
  542. float x_ratio, y_ratio;
  543. x_ratio = scale_x / sw->scale.scale_x;
  544. y_ratio = scale_y / sw->scale.scale_y;
  545. if (x_ratio < y_ratio)
  546. sw->scale.scale_y /= x_ratio;
  547. else
  548. sw->scale.scale_x /= y_ratio;
  549. }
  550. if (fabs(sw->scale.scale_x / sw->scale.scale_y * sw->scale.aspect_ratio
  551. - 1.0) > sw->scale.precision)
  552. XtWarning("can not preserve aspect ratio");
  553. }
  554. static void
  555. GetScaledSize(ScaleWidget sw)
  556. {
  557. sw->scale.width = (Dimension)
  558. max(myrint(sw->scale.scale_x * sw->scale.image->width), 1);
  559. sw->scale.height = (Dimension)
  560. max(myrint(sw->scale.scale_y * sw->scale.image->height), 1);
  561. }
  562. static void
  563. GetScaleValues(ScaleWidget sw)
  564. {
  565. /*
  566. * Make sure to subtract internal width and height.
  567. */
  568. sw->scale.scale_x =
  569. (float) max((int)(sw->core.width - 2 * sw->scale.internal_width), 1)
  570. / (float) sw->scale.image->width;
  571. sw->scale.scale_y =
  572. (float) max((int)(sw->core.height - 2 * sw->scale.internal_height), 1)
  573. / (float) sw->scale.image->height;
  574. }
  575. static void
  576. Unscale(ScaleWidget sw)
  577. {
  578. sw->scale.scale_x = sw->scale.scale_y = 1.0;
  579. GetScaledSize(sw);
  580. BuildTable(sw);
  581. }
  582. static void
  583. Autoscale(ScaleWidget sw)
  584. {
  585. GetScaleValues(sw);
  586. if (sw->scale.proportional) Proportional(sw);
  587. Precision(sw);
  588. GetScaledSize(sw);
  589. BuildTable(sw);
  590. }
  591. static void
  592. PositionImage(ScaleWidget sw)
  593. {
  594. /*
  595. * Set as if for ForgegGravity (that is center the image)
  596. */
  597. sw->scale.x = (Position)
  598. (sw->core.width - sw->scale.width) / 2;
  599. sw->scale.y = (Position)
  600. (sw->core.height - sw->scale.height) / 2;
  601. /*****
  602. if (sw->scale.gravity & WestGravity) {
  603. }
  604. if (sw->scale.gravity & EastGravity) {
  605. }
  606. if (sw->scale.gravity & NorthGravity) {
  607. }
  608. if (sw->scale.gravity & SouthGravity) {
  609. }
  610. *****/
  611. }
  612. static void
  613. Resize(Widget w)
  614. {
  615. ScaleWidget sw = (ScaleWidget) w;
  616. if (sw->scale.autoscale) Autoscale(sw);
  617. PositionImage(sw);
  618. }
  619. static void
  620. Realize(Widget wid, Mask *vmask, XSetWindowAttributes *attr)
  621. {
  622. ScaleWidget sw = (ScaleWidget) wid;
  623. XtCreateWindow(wid, (unsigned int) InputOutput,
  624. (Visual *) sw->scale.visual, *vmask, attr);
  625. }
  626. static void
  627. Destroy(Widget w)
  628. {
  629. ScaleWidget sw = (ScaleWidget) w;
  630. XtFree((char *) sw->scale.table.x);
  631. XtFree((char *) sw->scale.table.y);
  632. XtFree((char *) sw->scale.table.width);
  633. XtFree((char *) sw->scale.table.height);
  634. XtFree((char *) sw->scale.rectangles);
  635. XtReleaseGC(w, sw->scale.gc);
  636. XDestroyImage(sw->scale.image);
  637. }
  638. /* ARGSUSED */
  639. static Boolean
  640. SetValues(Widget current, Widget request, Widget new,
  641. ArgList args, Cardinal *num_args)
  642. {
  643. ScaleWidget cur_sw = (ScaleWidget) current;
  644. /* ScaleWidget req_sw = (ScaleWidget) request; */
  645. ScaleWidget new_sw = (ScaleWidget) new;
  646. Boolean redisplay = False;
  647. Cardinal i;
  648. for (i = 0; i < *num_args; i++) {
  649. if (streq(XtNbackground, args[i].name)) {
  650. XSetBackground(XtDisplay(new), new_sw->scale.gc,
  651. new_sw->core.background_pixel);
  652. }
  653. if (streq(XtNforeground, args[i].name)) {
  654. XSetForeground(XtDisplay(new), new_sw->scale.gc,
  655. new_sw->scale.foreground_pixel);
  656. }
  657. if (streq(XtNimage, args[i].name)) {
  658. XDestroyImage(cur_sw->scale.image);
  659. if (new_sw->scale.image == NULL)
  660. new_sw->scale.image = XCreateImage(XtDisplay(new),
  661. DefaultVisual(XtDisplay(new),
  662. DefaultScreen(XtDisplay(new))),
  663. 1, XYBitmap, 0,
  664. XtCalloc(1, sizeof(char)),
  665. 1, 1, 8, 0);
  666. else
  667. new_sw->scale.image =
  668. XSubImage(new_sw->scale.image,
  669. 0, 0,
  670. new_sw->scale.image->width,
  671. new_sw->scale.image->height);
  672. if (new_sw->scale.resize)
  673. TryResize(new_sw);
  674. if (new_sw->scale.autoscale)
  675. Autoscale(new_sw);
  676. else {
  677. GetScaledSize(new_sw);
  678. BuildTable(new_sw);
  679. }
  680. PositionImage(new_sw);
  681. redisplay = True;
  682. }
  683. if (streq(XtNuserData, args[i].name))
  684. new_sw->scale.userData = (XtPointer)args[i].value;
  685. if (streq(XtNbufferSize, args[i].name)) {
  686. if (new_sw->scale.buffer_size != cur_sw->scale.buffer_size) {
  687. GetRectangleBuffer(new_sw, new_sw->scale.buffer_size);
  688. }
  689. }
  690. if (streq(XtNaspectRatio, args[i].name)) {
  691. if ((new_sw->scale.aspect_ratio =
  692. atof(new_sw->scale.aspect_ratio_str)) < 0.0) {
  693. new_sw->scale.aspect_ratio = cur_sw->scale.aspect_ratio;
  694. XtWarning("AspectRatio has to be a positive number.");
  695. }
  696. else if (new_sw->scale.aspect_ratio != cur_sw->scale.aspect_ratio){
  697. if (new_sw->scale.proportional) {
  698. Proportional(new_sw);
  699. Precision(new_sw);
  700. GetScaledSize(new_sw);
  701. BuildTable(new_sw);
  702. PositionImage(new_sw);
  703. redisplay = True;
  704. }
  705. }
  706. }
  707. if (streq(XtNproportional, args[i].name)) {
  708. if (new_sw->scale.proportional != cur_sw->scale.proportional) {
  709. if (new_sw->scale.proportional) Proportional(new_sw);
  710. Precision(new_sw);
  711. GetScaledSize(new_sw);
  712. BuildTable(new_sw);
  713. PositionImage(new_sw);
  714. redisplay = True;
  715. }
  716. }
  717. if (streq(XtNscaleX, args[i].name)
  718. ||
  719. streq(XtNscaleY, args[i].name)) {
  720. if (new_sw->scale.scale_x_str == DefaultScaleFactor
  721. ||
  722. new_sw->scale.scale_y_str == DefaultScaleFactor)
  723. GetInitialScaleValues(new_sw);
  724. else {
  725. if ((new_sw->scale.scale_x =
  726. atof(new_sw->scale.scale_x_str)) < 0.0) {
  727. new_sw->scale.scale_x = cur_sw->scale.scale_x;
  728. XtWarning("ScaleValue has to be a positive number.");
  729. }
  730. if ((new_sw->scale.scale_y =
  731. atof(new_sw->scale.scale_y_str)) < 0.0) {
  732. new_sw->scale.scale_y = cur_sw->scale.scale_y;
  733. XtWarning("ScaleValue has to be a positive number.");
  734. }
  735. }
  736. if (new_sw->scale.scale_x != cur_sw->scale.scale_x
  737. ||
  738. new_sw->scale.scale_y != cur_sw->scale.scale_y) {
  739. /*?*?*?*?*?*?*?*?*?*?*?*?*?*?**?*?*?*?*?*?*?*?*?***?*/
  740. fprintf(stderr, "================>>%f %f\n",
  741. new_sw->scale.scale_x, new_sw->scale.scale_y);
  742. if (new_sw->scale.proportional) Proportional(new_sw);
  743. Precision(new_sw);
  744. if (new_sw->scale.resize)
  745. TryResize(new_sw);
  746. GetScaledSize(new_sw);
  747. BuildTable(new_sw);
  748. PositionImage(new_sw);
  749. redisplay = True;
  750. }
  751. }
  752. if (streq(XtNprecision, args[i].name)) {
  753. if ((new_sw->scale.precision =
  754. atof(new_sw->scale.precision_str)) < 0.0) {
  755. new_sw->scale.precision = cur_sw->scale.precision;
  756. XtWarning("Precision has to be a positive number.");
  757. }
  758. if (new_sw->scale.precision != cur_sw->scale.precision) {
  759. if (new_sw->scale.proportional) Proportional(new_sw);
  760. Precision(new_sw);
  761. GetScaledSize(new_sw);
  762. BuildTable(new_sw);
  763. PositionImage(new_sw);
  764. redisplay = True;
  765. }
  766. }
  767. }
  768. return(redisplay);
  769. }
  770. void
  771. SWUnscale(Widget w, XEvent *event, String *params, Cardinal *num_params)
  772. {
  773. ScaleWidget sw = (ScaleWidget) w;
  774. Unscale(sw);
  775. PositionImage(sw);
  776. XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True);
  777. }
  778. void
  779. SWAutoscale(Widget w, XEvent *event, String *params, Cardinal *num_params)
  780. {
  781. ScaleWidget sw = (ScaleWidget) w;
  782. Autoscale(sw);
  783. PositionImage(sw);
  784. XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True);
  785. }
  786. void
  787. SWInitialSize(Widget w, XEvent *event, String *params, Cardinal *num_params)
  788. {
  789. ScaleWidget sw = (ScaleWidget) w;
  790. GetInitialScaleValues(sw);
  791. if (sw->scale.proportional) Proportional(sw);
  792. Precision(sw);
  793. if (sw->scale.resize)
  794. TryResize(sw);
  795. GetScaledSize(sw);
  796. BuildTable(sw);
  797. PositionImage(sw);
  798. XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True);
  799. }
  800. void
  801. SWSetImage(Widget w, XImage *image)
  802. {
  803. int n;
  804. Arg wargs[2];
  805. n = 0;
  806. XtSetArg(wargs[n], XtNimage, (XtArgVal) image); n++;
  807. XtSetValues(w, wargs, n);
  808. }
  809. void
  810. RequestSelection(Widget w, XEvent *event, String *params, Cardinal *num_params)
  811. {
  812. SWRequestSelection(w, event->xbutton.time);
  813. }
  814. void
  815. GrabSelection(Widget w, XEvent *event, String *params, Cardinal *num_params)
  816. {
  817. SWGrabSelection(w, event->xbutton.time);
  818. }
  819. Pixmap
  820. SWGetPixmap(Widget w)
  821. {
  822. ScaleWidget sw = (ScaleWidget) w;
  823. Pixmap pixmap;
  824. pixmap = XCreatePixmap(XtDisplay(w), XtWindow(w),
  825. sw->scale.width,
  826. sw->scale.height,
  827. sw->scale.image->depth);
  828. ScaleImage(sw, pixmap,
  829. 0, 0, 0, 0,
  830. (Dimension) sw->scale.image->width,
  831. (Dimension) sw->scale.image->height);
  832. return(pixmap);
  833. }