PageRenderTime 97ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 1ms

/fontforgeexe/cvpalettes.c

https://github.com/tshinnic/fontforge
C | 4443 lines | 3820 code | 433 blank | 190 comment | 983 complexity | 8f7bb73147e3a5162aad5752bd1dd8bc MD5 | raw file
Possible License(s): AGPL-1.0, GPL-3.0, Unlicense
  1. /* Copyright (C) 2000-2012 by George Williams */
  2. /*
  3. * Redistribution and use in source and binary forms, with or without
  4. * modification, are permitted provided that the following conditions are met:
  5. * Redistributions of source code must retain the above copyright notice, this
  6. * list of conditions and the following disclaimer.
  7. * Redistributions in binary form must reproduce the above copyright notice,
  8. * this list of conditions and the following disclaimer in the documentation
  9. * and/or other materials provided with the distribution.
  10. * The name of the author may not be used to endorse or promote products
  11. * derived from this software without specific prior written permission.
  12. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  13. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  14. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  15. * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  16. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  17. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  18. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  19. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  20. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  21. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. #include "fontforgeui.h"
  24. #include "collabclientui.h"
  25. int palettes_docked=1;
  26. int rectelipse=0, polystar=0, regular_star=1;
  27. int center_out[2] = { false, true };
  28. float rr_radius=0;
  29. int ps_pointcnt=6;
  30. float star_percent=1.7320508; /* Regular 6 pointed star */
  31. extern int interpCPsOnMotion;
  32. #include <gkeysym.h>
  33. #include <math.h>
  34. #include "splinefont.h"
  35. #include <ustring.h>
  36. #include <utype.h>
  37. #include <gresource.h>
  38. #include "charview_private.h"
  39. #include "gdraw/hotkeys.h"
  40. static void CVLCheckLayerCount(CharView *cv, int resize);
  41. extern void CVDebugFree(DebugView *dv);
  42. extern GBox _ggadget_Default_Box;
  43. #define ACTIVE_BORDER (_ggadget_Default_Box.active_border)
  44. #define MAIN_FOREGROUND (_ggadget_Default_Box.main_foreground)
  45. extern GDevEventMask input_em[];
  46. extern const int input_em_cnt;
  47. int cvvisible[2] = { 1, 1}, bvvisible[3]= { 1,1,1 };
  48. static GWindow cvlayers, cvtools, bvlayers, bvtools, bvshades;
  49. static GWindow cvlayers2=NULL;
  50. #define LSHOW_CUBIC 1
  51. #define LSHOW_FG 2
  52. #define LSHOW_PREVIEW 4
  53. static int layerscols = LSHOW_CUBIC|LSHOW_FG|LSHOW_PREVIEW; /* which columns to show in layers1 palette */
  54. static int layer_height = 0; /* height of each layer row in layers1 palette */
  55. static int layer_header_height = 0; /* height of initial stuff in layers1 palette */
  56. static int layer_footer_height = 0; /* height of +/- buttons at bottom of layers1 palette */
  57. static int layers_max = 2; /* Maximum number of layers for which widgets have been allocated in layers1 palette */
  58. struct l2 {
  59. int active; /* index of the active layer */
  60. int offtop; /* first layer to show at the top line in layers palette */
  61. int visible_layers; /* number of layers apart from the guides layer to show before using a scrollbar */
  62. int current_layers; /* number of layers for the current character, and the number used in l2.layers */
  63. int max_layers; /* maximum number of layers for which layer controls and previews have been allocated */
  64. BDFChar **layers; /* layer thumbnail previews */
  65. int sb_start; /* x pixel position of the scrollbar */
  66. int column_width; /* width of various indicator columns */
  67. int mo_col, mo_layer; /* mouse over column and layer */
  68. int rename_active; /* If >=2, layer number for which the edit box for layer names is active */
  69. GClut *clut;
  70. GFont *font; /* font to draw text in the palette with */
  71. } layerinfo = { /* info about the current layers in the layers palette */
  72. 2, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0, NULL, NULL
  73. };
  74. struct l2 layer2 = { 2, 0, 0, 0, 0, NULL, 0, 0, 0, 0, 0, NULL, NULL };
  75. static int layers2_active = -1;
  76. static GPoint cvtoolsoff = { -9999, -9999 }, cvlayersoff = { -9999, -9999 }, bvlayersoff = { -9999, -9999 }, bvtoolsoff = { -9999, -9999 }, bvshadesoff = { -9999, -9999 };
  77. int palettes_fixed=1;
  78. static GCursor tools[cvt_max+1] = { ct_pointer }, spirotools[cvt_max+1];
  79. enum cvtools cv_b1_tool = cvt_pointer, cv_cb1_tool = cvt_pointer,
  80. cv_b2_tool = cvt_magnify, cv_cb2_tool = cvt_ruler;
  81. static GFont *toolsfont=NULL, *layersfont=NULL;
  82. #define CV_TOOLS_WIDTH 53
  83. #define CV_TOOLS_HEIGHT (10*27+4*12+2)
  84. #define CV_LAYERS_WIDTH 104
  85. #define CV_LAYERS_HEIGHT 100
  86. #define CV_LAYERS_INITIALCNT 6
  87. #define CV_LAYERS_LINE_HEIGHT 25
  88. #define CV_LAYERS2_WIDTH 120
  89. #define CV_LAYERS2_HEIGHT 196
  90. #define CV_LAYERS2_LINE_HEIGHT 25
  91. #define CV_LAYERS2_HEADER_HEIGHT 20
  92. #define CV_LAYERS2_VISLAYERS ( (CV_LAYERS2_HEIGHT-CV_LAYERS2_HEADER_HEIGHT-2*CV_LAYERS2_LINE_HEIGHT)/CV_LAYERS2_LINE_HEIGHT )
  93. #define BV_TOOLS_WIDTH 53
  94. #define BV_TOOLS_HEIGHT 80
  95. #define BV_LAYERS_HEIGHT 73
  96. #define BV_LAYERS_WIDTH 73
  97. #define BV_SHADES_HEIGHT (8+9*16)
  98. /* These are control ids for the layers palette controls */
  99. #define CID_VBase 1000
  100. #define CID_VGrid (CID_VBase+ly_grid)
  101. #define CID_VBack (CID_VBase+ly_back)
  102. #define CID_VFore (CID_VBase+ly_fore)
  103. #define CID_EBase 3000
  104. #define CID_EGrid (CID_EBase+ly_grid)
  105. #define CID_EBack (CID_EBase+ly_back)
  106. #define CID_EFore (CID_EBase+ly_fore)
  107. #define CID_QBase 5000
  108. #define CID_QGrid (CID_QBase+ly_grid)
  109. #define CID_QBack (CID_QBase+ly_back)
  110. #define CID_QFore (CID_QBase+ly_fore)
  111. #define CID_FBase 7000
  112. #define CID_SB 8000
  113. #define CID_Edit 8001
  114. #define CID_AddLayer 9000
  115. #define CID_RemoveLayer 9001
  116. #define CID_RenameLayer 9002
  117. #define CID_LayersMenu 9003
  118. static void ReparentFixup(GWindow child,GWindow parent, int x, int y, int width, int height ) {
  119. /* This is so nice */
  120. /* KDE does not honor my request for a border for top level windows */
  121. /* KDE does not honor my request for size (for narrow) top level windows */
  122. /* Gnome gets very confused by reparenting */
  123. /* If we've got a top level window, then reparenting it removes gnome's */
  124. /* decoration window, but sets the new parent to root (rather than what */
  125. /* we asked for */
  126. /* I have tried reparenting it twice, unmapping & reparenting. Nothing works */
  127. GWidgetReparentWindow(child,parent,x,y);
  128. if ( width!=0 )
  129. GDrawResize(child,width,height);
  130. GDrawSetWindowBorder(child,1,GDrawGetDefaultForeground(NULL));
  131. }
  132. void onCollabSessionStateChanged( GObject* gobj, FontViewBase* fv )
  133. {
  134. bool inCollab = collabclient_inSessionFV( fv );
  135. if (cvlayers != NULL) {
  136. GGadgetSetEnabled(GWidgetGetControl(cvlayers,CID_AddLayer), !inCollab );
  137. GGadgetSetEnabled(GWidgetGetControl(cvlayers,CID_RemoveLayer), !inCollab );
  138. GGadgetSetEnabled(GWidgetGetControl(cvlayers,CID_RenameLayer), !inCollab );
  139. } else if (cvlayers2 != NULL && 0) {
  140. // These controls seem not to exist in cvlayers2. We can look deeper into this later.
  141. GGadgetSetEnabled(GWidgetGetControl(cvlayers2,CID_AddLayer), !inCollab );
  142. GGadgetSetEnabled(GWidgetGetControl(cvlayers2,CID_RemoveLayer), !inCollab );
  143. GGadgetSetEnabled(GWidgetGetControl(cvlayers2,CID_RenameLayer), !inCollab );
  144. }
  145. }
  146. /* Initialize a window that is to be used for a palette. Specific widgets and other functionality are added elsewhere. */
  147. static GWindow CreatePalette(GWindow w, GRect *pos, int (*eh)(GWindow,GEvent *), void *user_data, GWindowAttrs *wattrs, GWindow v) {
  148. GWindow gw;
  149. GPoint pt, base;
  150. GRect newpos;
  151. GWindow root;
  152. GRect ownerpos, screensize;
  153. pt.x = pos->x; pt.y = pos->y;
  154. if ( !palettes_fixed ) {
  155. root = GDrawGetRoot(NULL);
  156. GDrawGetSize(w,&ownerpos);
  157. GDrawGetSize(root,&screensize);
  158. GDrawTranslateCoordinates(w,root,&pt);
  159. base.x = base.y = 0;
  160. GDrawTranslateCoordinates(w,root,&base);
  161. if ( pt.x<0 ) {
  162. if ( base.x+ownerpos.width+20+pos->width+20 > screensize.width )
  163. pt.x=0;
  164. else
  165. pt.x = base.x+ownerpos.width+20;
  166. }
  167. if ( pt.y<0 ) pt.y=0;
  168. if ( pt.x+pos->width>screensize.width )
  169. pt.x = screensize.width-pos->width;
  170. if ( pt.y+pos->height>screensize.height )
  171. pt.y = screensize.height-pos->height;
  172. }
  173. wattrs->mask |= wam_bordcol|wam_bordwidth;
  174. wattrs->border_width = 1;
  175. wattrs->border_color = GDrawGetDefaultForeground(NULL);
  176. newpos.x = pt.x; newpos.y = pt.y; newpos.width = pos->width; newpos.height = pos->height;
  177. wattrs->mask|= wam_positioned;
  178. wattrs->positioned = true;
  179. gw = GDrawCreateTopWindow(NULL,&newpos,eh,user_data,wattrs);
  180. if ( palettes_docked )
  181. ReparentFixup(gw,v,0,pos->y,pos->width,pos->height);
  182. collabclient_addSessionJoiningCallback( onCollabSessionStateChanged );
  183. collabclient_addSessionLeavingCallback( onCollabSessionStateChanged );
  184. return( gw );
  185. }
  186. /* Return screen coordinates of the palette in off, relative to the root window origin. */
  187. static void SaveOffsets(GWindow main, GWindow palette, GPoint *off) {
  188. if ( !palettes_docked && !palettes_fixed && GDrawIsVisible(palette)) {
  189. GRect mr, pr;
  190. GWindow root, temp;
  191. root = GDrawGetRoot(NULL);
  192. while ( (temp=GDrawGetParentWindow(main))!=root )
  193. main = temp;
  194. GDrawGetSize(main,&mr);
  195. GDrawGetSize(palette,&pr);
  196. off->x = pr.x-mr.x;
  197. off->y = pr.y-mr.y;
  198. if ( off->x<0 ) off->x = 0;
  199. if ( off->y<0 ) off->y = 0;
  200. }
  201. }
  202. /* Set the palette window position to off, a point in the root window space. */
  203. static void RestoreOffsets(GWindow main, GWindow palette, GPoint *off) {
  204. GPoint pt;
  205. GWindow root,temp;
  206. GRect screensize, pos;
  207. if ( palettes_fixed )
  208. return;
  209. pt = *off;
  210. root = GDrawGetRoot(NULL);
  211. GDrawGetSize(root,&screensize);
  212. GDrawGetSize(palette,&pos);
  213. while ( (temp=GDrawGetParentWindow(main))!=root )
  214. main = temp;
  215. GDrawTranslateCoordinates(main,root,&pt);
  216. if ( pt.x<0 ) pt.x=0;
  217. if ( pt.y<0 ) pt.y=0;
  218. if ( pt.x+pos.width>screensize.width )
  219. pt.x = screensize.width-pos.width;
  220. if ( pt.y+pos.height>screensize.height )
  221. pt.y = screensize.height-pos.height;
  222. GDrawTrueMove(palette,pt.x,pt.y);
  223. GDrawRaise(palette);
  224. }
  225. static void CVMenuTool(GWindow gw,struct gmenuitem *mi,GEvent *e) {
  226. CharView *cv = (CharView *) GDrawGetUserData(gw);
  227. cv->b1_tool = mi->mid;
  228. if ( cvtools!=NULL )
  229. GDrawRequestExpose(cvtools,NULL,false);
  230. CVToolsSetCursor(cv,0,NULL);
  231. }
  232. static void CVChangeSpiroMode(CharView *cv);
  233. static void CVMenuSpiroSet(GWindow gw,struct gmenuitem *mi,GEvent *e) {
  234. CharView *cv = (CharView *) GDrawGetUserData(gw);
  235. CVChangeSpiroMode(cv);
  236. }
  237. void cvtoollist_check(GWindow gw,struct gmenuitem *mi,GEvent *e) {
  238. CharView *cv = (CharView *) GDrawGetUserData(gw);
  239. int order2 = cv->b.layerheads[cv->b.drawmode]->order2;
  240. for ( mi = mi->sub; mi->ti.text!=NULL || mi->ti.line ; ++mi ) {
  241. mi->ti.checked = mi->mid==cv->b1_tool;
  242. switch ( mi->mid ) {
  243. case cvt_freehand:
  244. mi->ti.disabled = order2;
  245. break;
  246. case cvt_spiro:
  247. mi->ti.disabled = !hasspiro();
  248. break;
  249. }
  250. }
  251. }
  252. /* Note: If you change this ordering, change enum cvtools */
  253. static char *popupsres[] = {
  254. N_("Pointer"), N_("Magnify (Minify with alt)"),
  255. N_("Draw a freehand curve"), N_("Scroll by hand"),
  256. N_("Cut splines in two"), N_("Measure distance, angle between points"),
  257. N_("Add a point, then drag out its control points"), N_("Change whether spiro is active or not"),
  258. N_("Add a curve point"), N_("Add a curve point always either horizontal or vertical"),
  259. N_("Add a corner point"), N_("Add a tangent point"),
  260. N_("Scale the selection"), N_("Rotate the selection"),
  261. N_("Flip the selection"), N_("Skew the selection"),
  262. N_("Rotate the selection in 3D and project back to plain"), N_("Perform a perspective transformation on the selection"),
  263. N_("Rectangle or Ellipse"), N_("Polygon or Star"),
  264. N_("Rectangle or Ellipse"), N_("Polygon or Star")};
  265. GMenuItem2 cvtoollist[] = {
  266. { { (unichar_t *) N_("_Pointer"), (GImage *) "toolspointer.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Pointer|No Shortcut"), NULL, NULL, CVMenuTool, cvt_pointer },
  267. { { (unichar_t *) N_("_Magnify"), (GImage *) "toolsmagnify.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Magnify|No Shortcut"), NULL, NULL, CVMenuTool, cvt_magnify },
  268. { { (unichar_t *) N_("_Freehand"), (GImage *) "toolsfreehand.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Freehand|No Shortcut"), NULL, NULL, CVMenuTool, cvt_freehand },
  269. { { (unichar_t *) N_("_Scroll"), (GImage *) "toolsscroll.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Scroll|No Shortcut"), NULL, NULL, CVMenuTool, cvt_hand },
  270. { { (unichar_t *) N_("_Knife"), (GImage *) "toolsknife.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Knife|No Shortcut"), NULL, NULL, CVMenuTool, cvt_knife },
  271. { { (unichar_t *) N_("_Ruler"), (GImage *) "toolsruler.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Ruler|No Shortcut"), NULL, NULL, CVMenuTool, cvt_ruler },
  272. { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
  273. { { (unichar_t *) N_("P_en"), (GImage *) "toolspen.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Pen|No Shortcut"), NULL, NULL, CVMenuTool, cvt_pen },
  274. { { (unichar_t *) N_("_Activate Spiro"), (GImage *) "toolsspiro.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Activate Spiro|No Shortcut"), NULL, NULL, CVMenuSpiroSet, cvt_spiro },
  275. { { (unichar_t *) N_("_Curve"), (GImage *) "pointscurve.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Curve Tool|No Shortcut"), NULL, NULL, CVMenuTool, cvt_curve },
  276. { { (unichar_t *) N_("_HVCurve"), (GImage *) "pointshvcurve.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'o' }, H_("HVCurve Tool|No Shortcut"), NULL, NULL, CVMenuTool, cvt_hvcurve },
  277. { { (unichar_t *) N_("C_orner"), (GImage *) "pointscorner.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'o' }, H_("Corner Tool|No Shortcut"), NULL, NULL, CVMenuTool, cvt_corner },
  278. { { (unichar_t *) N_("_Tangent"), (GImage *) "pointstangent.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Tangent Tool|No Shortcut"), NULL, NULL, CVMenuTool, cvt_tangent },
  279. { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
  280. { { (unichar_t *) N_("Sca_le"), (GImage *) "toolsscale.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Scale|No Shortcut"), NULL, NULL, CVMenuTool, cvt_scale },
  281. { { (unichar_t *) N_("Rotate"), (GImage *) "toolsrotate.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Rotate|No Shortcut"), NULL, NULL, CVMenuTool, cvt_rotate },
  282. { { (unichar_t *) N_("Flip"), (GImage *) "toolsflip.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Flip|No Shortcut"), NULL, NULL, CVMenuTool, cvt_flip },
  283. { { (unichar_t *) N_("Ske_w"), (GImage *) "toolsskew.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Skew|No Shortcut"), NULL, NULL, CVMenuTool, cvt_skew },
  284. { { (unichar_t *) N_("_3D Rotate"), (GImage *) "tools3drotate.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("3D Rotate|No Shortcut"), NULL, NULL, CVMenuTool, cvt_3d_rotate },
  285. { { (unichar_t *) N_("Perspecti_ve"), (GImage *) "toolsperspective.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Perspective|No Shortcut"), NULL, NULL, CVMenuTool, cvt_perspective },
  286. { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
  287. { { (unichar_t *) N_("Rectan_gle"), (GImage *) "toolsrect.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Rectangle|No Shortcut"), NULL, NULL, CVMenuTool, cvt_rect },
  288. { { (unichar_t *) N_("Pol_ygon"), (GImage *) "toolspolygon.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Polygon|No Shortcut"), NULL, NULL, CVMenuTool, cvt_poly },
  289. { { (unichar_t *) N_("Ellipse"), (GImage *) "toolselipse.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Ellipse|No Shortcut"), NULL, NULL, CVMenuTool, cvt_elipse },
  290. { { (unichar_t *) N_("Star"), (GImage *) "toolsstar.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Star|No Shortcut"), NULL, NULL, CVMenuTool, cvt_star },
  291. GMENUITEM2_EMPTY
  292. };
  293. GMenuItem2 cvspirotoollist[] = {
  294. { { (unichar_t *) N_("_Pointer"), (GImage *) "toolspointer.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Pointer|No Shortcut"), NULL, NULL, CVMenuTool, cvt_pointer },
  295. { { (unichar_t *) N_("_Magnify"), (GImage *) "toolsmagnify.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Magnify|No Shortcut"), NULL, NULL, CVMenuTool, cvt_magnify },
  296. { { (unichar_t *) N_("_Freehand"), (GImage *) "toolsfreehand.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Freehand|No Shortcut"), NULL, NULL, CVMenuTool, cvt_freehand },
  297. { { (unichar_t *) N_("_Scroll"), (GImage *) "toolsscroll.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("Scroll|No Shortcut"), NULL, NULL, CVMenuTool, cvt_hand },
  298. { { (unichar_t *) N_("_Knife"), (GImage *) "toolsknife.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Knife|No Shortcut"), NULL, NULL, CVMenuTool, cvt_knife },
  299. { { (unichar_t *) N_("_Ruler"), (GImage *) "toolsruler.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Ruler|No Shortcut"), NULL, NULL, CVMenuTool, cvt_ruler },
  300. { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
  301. { { (unichar_t *) N_("_Knife"), (GImage *) "toolsknife.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Knife|No Shortcut"), NULL, NULL, CVMenuTool, cvt_knife },
  302. { { (unichar_t *) N_("_Ruler"), (GImage *) "toolsruler.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Ruler|No Shortcut"), NULL, NULL, CVMenuTool, cvt_ruler },
  303. { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
  304. { { (unichar_t *) N_("De_activate Spiro"), (GImage *) "toolsspiro.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Activate Spiro|No Shortcut"), NULL, NULL, CVMenuSpiroSet, cvt_spiro },
  305. { { (unichar_t *) N_("C_orner"), (GImage *) "pointscorner.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'o' }, H_("Corner Tool|No Shortcut"), NULL, NULL, CVMenuTool, cvt_spirocorner },
  306. { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
  307. { { (unichar_t *) N_("G_4"), (GImage *) "pointscurve.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'C' }, H_("G4 Tool|No Shortcut"), NULL, NULL, CVMenuTool, cvt_spirog4 },
  308. { { (unichar_t *) N_("G_2"), (GImage *) "pointsG2curve.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'o' }, H_("G2 Tool|No Shortcut"), NULL, NULL, CVMenuTool, cvt_spirog2 },
  309. { { (unichar_t *) N_("Lef_t"), (GImage *) "pointsspiroprev.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Left Tool|No Shortcut"), NULL, NULL, CVMenuTool, cvt_spiroleft },
  310. { { (unichar_t *) N_("Rig_ht"), (GImage *) "pointsspironext.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Right Tool|No Shortcut"), NULL, NULL, CVMenuTool, cvt_spiroright },
  311. { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
  312. { { (unichar_t *) N_("Sca_le"), (GImage *) "toolsscale.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Scale|No Shortcut"), NULL, NULL, CVMenuTool, cvt_scale },
  313. { { (unichar_t *) N_("Rotate"), (GImage *) "toolsrotate.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Rotate|No Shortcut"), NULL, NULL, CVMenuTool, cvt_rotate },
  314. { { (unichar_t *) N_("Flip"), (GImage *) "toolsflip.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Flip|No Shortcut"), NULL, NULL, CVMenuTool, cvt_flip },
  315. { { (unichar_t *) N_("Ske_w"), (GImage *) "toolsskew.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Skew|No Shortcut"), NULL, NULL, CVMenuTool, cvt_skew },
  316. { { (unichar_t *) N_("_3D Rotate"), (GImage *) "tools3drotate.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("3D Rotate|No Shortcut"), NULL, NULL, CVMenuTool, cvt_3d_rotate },
  317. { { (unichar_t *) N_("Perspecti_ve"), (GImage *) "toolsperspective.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Perspective|No Shortcut"), NULL, NULL, CVMenuTool, cvt_perspective },
  318. { { NULL, NULL, COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 0, 0, 0, 1, 0, 0, 0, '\0' }, NULL, NULL, NULL, NULL, 0 }, /* line */
  319. { { (unichar_t *) N_("Rectan_gle"), (GImage *) "toolsrect.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Rectangle|No Shortcut"), NULL, NULL, CVMenuTool, cvt_rect },
  320. { { (unichar_t *) N_("Pol_ygon"), (GImage *) "toolspolygon.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Polygon|No Shortcut"), NULL, NULL, CVMenuTool, cvt_poly },
  321. { { (unichar_t *) N_("Ellipse"), (GImage *) "toolselipse.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Ellipse|No Shortcut"), NULL, NULL, CVMenuTool, cvt_elipse },
  322. { { (unichar_t *) N_("Star"), (GImage *) "toolsstar.png", COLOR_DEFAULT, COLOR_DEFAULT, NULL, NULL, 0, 1, 1, 0, 0, 0, 1, 1, 0, 'T' }, H_("Star|No Shortcut"), NULL, NULL, CVMenuTool, cvt_star },
  323. GMENUITEM2_EMPTY
  324. };
  325. static char *editablelayers[] = {
  326. /* GT: Foreground, make it short */
  327. N_("F_ore"),
  328. /* GT: Background, make it short */
  329. N_("_Back"),
  330. /* GT: Guide layer, make it short */
  331. N_("_Guide")
  332. };
  333. static real raddiam_x = 20, raddiam_y = 20, rotate_by=0;
  334. static StrokeInfo expand = {
  335. 25, lj_round, lc_butt, si_centerline,
  336. false, /* removeexternal */
  337. false, /* removeinternal */
  338. false, /* leave users */
  339. 3.1415926535897932/4, 25, NULL, 50,
  340. 0.0, 0, 0, NULL, NULL
  341. };
  342. real CVRoundRectRadius(void) {
  343. return( rr_radius );
  344. }
  345. int CVRectElipseCenter(void) {
  346. return( center_out[rectelipse] );
  347. }
  348. int CVPolyStarPoints(void) {
  349. return( ps_pointcnt );
  350. }
  351. real CVStarRatio(void) {
  352. if ( regular_star )
  353. return( sin(3.1415926535897932/ps_pointcnt)*tan(2*3.1415926535897932/ps_pointcnt)+cos(3.1415926535897932/ps_pointcnt) );
  354. return( star_percent );
  355. }
  356. StrokeInfo *CVFreeHandInfo(void) {
  357. return( &expand );
  358. }
  359. struct ask_info {
  360. GWindow gw;
  361. int done;
  362. int ret;
  363. float *val;
  364. int *co;
  365. GGadget *rb1;
  366. GGadget *reg;
  367. GGadget *pts;
  368. int ispolystar;
  369. int haspos;
  370. char *lab;
  371. CharView *cv;
  372. };
  373. #define CID_ValText 1001
  374. #define CID_PointPercent 1002
  375. #define CID_CentCornLab 1003
  376. #define CID_CentCornX 1004
  377. #define CID_CentCornY 1005
  378. #define CID_RadDiamLab 1006
  379. #define CID_RadDiamX 1007
  380. #define CID_RadDiamY 1008
  381. #define CID_Angle 1009
  382. static void FakeShapeEvents(CharView *cv) {
  383. GEvent event;
  384. real trans[6];
  385. cv->active_tool = rectelipse ? cvt_elipse : cvt_rect;
  386. if ( cv->b.sc->inspiro && hasspiro() ) {
  387. GDrawSetCursor(cv->v,spirotools[cv->active_tool]);
  388. GDrawSetCursor(cvtools,spirotools[cv->active_tool]);
  389. } else {
  390. GDrawSetCursor(cv->v,tools[cv->active_tool]);
  391. GDrawSetCursor(cvtools,tools[cv->active_tool]);
  392. }
  393. cv->showing_tool = cv->active_tool;
  394. memset(&event,0,sizeof(event));
  395. event.type = et_mousedown;
  396. CVMouseDownShape(cv,&event);
  397. cv->info.x += raddiam_x;
  398. cv->info.y += raddiam_y;
  399. CVMouseMoveShape(cv);
  400. CVMouseUpShape(cv);
  401. if ( raddiam_x!=0 && raddiam_y!=0 && rotate_by!=0 ) {
  402. trans[0] = trans[3] = cos ( rotate_by*3.1415926535897932/180. );
  403. trans[1] = sin( rotate_by*3.1415926535897932/180. );
  404. trans[2] = -trans[1];
  405. trans[4] = -cv->p.x*trans[0] - cv->p.y*trans[2] + cv->p.x;
  406. trans[5] = -cv->p.x*trans[1] - cv->p.y*trans[3] + cv->p.y;
  407. SplinePointListTransform(cv->b.layerheads[cv->b.drawmode]->splines,trans,
  408. interpCPsOnMotion?tpt_OnlySelectedInterpCPs:tpt_OnlySelected);
  409. SCUpdateAll(cv->b.sc);
  410. }
  411. cv->active_tool = cvt_none;
  412. }
  413. static int TA_OK(GGadget *g, GEvent *e) {
  414. if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
  415. struct ask_info *d = GDrawGetUserData(GGadgetGetWindow(g));
  416. real val, val2=0;
  417. int err=0;
  418. int re = !GGadgetIsChecked(d->rb1);
  419. if ( d->ispolystar ) {
  420. val = GetInt8(d->gw,CID_ValText,d->lab,&err);
  421. if ( !(regular_star = GGadgetIsChecked(d->reg)))
  422. val2 = GetReal8(d->gw,CID_PointPercent,_("Size of Points"),&err);
  423. } else {
  424. val = GetReal8(d->gw,CID_ValText,d->lab,&err);
  425. d->co[re] = !GGadgetIsChecked(d->reg);
  426. }
  427. if ( err )
  428. return( true );
  429. if ( d->haspos ) {
  430. real x,y, radx,rady, ang;
  431. x = GetInt8(d->gw,CID_CentCornX,_("_X"),&err);
  432. y = GetInt8(d->gw,CID_CentCornY,_("_Y"),&err);
  433. radx = GetInt8(d->gw,CID_RadDiamX,_("Radius: "),&err);
  434. rady = GetInt8(d->gw,CID_RadDiamY,_("Radius: "),&err);
  435. ang = GetInt8(d->gw,CID_Angle,_("Angle:"),&err);
  436. if ( err )
  437. return( true );
  438. d->cv->p.x = d->cv->info.x = x;
  439. d->cv->p.y = d->cv->info.y = y;
  440. raddiam_x = radx; raddiam_y = rady;
  441. rotate_by = ang;
  442. rectelipse = re;
  443. *d->val = val;
  444. FakeShapeEvents(d->cv);
  445. }
  446. *d->val = val;
  447. d->ret = re;
  448. d->done = true;
  449. if ( !regular_star && d->ispolystar )
  450. star_percent = val2/100;
  451. SavePrefs(true);
  452. }
  453. return( true );
  454. }
  455. static int TA_Cancel(GGadget *g, GEvent *e) {
  456. if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
  457. struct ask_info *d = GDrawGetUserData(GGadgetGetWindow(g));
  458. d->done = true;
  459. }
  460. return( true );
  461. }
  462. static int TA_CenRadChange(GGadget *g, GEvent *e) {
  463. if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
  464. struct ask_info *d = GDrawGetUserData(GGadgetGetWindow(g));
  465. int is_bb = GGadgetIsChecked(d->reg);
  466. GGadgetSetTitle8(GWidgetGetControl(d->gw,CID_CentCornLab),
  467. is_bb ? _("Corner") : _("C_enter"));
  468. GGadgetSetTitle8(GWidgetGetControl(d->gw,CID_RadDiamLab),
  469. is_bb ? _("Diameter:") : _("Radius: "));
  470. }
  471. return( true );
  472. }
  473. static int TA_RadChange(GGadget *g, GEvent *e) {
  474. if ( e->type==et_controlevent && e->u.control.subtype == et_radiochanged ) {
  475. struct ask_info *d = GDrawGetUserData(GGadgetGetWindow(g));
  476. int is_ellipse = !GGadgetIsChecked(d->rb1);
  477. GGadgetSetEnabled(GWidgetGetControl(d->gw,CID_ValText), !is_ellipse );
  478. GGadgetSetChecked(d->reg,!center_out[is_ellipse]);
  479. GGadgetSetChecked(d->pts,center_out[is_ellipse]);
  480. if ( d->haspos )
  481. TA_CenRadChange(g,e);
  482. }
  483. return( true );
  484. }
  485. static int toolask_e_h(GWindow gw, GEvent *event) {
  486. if ( event->type==et_close ) {
  487. struct ask_info *d = GDrawGetUserData(gw);
  488. d->done = true;
  489. } else if ( event->type == et_map ) {
  490. /* Above palettes */
  491. GDrawRaise(gw);
  492. }
  493. return( event->type!=et_char );
  494. }
  495. static int Ask(char *rb1, char *rb2, int rb, char *lab, float *val, int *co,
  496. int ispolystar, CharView *cv ) {
  497. struct ask_info d;
  498. char buffer[20], buf[20];
  499. char cenx[20], ceny[20], radx[20], rady[20], angle[20];
  500. GRect pos;
  501. GWindowAttrs wattrs;
  502. GGadgetCreateData gcd[19];
  503. GTextInfo label[19];
  504. int off = ((ispolystar&1)?15:0) + ((ispolystar&2)?84:0);
  505. int haspos = (ispolystar&2)?1:0;
  506. ispolystar &= 1;
  507. d.done = false;
  508. d.ret = rb;
  509. d.val = val;
  510. d.co = co;
  511. d.ispolystar = ispolystar;
  512. d.haspos = haspos;
  513. d.lab = lab;
  514. d.cv = cv;
  515. memset(&wattrs,0,sizeof(wattrs));
  516. wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_isdlg|wam_restrict;
  517. wattrs.event_masks = ~(1<<et_charup);
  518. wattrs.restrict_input_to_me = 1;
  519. wattrs.undercursor = 1;
  520. wattrs.cursor = ct_pointer;
  521. wattrs.utf8_window_title = _("Shape Type");
  522. wattrs.is_dlg = true;
  523. pos.x = pos.y = 0;
  524. pos.width = GGadgetScale(GDrawPointsToPixels(NULL,190));
  525. pos.height = GDrawPointsToPixels(NULL,120+off);
  526. d.gw = GDrawCreateTopWindow(NULL,&pos,toolask_e_h,&d,&wattrs);
  527. memset(&label,0,sizeof(label));
  528. memset(&gcd,0,sizeof(gcd));
  529. label[0].text = (unichar_t *) rb1;
  530. label[0].text_is_1byte = true;
  531. gcd[0].gd.label = &label[0];
  532. gcd[0].gd.pos.x = 5; gcd[0].gd.pos.y = 5;
  533. gcd[0].gd.flags = gg_enabled|gg_visible | (rb==0?gg_cb_on:0);
  534. gcd[0].creator = GRadioCreate;
  535. label[1].text = (unichar_t *) rb2;
  536. label[1].text_is_1byte = true;
  537. gcd[1].gd.label = &label[1];
  538. gcd[1].gd.pos.x = ispolystar?65:75; gcd[1].gd.pos.y = 5;
  539. gcd[1].gd.flags = gg_enabled|gg_visible | (rb==1?gg_cb_on:0);
  540. gcd[1].creator = GRadioCreate;
  541. label[2].text = (unichar_t *) lab;
  542. label[2].text_is_1byte = true;
  543. gcd[2].gd.label = &label[2];
  544. gcd[2].gd.pos.x = 5; gcd[2].gd.pos.y = 25;
  545. gcd[2].gd.flags = gg_enabled|gg_visible ;
  546. gcd[2].creator = GLabelCreate;
  547. sprintf( buffer, "%g", *val );
  548. label[3].text = (unichar_t *) buffer;
  549. label[3].text_is_1byte = true;
  550. gcd[3].gd.label = &label[3];
  551. gcd[3].gd.pos.x = 5; gcd[3].gd.pos.y = 40;
  552. gcd[3].gd.flags = gg_enabled|gg_visible ;
  553. gcd[3].gd.cid = CID_ValText;
  554. gcd[3].creator = GTextFieldCreate;
  555. gcd[4].gd.pos.x = 20-3; gcd[4].gd.pos.y = 85+off;
  556. gcd[4].gd.pos.width = -1; gcd[4].gd.pos.height = 0;
  557. gcd[4].gd.flags = gg_visible | gg_enabled | gg_but_default;
  558. label[4].text = (unichar_t *) _("_OK");
  559. label[4].text_is_1byte = true;
  560. label[4].text_in_resource = true;
  561. gcd[4].gd.mnemonic = 'O';
  562. gcd[4].gd.label = &label[4];
  563. gcd[4].gd.handle_controlevent = TA_OK;
  564. gcd[4].creator = GButtonCreate;
  565. gcd[5].gd.pos.x = -20; gcd[5].gd.pos.y = 85+3+off;
  566. gcd[5].gd.pos.width = -1; gcd[5].gd.pos.height = 0;
  567. gcd[5].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
  568. label[5].text = (unichar_t *) _("_Cancel");
  569. label[5].text_is_1byte = true;
  570. label[5].text_in_resource = true;
  571. gcd[5].gd.label = &label[5];
  572. gcd[5].gd.mnemonic = 'C';
  573. gcd[5].gd.handle_controlevent = TA_Cancel;
  574. gcd[5].creator = GButtonCreate;
  575. if ( ispolystar ) {
  576. label[6].text = (unichar_t *) _("Regular");
  577. label[6].text_is_1byte = true;
  578. gcd[6].gd.label = &label[6];
  579. gcd[6].gd.pos.x = 5; gcd[6].gd.pos.y = 70;
  580. gcd[6].gd.flags = gg_enabled|gg_visible | (rb==0?gg_cb_on:0);
  581. gcd[6].creator = GRadioCreate;
  582. label[7].text = (unichar_t *) _("Points:");
  583. label[7].text_is_1byte = true;
  584. gcd[7].gd.label = &label[7];
  585. gcd[7].gd.pos.x = 65; gcd[7].gd.pos.y = 70;
  586. gcd[7].gd.flags = gg_enabled|gg_visible | (rb==1?gg_cb_on:0);
  587. gcd[7].creator = GRadioCreate;
  588. sprintf( buf, "%4g", star_percent*100 );
  589. label[8].text = (unichar_t *) buf;
  590. label[8].text_is_1byte = true;
  591. gcd[8].gd.label = &label[8];
  592. gcd[8].gd.pos.x = 125; gcd[8].gd.pos.y = 70; gcd[8].gd.pos.width=50;
  593. gcd[8].gd.flags = gg_enabled|gg_visible ;
  594. gcd[8].gd.cid = CID_PointPercent;
  595. gcd[8].creator = GTextFieldCreate;
  596. label[9].text = (unichar_t *) "%";
  597. label[9].text_is_1byte = true;
  598. gcd[9].gd.label = &label[9];
  599. gcd[9].gd.pos.x = 180; gcd[9].gd.pos.y = 70;
  600. gcd[9].gd.flags = gg_enabled|gg_visible ;
  601. gcd[9].creator = GLabelCreate;
  602. } else {
  603. label[6].text = (unichar_t *) _("Bounding Box");
  604. label[6].text_is_1byte = true;
  605. gcd[6].gd.label = &label[6];
  606. gcd[6].gd.pos.x = 5; gcd[6].gd.pos.y = 65;
  607. gcd[6].gd.flags = gg_enabled|gg_visible | (co[rb]==0?gg_cb_on:0);
  608. gcd[6].creator = GRadioCreate;
  609. label[7].text = (unichar_t *) _("Center Out");
  610. label[7].text_is_1byte = true;
  611. gcd[7].gd.label = &label[7];
  612. gcd[7].gd.pos.x = 90; gcd[7].gd.pos.y = 65;
  613. gcd[7].gd.flags = gg_enabled|gg_visible | (co[rb]==1?gg_cb_on:0);
  614. gcd[7].creator = GRadioCreate;
  615. if ( rb )
  616. gcd[3].gd.flags = gg_visible;
  617. gcd[0].gd.handle_controlevent = TA_RadChange;
  618. gcd[1].gd.handle_controlevent = TA_RadChange;
  619. if ( haspos ) {
  620. gcd[6].gd.handle_controlevent = TA_CenRadChange;
  621. gcd[7].gd.handle_controlevent = TA_CenRadChange;
  622. label[8].text = (unichar_t *) _("_X");
  623. label[8].text_is_1byte = true;
  624. label[8].text_in_resource = true;
  625. gcd[8].gd.label = &label[8];
  626. gcd[8].gd.pos.x = 70; gcd[8].gd.pos.y = gcd[7].gd.pos.y+15;
  627. gcd[8].gd.flags = gg_enabled|gg_visible;
  628. gcd[8].creator = GLabelCreate;
  629. label[9].text = (unichar_t *) _("_Y");
  630. label[9].text_is_1byte = true;
  631. label[9].text_in_resource = true;
  632. gcd[9].gd.label = &label[9];
  633. gcd[9].gd.pos.x = 120; gcd[9].gd.pos.y = gcd[8].gd.pos.y;
  634. gcd[9].gd.flags = gg_enabled|gg_visible;
  635. gcd[9].creator = GLabelCreate;
  636. label[10].text = (unichar_t *) (co[rb] ? _("C_enter") : _("C_orner") );
  637. label[10].text_is_1byte = true;
  638. label[10].text_in_resource = true;
  639. gcd[10].gd.label = &label[10];
  640. gcd[10].gd.pos.x = 5; gcd[10].gd.pos.y = gcd[8].gd.pos.y+17;
  641. gcd[10].gd.flags = gg_enabled|gg_visible;
  642. gcd[10].gd.cid = CID_CentCornLab;
  643. gcd[10].creator = GLabelCreate;
  644. sprintf( cenx, "%g", (double) cv->info.x );
  645. label[11].text = (unichar_t *) cenx;
  646. label[11].text_is_1byte = true;
  647. gcd[11].gd.label = &label[11];
  648. gcd[11].gd.pos.x = 60; gcd[11].gd.pos.y = gcd[10].gd.pos.y-4;
  649. gcd[11].gd.pos.width = 40;
  650. gcd[11].gd.flags = gg_enabled|gg_visible;
  651. gcd[11].gd.cid = CID_CentCornX;
  652. gcd[11].creator = GTextFieldCreate;
  653. sprintf( ceny, "%g", (double) cv->info.y );
  654. label[12].text = (unichar_t *) ceny;
  655. label[12].text_is_1byte = true;
  656. gcd[12].gd.label = &label[12];
  657. gcd[12].gd.pos.x = 110; gcd[12].gd.pos.y = gcd[11].gd.pos.y;
  658. gcd[12].gd.pos.width = gcd[11].gd.pos.width;
  659. gcd[12].gd.flags = gg_enabled|gg_visible;
  660. gcd[12].gd.cid = CID_CentCornY;
  661. gcd[12].creator = GTextFieldCreate;
  662. label[13].text = (unichar_t *) (co[rb] ? _("Radius: ") : _("Diameter:") );
  663. label[13].text_is_1byte = true;
  664. gcd[13].gd.label = &label[13];
  665. gcd[13].gd.pos.x = 5; gcd[13].gd.pos.y = gcd[10].gd.pos.y+24;
  666. gcd[13].gd.flags = gg_enabled|gg_visible;
  667. gcd[13].gd.cid = CID_RadDiamLab;
  668. gcd[13].creator = GLabelCreate;
  669. sprintf( radx, "%g", (double) raddiam_x );
  670. label[14].text = (unichar_t *) radx;
  671. label[14].text_is_1byte = true;
  672. gcd[14].gd.label = &label[14];
  673. gcd[14].gd.pos.x = gcd[11].gd.pos.x; gcd[14].gd.pos.y = gcd[13].gd.pos.y-4;
  674. gcd[14].gd.pos.width = gcd[11].gd.pos.width;
  675. gcd[14].gd.flags = gg_enabled|gg_visible;
  676. gcd[14].gd.cid = CID_RadDiamX;
  677. gcd[14].creator = GTextFieldCreate;
  678. sprintf( rady, "%g", (double) raddiam_y );
  679. label[15].text = (unichar_t *) rady;
  680. label[15].text_is_1byte = true;
  681. gcd[15].gd.label = &label[15];
  682. gcd[15].gd.pos.x = gcd[12].gd.pos.x; gcd[15].gd.pos.y = gcd[14].gd.pos.y;
  683. gcd[15].gd.pos.width = gcd[11].gd.pos.width;
  684. gcd[15].gd.flags = gg_enabled|gg_visible;
  685. gcd[15].gd.cid = CID_RadDiamY;
  686. gcd[15].creator = GTextFieldCreate;
  687. label[16].text = (unichar_t *) _("Angle:");
  688. label[16].text_is_1byte = true;
  689. gcd[16].gd.label = &label[16];
  690. gcd[16].gd.pos.x = 5; gcd[16].gd.pos.y = gcd[13].gd.pos.y+24;
  691. gcd[16].gd.flags = gg_enabled|gg_visible;
  692. gcd[16].creator = GLabelCreate;
  693. sprintf( angle, "%g", (double) rotate_by );
  694. label[17].text = (unichar_t *) angle;
  695. label[17].text_is_1byte = true;
  696. gcd[17].gd.label = &label[17];
  697. gcd[17].gd.pos.x = 60; gcd[17].gd.pos.y = gcd[16].gd.pos.y-4;
  698. gcd[17].gd.pos.width = gcd[11].gd.pos.width;
  699. gcd[17].gd.flags = gg_enabled|gg_visible;
  700. gcd[17].gd.cid = CID_Angle;
  701. gcd[17].creator = GTextFieldCreate;
  702. }
  703. }
  704. GGadgetsCreate(d.gw,gcd);
  705. d.rb1 = gcd[0].ret;
  706. d.reg = gcd[6].ret;
  707. d.pts = gcd[7].ret;
  708. GWidgetHidePalettes();
  709. GDrawSetVisible(d.gw,true);
  710. while ( !d.done )
  711. GDrawProcessOneEvent(NULL);
  712. GDrawDestroyWindow(d.gw);
  713. return( d.ret );
  714. }
  715. static void CVRectElipse(CharView *cv) {
  716. rectelipse = Ask(_("Rectangle"),_("Ellipse"),rectelipse,
  717. _("Round Rectangle Radius"),&rr_radius,center_out,false, cv);
  718. GDrawRequestExpose(cvtools,NULL,false);
  719. }
  720. void CVRectEllipsePosDlg(CharView *cv) {
  721. rectelipse = Ask(_("Rectangle"),_("Ellipse"),rectelipse,
  722. _("Round Rectangle Radius"),&rr_radius,center_out,2, cv);
  723. GDrawRequestExpose(cvtools,NULL,false);
  724. }
  725. static void CVPolyStar(CharView *cv) {
  726. float temp = ps_pointcnt;
  727. int foo[2];
  728. polystar = Ask(_("Polygon"),_("Star"),polystar,
  729. _("Number of star points/Polygon vertices"),&temp,foo,true, cv);
  730. ps_pointcnt = temp;
  731. }
  732. static void ToolsExpose(GWindow pixmap, CharView *cv, GRect *r) {
  733. GRect old;
  734. /* Note: If you change this ordering, change enum cvtools */
  735. static GImage *normbuttons[][2] = { { &GIcon_pointer, &GIcon_magnify },
  736. { &GIcon_freehand, &GIcon_hand },
  737. { &GIcon_knife, &GIcon_ruler },
  738. { &GIcon_pen, &GIcon_spirodisabled },
  739. { &GIcon_curve, &GIcon_hvcurve },
  740. { &GIcon_corner, &GIcon_tangent},
  741. { &GIcon_scale, &GIcon_rotate },
  742. { &GIcon_flip, &GIcon_skew },
  743. { &GIcon_3drotate, &GIcon_perspective },
  744. { &GIcon_rect, &GIcon_poly},
  745. { &GIcon_elipse, &GIcon_star}};
  746. static GImage *spirobuttons[][2] = { { &GIcon_pointer, &GIcon_magnify },
  747. { &GIcon_freehand, &GIcon_hand },
  748. { &GIcon_knife, &GIcon_ruler },
  749. { &GIcon_spiroright, &GIcon_spirodown },
  750. { &GIcon_spirocurve, &GIcon_spirog2curve },
  751. { &GIcon_spirocorner, &GIcon_spiroleft },
  752. { &GIcon_scale, &GIcon_rotate },
  753. { &GIcon_flip, &GIcon_skew },
  754. { &GIcon_3drotate, &GIcon_perspective },
  755. { &GIcon_rect, &GIcon_poly},
  756. { &GIcon_elipse, &GIcon_star}};
  757. static GImage *normsmalls[] = { &GIcon_smallpointer, &GIcon_smallmag,
  758. &GIcon_smallpencil, &GIcon_smallhand,
  759. &GIcon_smallknife, &GIcon_smallruler,
  760. &GIcon_smallpen, NULL,
  761. &GIcon_smallcurve, &GIcon_smallhvcurve,
  762. &GIcon_smallcorner, &GIcon_smalltangent,
  763. &GIcon_smallscale, &GIcon_smallrotate,
  764. &GIcon_smallflip, &GIcon_smallskew,
  765. &GIcon_small3drotate, &GIcon_smallperspective,
  766. &GIcon_smallrect, &GIcon_smallpoly,
  767. &GIcon_smallelipse, &GIcon_smallstar };
  768. static GImage *spirosmalls[] = { &GIcon_smallpointer, &GIcon_smallmag,
  769. &GIcon_smallpencil, &GIcon_smallhand,
  770. &GIcon_smallknife, &GIcon_smallruler,
  771. &GIcon_smallspiroright, NULL,
  772. &GIcon_smallspirocurve, &GIcon_smallspirog2curve,
  773. &GIcon_smallspirocorner, &GIcon_smallspiroleft,
  774. &GIcon_smallscale, &GIcon_smallrotate,
  775. &GIcon_smallflip, &GIcon_smallskew,
  776. &GIcon_small3drotate, &GIcon_smallperspective,
  777. &GIcon_smallrect, &GIcon_smallpoly,
  778. &GIcon_smallelipse, &GIcon_smallstar };
  779. static const unichar_t _Mouse[][9] = {
  780. { 'M', 's', 'e', '1', '\0' },
  781. { '^', 'M', 's', 'e', '1', '\0' },
  782. { 'M', 's', 'e', '2', '\0' },
  783. { '^', 'M', 's', 'e', '2', '\0' }};
  784. int i,j,norm, mi;
  785. int tool = cv->cntrldown?cv->cb1_tool:cv->b1_tool;
  786. int dither = GDrawSetDither(NULL,false);
  787. GRect temp;
  788. int canspiro = hasspiro(), inspiro = canspiro && cv->b.sc->inspiro;
  789. GImage *(*buttons)[2] = inspiro ? spirobuttons : normbuttons;
  790. GImage **smalls = inspiro ? spirosmalls : normsmalls;
  791. normbuttons[3][1] = canspiro ? &GIcon_spiroup : &GIcon_spirodisabled;
  792. GDrawPushClip(pixmap,r,&old);
  793. GDrawFillRect(pixmap,r,GDrawGetDefaultBackground(NULL));
  794. GDrawSetLineWidth(pixmap,0);
  795. for ( i=0; i<sizeof(normbuttons)/sizeof(normbuttons[0])-1; ++i ) for ( j=0; j<2; ++j ) {
  796. mi = i;
  797. if ( i==(cvt_rect)/2 && ((j==0 && rectelipse) || (j==1 && polystar)) )
  798. ++mi;
  799. /* if ( cv->b.sc->parent->order2 && buttons[mi][j]==&GIcon_freehand ) */
  800. /* GDrawDrawImage(pixmap,&GIcon_greyfree,NULL,j*27+1,i*27+1); */
  801. /* else */
  802. GDrawDrawImage(pixmap,buttons[mi][j],NULL,j*27+1,i*27+1);
  803. norm = (mi*2+j!=tool);
  804. {
  805. // These are from charview.c.
  806. extern int cvbutton3d; // Default 1.
  807. extern Color cvbutton3dedgelightcol; // Default 0xe0e0e0.
  808. extern Color cvbutton3dedgedarkcol; // Default 0x707070.
  809. if (cvbutton3d) {
  810. GDrawDrawLine(pixmap,j*27,i*27,j*27+25,i*27,norm?cvbutton3dedgelightcol:cvbutton3dedgedarkcol);
  811. GDrawDrawLine(pixmap,j*27,i*27,j*27,i*27+25,norm?cvbutton3dedgelightcol:cvbutton3dedgedarkcol);
  812. GDrawDrawLine(pixmap,j*27,i*27+25,j*27+25,i*27+25,norm?cvbutton3dedgedarkcol:cvbutton3dedgelightcol);
  813. GDrawDrawLine(pixmap,j*27+25,i*27,j*27+25,i*27+25,norm?cvbutton3dedgedarkcol:cvbutton3dedgelightcol);
  814. }
  815. }
  816. }
  817. GDrawSetFont(pixmap,toolsfont);
  818. temp.x = 52-16; temp.y = i*27; temp.width = 16; temp.height = 4*12;
  819. GDrawFillRect(pixmap,&temp,GDrawGetDefaultBackground(NULL));
  820. for ( j=0; j<4; ++j ) {
  821. GDrawDrawText(pixmap,2,i*27+j*12+10,(unichar_t *) _Mouse[j],-1,GDrawGetDefaultForeground(NULL));
  822. if ( (&cv->b1_tool)[j]!=cvt_none && smalls[(&cv->b1_tool)[j]])
  823. GDrawDrawImage(pixmap,smalls[(&cv->b1_tool)[j]],NULL,52-16,i*27+j*12);
  824. }
  825. GDrawPopClip(pixmap,&old);
  826. GDrawSetDither(NULL,dither);
  827. }
  828. int TrueCharState(GEvent *event) {
  829. int bit = 0;
  830. /* X doesn't set the state until after the event. I want the state to */
  831. /* reflect whatever key just got depressed/released */
  832. int keysym = event->u.chr.keysym;
  833. if ( keysym == GK_Caps_Lock || keysym == GK_Shift_Lock ) {
  834. static int set_on_last_down = false;
  835. /* caps lock is sticky and doesn't work like the other modifiers */
  836. /* but it is even worse. the bit seems to be set on key down, but */
  837. /* unset on key up. In other words on key up, the bit will always */
  838. /* set and we have no idea which way it will go. So we guess, and */
  839. /* if they haven't messed with the key outside ff we should be right */
  840. if ( event->type == et_char ) {
  841. set_on_last_down = (event->u.chr.state ^ ksm_capslock)& ksm_capslock;
  842. return( event->u.chr.state ^ ksm_capslock );
  843. } else if ( !(event->u.chr.state & ksm_capslock) || set_on_last_down )
  844. return( event->u.chr.state );
  845. else
  846. return( event->u.chr.state & ~ksm_capslock );
  847. }
  848. if ( keysym == GK_Meta_L || keysym == GK_Meta_R ||
  849. keysym == GK_Alt_L || keysym == GK_Alt_R )
  850. bit = ksm_meta;
  851. else if ( keysym == GK_Shift_L || keysym == GK_Shift_R )
  852. bit = ksm_shift;
  853. else if ( keysym == GK_Control_L || keysym == GK_Control_R )
  854. bit = ksm_control;
  855. else if ( keysym == GK_Super_L || keysym == GK_Super_L )
  856. bit = ksm_super;
  857. else if ( keysym == GK_Hyper_L || keysym == GK_Hyper_L )
  858. bit = ksm_hyper;
  859. else
  860. return( event->u.chr.state );
  861. if ( event->type == et_char )
  862. return( event->u.chr.state | bit );
  863. else
  864. return( event->u.chr.state & ~bit );
  865. }
  866. void CVToolsSetCursor(CharView *cv, int state, char *device) {
  867. int shouldshow;
  868. int cntrl;
  869. if ( tools[0] == ct_pointer ) {
  870. tools[cvt_pointer] = ct_mypointer;
  871. tools[cvt_magnify] = ct_magplus;
  872. tools[cvt_freehand] = ct_pencil;
  873. tools[cvt_hand] = ct_myhand;
  874. tools[cvt_curve] = ct_circle;
  875. tools[cvt_hvcurve] = ct_hvcircle;
  876. tools[cvt_corner] = ct_square;
  877. tools[cvt_tangent] = ct_triangle;
  878. tools[cvt_pen] = ct_pen;
  879. tools[cvt_knife] = ct_knife;
  880. tools[cvt_ruler] = ct_ruler;
  881. tools[cvt_scale] = ct_scale;
  882. tools[cvt_flip] = ct_flip;
  883. tools[cvt_rotate] = ct_rotate;
  884. tools[cvt_skew] = ct_skew;
  885. tools[cvt_3d_rotate] = ct_3drotate;
  886. tools[cvt_perspective] = ct_perspective;
  887. tools[cvt_rect] = ct_rect;
  888. tools[cvt_poly] = ct_poly;
  889. tools[cvt_elipse] = ct_elipse;
  890. tools[cvt_star] = ct_star;
  891. tools[cvt_minify] = ct_magminus;
  892. memcpy(spirotools,tools,sizeof(tools));
  893. spirotools[cvt_spirog2] = ct_g2circle;
  894. spirotools[cvt_spiroleft] = ct_spiroleft;
  895. spirotools[cvt_spiroright] = ct_spiroright;
  896. }
  897. shouldshow = cvt_none;
  898. if ( cv->active_tool!=cvt_none )
  899. shouldshow = cv->active_tool;
  900. else if ( cv->pressed_display!=cvt_none )
  901. shouldshow = cv->pressed_display;
  902. else if ( device==NULL || strcmp(device,"Mouse1")==0 ) {
  903. if ( (state&(ksm_shift|ksm_control)) && (state&ksm_button4))
  904. shouldshow = cvt_magnify;
  905. else if ( (state&(ksm_shift|ksm_control)) && (state&ksm_button5))
  906. shouldshow = cvt_minify;
  907. else if ( (state&ksm_control) && (state&(ksm_button2|ksm_super)) )
  908. shouldshow = cv->cb2_tool;
  909. else if ( (state&(ksm_button2|ksm_super)) )
  910. shouldshow = cv->b2_tool;
  911. else if ( (state&ksm_control) )
  912. shouldshow = cv->cb1_tool;
  913. else
  914. shouldshow = cv->b1_tool;
  915. } else if ( strcmp(device,"eraser")==0 )
  916. shouldshow = cv->er_tool;
  917. else if ( strcmp(device,"stylus")==0 ) {
  918. if ( (state&(ksm_button2|ksm_control|ksm_super)) )
  919. shouldshow = cv->s2_tool;
  920. else
  921. shouldshow = cv->s1_tool;
  922. }
  923. if ( shouldshow==cvt_magnify && (state&ksm_meta))
  924. shouldshow = cvt_minify;
  925. if ( shouldshow!=cv->showing_tool ) {
  926. CPEndInfo(cv);
  927. if ( cv->b.sc->inspiro && hasspiro()) {
  928. GDrawSetCursor(cv->v,spirotools[shouldshow]);
  929. if ( cvtools!=NULL ) /* Might happen if window owning docked palette destroyed */
  930. GDrawSetCursor(cvtools,spirotools[shouldshow]);
  931. } else {
  932. GDrawSetCursor(cv->v,tools[shouldshow]);
  933. if ( cvtools!=NULL ) /* Might happen if window owning docked palette destroyed */
  934. GDrawSetCursor(cvtools,tools[shouldshow]);
  935. }
  936. cv->showing_tool = shouldshow;
  937. }
  938. if ( device==NULL || strcmp(device,"stylus")==0 ) {
  939. cntrl = (state&ksm_control)?1:0;
  940. if ( device!=NULL && (state&ksm_button2))
  941. cntrl = true;
  942. if ( cntrl != cv->cntrldown ) {
  943. cv->cntrldown = cntrl;
  944. GDrawRequestExpose(cvtools,NULL,false);
  945. }
  946. }
  947. }
  948. static int CVCurrentTool(CharView *cv, GEvent *event) {
  949. if ( event->u.mouse.device!=NULL && strcmp(event->u.mouse.device,"eraser")==0 )
  950. return( cv->er_tool );
  951. else if ( event->u.mouse.device!=NULL && strcmp(event->u.mouse.device,"stylus")==0 ) {
  952. if ( event->u.mouse.button==2 )
  953. /* Only thing that matters is touch which maps to button 1 */;
  954. else if ( cv->had_control )
  955. return( cv->s2_tool );
  956. else
  957. return( cv->s1_tool );
  958. }
  959. if ( cv->had_control && event->u.mouse.button==2 )
  960. return( cv->cb2_tool );
  961. else if ( event->u.mouse.button==2 )
  962. return( cv->b2_tool );
  963. else if ( cv->had_control ) {
  964. return( cv->cb1_tool );
  965. } else {
  966. return( cv->b1_tool );
  967. }
  968. }
  969. static void SCCheckForSSToOptimize(SplineChar *sc, SplineSet *ss,int order2) {
  970. for ( ; ss!=NULL ; ss = ss->next ) {
  971. if ( ss->beziers_need_optimizer ) {
  972. SplineSetAddExtrema(sc,ss,ae_only_good,sc->parent->ascent+sc->parent->descent);
  973. ss->beziers_need_optimizer = false;
  974. }
  975. if ( order2 && ss->first->next!=NULL && !ss->first->next->order2 ) {
  976. SplineSet *temp = SSttfApprox(ss), foo;
  977. foo = *ss;
  978. ss->first = temp->first; ss->last = temp->last;
  979. temp->first = foo.first; temp->last = foo.last;
  980. SplinePointListFree(temp);
  981. }
  982. }
  983. }
  984. static void CVChangeSpiroMode(CharView *cv) {
  985. if ( hasspiro() ) {
  986. cv->b.sc->inspiro = !cv->b.sc->inspiro;
  987. cv->showing_tool = cvt_none;
  988. CVClearSel(cv);
  989. if ( !cv->b.sc->inspiro )
  990. SCCheckForSSToOptimize(cv->b.sc,cv->b.layerheads[cv->b.drawmode]->splines,
  991. cv->b.layerheads[cv->b.drawmode]->order2);
  992. GDrawRequestExpose(cvtools,NULL,false);
  993. SCUpdateAll(cv->b.sc);
  994. } else
  995. #ifdef _NO_LIBSPIRO
  996. ff_post_error(_("You may not use spiros"),_("This version of fontforge was not linked with the spiro library, so you may not use them."));
  997. #else
  998. ff_post_error(_("You may not use spiros"),_("FontForge was unable to load libspiro, spiros are not available for use."));
  999. #endif
  1000. }
  1001. char* HKTextInfoToUntranslatedTextFromTextInfo( GTextInfo* ti ); // From ../gdraw/gmenu.c.
  1002. static void ToolsMouse(CharView *cv, GEvent *event) {
  1003. int i = (event->u.mouse.y/27), j = (event->u.mouse.x/27), mi=i;
  1004. int pos;
  1005. int isstylus = event->u.mouse.device!=NULL && strcmp(event->u.mouse.device,"stylus")==0;
  1006. int styluscntl = isstylus && (event->u.mouse.state&0x200);
  1007. static int settings[2];
  1008. if(j >= 2)
  1009. return; /* If the wm gave me a window the wrong size */
  1010. if ( i==(cvt_rect)/2 ) {
  1011. int current = CVCurrentTool(cv,event);
  1012. int changed = false;
  1013. if ( event->type == et_mousedown && event->u.mouse.clicks>=2 ) {
  1014. rectelipse = settings[0];
  1015. polystar = settings[1];
  1016. } else if ( event->type == et_mousedown ) {
  1017. settings[0] = rectelipse; settings[1] = polystar;
  1018. /* A double click will change the type twice, which leaves it where it was, which is desired */
  1019. if ( j==0 && ((!rectelipse && current==cvt_rect) || (rectelipse && current==cvt_elipse)) ) {
  1020. rectelipse = !rectelipse;
  1021. changed = true;
  1022. } else if (j==1 && ((!polystar && current==cvt_poly) || (polystar && current==cvt_star)) ) {
  1023. polystar = !polystar;
  1024. changed = true;
  1025. }
  1026. if ( changed ) {
  1027. SavePrefs(true);
  1028. GDrawRequestExpose(cvtools,NULL,false);
  1029. }
  1030. }
  1031. if ( (j==0 && rectelipse) || (j==1 && polystar) )
  1032. ++mi;
  1033. }
  1034. pos = mi*2 + j;
  1035. GGadgetEndPopup();
  1036. /* we have two fewer buttons than commands as two bottons each control two commands */
  1037. if ( pos<0 || pos>=cvt_max )
  1038. pos = cvt_none;
  1039. if ( event->type == et_mousedown ) {
  1040. if ( isstylus && event->u.mouse.button==2 )
  1041. /* Not a real button press, only touch counts. This is a modifier */;
  1042. else if ( pos==cvt_spiro ) {
  1043. CVChangeSpiroMode(cv);
  1044. /* This is just a button that indicates a state */
  1045. } else {
  1046. cv->pressed_tool = cv->pressed_display = pos;
  1047. cv->had_control = ((event->u.mouse.state&ksm_control) || styluscntl)?1:0;
  1048. event->u.mouse.state |= (1<<(7+event->u.mouse.button));
  1049. }
  1050. if ( event->u.mouse.clicks>=2 &&
  1051. (pos/2 == cvt_scale/2 || pos/2 == cvt_rotate/2 || pos == cvt_3d_rotate ))
  1052. CVDoTransform(cv,pos);
  1053. } else if ( event->type == et_mousemove ) {
  1054. if ( cv->pressed_tool==cvt_none && pos!=cvt_none ) {
  1055. /* Not pressed */
  1056. char *msg = _(popupsres[pos]);
  1057. if ( cv->b.sc->inspiro && hasspiro()) {
  1058. if ( pos==cvt_spirog2 )
  1059. msg = _("Add a g2 curve point");
  1060. else if ( pos==cvt_spiroleft )
  1061. msg = _("Add a prev constraint point (sometimes like a tangent)");
  1062. else if ( pos==cvt_spiroright )
  1063. msg = _("Add a next constraint point (sometimes like a tangent)");
  1064. }
  1065. // We want to display the hotkey for the key in question if possible.
  1066. char * mininame = HKTextInfoToUntranslatedTextFromTextInfo(&cvtoollist[pos].ti);
  1067. char * menuname = NULL;
  1068. Hotkey* toolhotkey = NULL;
  1069. if (mininame != NULL) {
  1070. if (asprintf(&menuname, "%s%s", "Point.Tools.", mininame) != -1) {
  1071. toolhotkey = hotkeyFindByMenuPath(cv->gw, menuname);
  1072. free(menuname); menuname = NULL;
  1073. }
  1074. free(mininame); mininame = NULL;
  1075. }
  1076. char * finalmsg = NULL;
  1077. if (toolhotkey != NULL && asprintf(&finalmsg, "%s (%s)", msg, toolhotkey->text) != -1) {
  1078. GGadgetPreparePopup8(cvtools, finalmsg);
  1079. free(finalmsg); finalmsg = NULL;
  1080. } else GGadgetPreparePopup8(cvtools, msg); // That's what we were doing before. Much simpler.
  1081. } else if ( pos!=cv->pressed_tool || cv->had_control != (((event->u.mouse.state&ksm_control) || styluscntl)?1:0) )
  1082. cv->pressed_display = cvt_none;
  1083. else
  1084. cv->pressed_display = cv->pressed_tool;
  1085. } else if ( event->type == et_mouseup ) {
  1086. if ( pos==cvt_freehand && event->u.mouse.clicks==2 ) {
  1087. FreeHandStrokeDlg(&expand);
  1088. } else if ( pos==cvt_pointer && event->u.mouse.clicks==2 ) {
  1089. PointerDlg(cv);
  1090. } else if ( pos==cvt_ruler && event->u.mouse.clicks==2 ) {
  1091. RulerDlg(cv);
  1092. } else if ( i==cvt_rect/2 && event->u.mouse.clicks==2 ) {
  1093. ((j==0)?CVRectElipse:CVPolyStar)(cv);
  1094. mi = i;
  1095. if ( (j==0 && rectelipse) || (j==1 && polystar) )
  1096. ++mi;
  1097. pos = mi*2 + j;
  1098. cv->pressed_tool = cv->pressed_display = pos;
  1099. }
  1100. if ( pos!=cv->pressed_tool || cv->had_control != (((event->u.mouse.state&ksm_control)||styluscntl)?1:0) )
  1101. cv->pressed_tool = cv->pressed_display = cvt_none;
  1102. else {
  1103. if ( event->u.mouse.device!=NULL && strcmp(event->u.mouse.device,"eraser")==0 )
  1104. cv->er_tool = pos;
  1105. else if ( isstylus ) {
  1106. if ( event->u.mouse.button==2 )
  1107. /* Only thing that matters is touch which maps to button 1 */;
  1108. else if ( cv->had_control )
  1109. cv->s2_tool = pos;
  1110. else
  1111. cv->s1_tool = pos;
  1112. } else if ( cv->had_control && event->u.mouse.button==2 )
  1113. cv->cb2_tool = cv_cb2_tool = pos;
  1114. else if ( event->u.mouse.button==2 )
  1115. cv->b2_tool = cv_b2_tool = pos;
  1116. else if ( cv->had_control ) {
  1117. cv->cb1_tool = cv_cb1_tool = pos;
  1118. } else {
  1119. cv->b1_tool = cv_b1_tool = pos;
  1120. }
  1121. SavePrefs(true);
  1122. cv->pressed_tool = cv->pressed_display = cvt_none;
  1123. }
  1124. GDrawRequestExpose(cvtools,NULL,false);
  1125. event->u.chr.state &= ~(1<<(7+event->u.mouse.button));
  1126. }
  1127. CVToolsSetCursor(cv,event->u.mouse.state,event->u.mouse.device);
  1128. }
  1129. static void PostCharToWindow(GWindow to, GEvent *e) {
  1130. GPoint p;
  1131. p.x = e->u.chr.x; p.y = e->u.chr.y;
  1132. GDrawTranslateCoordinates(e->w,to,&p);
  1133. e->u.chr.x = p.x; e->u.chr.y = p.y;
  1134. e->w = to;
  1135. GDrawPostEvent(e);
  1136. }
  1137. static int cvtools_e_h(GWindow gw, GEvent *event) {
  1138. CharView *cv = (CharView *) GDrawGetUserData(gw);
  1139. if ( event->type==et_destroy ) {
  1140. cvtools = NULL;
  1141. return( true );
  1142. }
  1143. if ( cv==NULL )
  1144. return( true );
  1145. GGadgetPopupExternalEvent(event);
  1146. switch ( event->type ) {
  1147. case et_expose:
  1148. ToolsExpose(gw,cv,&event->u.expose.rect);
  1149. break;
  1150. case et_mousedown:
  1151. ToolsMouse(cv,event);
  1152. break;
  1153. case et_mousemove:
  1154. ToolsMouse(cv,event);
  1155. break;
  1156. case et_mouseup:
  1157. ToolsMouse(cv,event);
  1158. break;
  1159. case et_crossing:
  1160. cv->pressed_display = cvt_none;
  1161. CVToolsSetCursor(cv,event->u.mouse.state,NULL);
  1162. break;
  1163. case et_char: case et_charup:
  1164. if ( cv->had_control != ((event->u.chr.state&ksm_control)?1:0) )
  1165. cv->pressed_display = cvt_none;
  1166. PostCharToWindow(cv->gw,event);
  1167. break;
  1168. case et_close:
  1169. GDrawSetVisible(gw,false);
  1170. break;
  1171. }
  1172. return( true );
  1173. }
  1174. GWindow CVMakeTools(CharView *cv) {
  1175. GRect r;
  1176. GWindowAttrs wattrs;
  1177. FontRequest rq;
  1178. if ( cvtools!=NULL )
  1179. return( cvtools );
  1180. memset(&wattrs,0,sizeof(wattrs));
  1181. wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_positioned|wam_isdlg;
  1182. wattrs.event_masks = -1;
  1183. wattrs.cursor = ct_mypointer;
  1184. wattrs.positioned = true;
  1185. wattrs.is_dlg = true;
  1186. wattrs.utf8_window_title = _("Tools");
  1187. r.width = CV_TOOLS_WIDTH; r.height = CV_TOOLS_HEIGHT;
  1188. if ( cvtoolsoff.x==-9999 ) {
  1189. cvtoolsoff.x = -r.width-6; cvtoolsoff.y = cv->mbh+20;
  1190. }
  1191. r.x = cvtoolsoff.x; r.y = cvtoolsoff.y;
  1192. if ( palettes_docked )
  1193. r.x = r.y = 0;
  1194. cvtools = CreatePalette( cv->gw, &r, cvtools_e_h, NULL, &wattrs, cv->v );
  1195. if ( GDrawRequestDeviceEvents(cvtools,input_em_cnt,input_em)>0 ) {
  1196. /* Success! They've got a wacom tablet */
  1197. }
  1198. if ( toolsfont==NULL ) {
  1199. memset(&rq,0,sizeof(rq));
  1200. rq.utf8_family_name = SANS_UI_FAMILIES;
  1201. rq.point_size = -10;
  1202. rq.weight = 400;
  1203. toolsfont = GDrawInstanciateFont(NULL,&rq);
  1204. toolsfont = GResourceFindFont("ToolsPalette.Font",toolsfont);
  1205. }
  1206. if ( cvvisible[1])
  1207. GDrawSetVisible(cvtools,true);
  1208. return( cvtools );
  1209. }
  1210. /* ********************************************************* */
  1211. /* ****************** Layers Palette ********************* */
  1212. /* ********************************************************* */
  1213. /* Create a layer thumbnail */
  1214. static BDFChar *BDFCharFromLayer(SplineChar *sc,int layer) {
  1215. SplineChar dummy;
  1216. memset(&dummy,0,sizeof(dummy));
  1217. dummy.layer_cnt = 2;
  1218. dummy.layers = sc->layers+layer-1;
  1219. dummy.parent = sc->parent;
  1220. return( SplineCharAntiAlias(&dummy,ly_fore,24,4));
  1221. }
  1222. /* Update the type3 layers palette to the given character view */
  1223. static void CVLayers2Set(CharView *cv) {
  1224. int i, top;
  1225. GGadgetSetChecked(GWidgetGetControl(cvlayers2,CID_VFore),cv->showfore);
  1226. GGadgetSetChecked(GWidgetGetControl(cvlayers2,CID_VBack),cv->showback[0]&1);
  1227. GGadgetSetChecked(GWidgetGetControl(cvlayers2,CID_VGrid),cv->showgrids);
  1228. int ly = 0;
  1229. // We want to look at the unhandled layers.
  1230. if (ly <= ly_back) ly = ly_back + 1;
  1231. if (ly <= ly_fore) ly = ly_fore + 1;
  1232. if (ly <= ly_grid) ly = ly_grid + 1;
  1233. while (ly < cv->b.sc->parent->layer_cnt) {
  1234. GGadget *tmpgadget = GWidgetGetControl(cvlayers2, CID_VBase + ly);
  1235. if (tmpgadget != NULL) {
  1236. // We set a low cap on the number of layers provisioned with check boxes for safety.
  1237. // So it is important to check that this exists.
  1238. GGadgetSetChecked(tmpgadget, cv->showback[ly>>5]&(1<<(ly&31)));
  1239. }
  1240. ly ++;
  1241. }
  1242. /* set old to NULL */
  1243. layer2.offtop = 0;
  1244. for ( i=2; i<layer2.current_layers; ++i ) {
  1245. BDFCharFree(layer2.layers[i]);
  1246. layer2.layers[i]=NULL;
  1247. }
  1248. /* reallocate enough space if necessary */
  1249. if ( cv->b.sc->layer_cnt+1>=layer2.max_layers ) {
  1250. top = cv->b.sc->layer_cnt+10;
  1251. if ( layer2.layers==NULL )
  1252. layer2.layers = calloc(top,sizeof(BDFChar *));
  1253. else {
  1254. layer2.layers = realloc(layer2.layers,top*sizeof(BDFChar *));
  1255. for ( i=layer2.current_layers; i<top; ++i )
  1256. layer2.layers[i] = NULL;
  1257. }
  1258. layer2.max_layers = top;
  1259. }
  1260. layer2.current_layers = cv->b.sc->layer_cnt+1;
  1261. for ( i=ly_fore; i<cv->b.sc->layer_cnt; ++i )
  1262. layer2.layers[i+1] = BDFCharFromLayer(cv->b.sc,i);
  1263. layer2.active = CVLayer(&cv->b)+1;
  1264. GScrollBarSetBounds(GWidgetGetControl(cvlayers2,CID_SB),0,cv->b.sc->layer_cnt+1-2,
  1265. CV_LAYERS2_VISLAYERS);
  1266. if ( layer2.offtop>cv->b.sc->layer_cnt-1-CV_LAYERS2_VISLAYERS )
  1267. layer2.offtop = cv->b.sc->layer_cnt-1-CV_LAYERS2_VISLAYERS;
  1268. if ( layer2.offtop<0 ) layer2.offtop = 0;
  1269. GScrollBarSetPos(GWidgetGetControl(cvlayers2,CID_SB),layer2.offtop);
  1270. GDrawRequestExpose(cvlayers2,NULL,false);
  1271. }
  1272. static void Layers2Expose(CharView *cv,GWindow pixmap,GEvent *event) {
  1273. int i, ll;
  1274. const char *str;
  1275. GRect r;
  1276. struct _GImage base;
  1277. GImage gi;
  1278. int as = (24*cv->b.sc->parent->ascent)/(cv->b.sc->parent->ascent+cv->b.sc->parent->descent);
  1279. if ( event->u.expose.rect.y+event->u.expose.rect.height<CV_LAYERS2_HEADER_HEIGHT )
  1280. return;
  1281. r.x = 30; r.width = layer2.sb_start-r.x;
  1282. r.y = CV_LAYERS2_HEADER_HEIGHT;
  1283. r.height = CV_LAYERS2_LINE_HEIGHT-CV_LAYERS2_HEADER_HEIGHT;
  1284. GDrawFillRect(pixmap,&r,GDrawGetDefaultBackground(NULL));
  1285. GDrawSetDither(NULL, false); /* on 8 bit displays we don't want any dithering */
  1286. memset(&gi,0,sizeof(gi));
  1287. memset(&base,0,sizeof(base));
  1288. gi.u.image = &base;
  1289. base.image_type = it_index;
  1290. base.clut = layer2.clut;
  1291. base.trans = -1;
  1292. GDrawSetFont(pixmap,layer2.font);
  1293. for ( i=(event->u.expose.rect.y-CV_LAYERS2_HEADER_HEIGHT)/CV_LAYERS2_LINE_HEIGHT;
  1294. i<(event->u.expose.rect.y+event->u.expose.rect.height+CV_LAYERS2_LINE_HEIGHT-1-CV_LAYERS2_HEADER_HEIGHT)/CV_LAYERS2_LINE_HEIGHT;
  1295. ++i ) {
  1296. ll = i<2 ? i : i+layer2.offtop;
  1297. if ( ll==layer2.active ) {
  1298. r.x = 30; r.width = layer2.sb_start-r.x;
  1299. r.y = CV_LAYERS2_HEADER_HEIGHT + i*CV_LAYERS2_LINE_HEIGHT;
  1300. r.height = CV_LAYERS2_LINE_HEIGHT;
  1301. GDrawFillRect(pixmap,&r,GDrawGetDefaultForeground(NULL));
  1302. }
  1303. GDrawDrawLine(pixmap,r.x,CV_LAYERS2_HEADER_HEIGHT+i*CV_LAYERS2_LINE_HEIGHT,
  1304. r.x+r.width,CV_LAYERS2_HEADER_HEIGHT+i*CV_LAYERS2_LINE_HEIGHT,
  1305. 0x808080);
  1306. if ( i==0 || i==1 ) {
  1307. str = i==0?_("Guide") : _("Back");
  1308. GDrawDrawText8(pixmap,r.x+2,CV_LAYERS2_HEADER_HEIGHT + i*CV_LAYERS2_LINE_HEIGHT + (CV_LAYERS2_LINE_HEIGHT-12)/2+12,
  1309. (char *) str,-1,ll==layer2.active?0xffffff:GDrawGetDefaultForeground(NULL));
  1310. } else if ( layer2.offtop+i>=layer2.current_layers ) {
  1311. break;
  1312. } else if ( layer2.layers[layer2.offtop+i]!=NULL ) {
  1313. #if 0
  1314. // This is currently broken, and we do not have time to fix it.
  1315. BDFChar *bdfc = layer2.layers[layer2.offtop+i];
  1316. base.data = bdfc->bitmap;
  1317. base.bytes_per_line = bdfc->bytes_per_line;
  1318. base.width = bdfc->xmax-bdfc->xmin+1;
  1319. base.height = bdfc->ymax-bdfc->ymin+1;
  1320. GDrawDrawImage(pixmap,&gi,NULL,
  1321. r.x+2+bdfc->xmin,
  1322. CV_LAYERS2_HEADER_HEIGHT + i*CV_LAYERS2_LINE_HEIGHT+as-bdfc->ymax);
  1323. #else
  1324. // This logic comes from CVInfoDrawText.
  1325. const int layernamesz = 100;
  1326. char layername[layernamesz+1];
  1327. strncpy(layername,_("Guide"),layernamesz);
  1328. int idx = layer2.offtop+i-1;
  1329. if(idx >= 0 && idx < cv->b.sc->parent->layer_cnt) {
  1330. strncpy(layername,cv->b.sc->parent->layers[idx].name,layernamesz);
  1331. } else {
  1332. fprintf(stderr, "Invalid layer!\n");
  1333. }
  1334. // And this comes from above.
  1335. GDrawDrawText8(pixmap,r.x+2,CV_LAYERS2_HEADER_HEIGHT + i*CV_LAYERS2_LINE_HEIGHT + (CV_LAYERS2_LINE_HEIGHT-12)/2+12,
  1336. (char *) layername,-1,ll==layer2.active?0xffffff:GDrawGetDefaultForeground(NULL));
  1337. #endif // 0
  1338. }
  1339. }
  1340. }
  1341. // Frank changed the prefix from MID to MIDL in order to avert conflicts with values set in charview_private.h.
  1342. #define MIDL_LayerInfo 1
  1343. #define MIDL_NewLayer 2
  1344. #define MIDL_DelLayer 3
  1345. #define MIDL_First 4
  1346. #define MIDL_Earlier 5
  1347. #define MIDL_Later 6
  1348. #define MIDL_Last 7
  1349. #define MIDL_MakeLine 100
  1350. #define MIDL_MakeArc 200
  1351. #define MIDL_InsertPtOnSplineAt 2309
  1352. #define MIDL_NamePoint 2318
  1353. #define MIDL_NameContour 2319
  1354. static void CVLayer2Invoked(GWindow v, GMenuItem *mi, GEvent *e) {
  1355. CharView *cv = (CharView *) GDrawGetUserData(v);
  1356. Layer temp;
  1357. int layer = CVLayer(&cv->b);
  1358. SplineChar *sc = cv->b.sc;
  1359. int i;
  1360. char *buts[3];
  1361. buts[0] = _("_Yes"); buts[1]=_("_No"); buts[2] = NULL;
  1362. switch ( mi->mid ) {
  1363. case MIDL_LayerInfo:
  1364. if ( !LayerDialog(cv->b.layerheads[cv->b.drawmode],cv->b.sc->parent))
  1365. return;
  1366. break;
  1367. case MIDL_NewLayer:
  1368. LayerDefault(&temp);
  1369. if ( !LayerDialog(&temp,cv->b.sc->parent))
  1370. return;
  1371. sc->layers = realloc(sc->layers,(sc->layer_cnt+1)*sizeof(Layer));
  1372. sc->layers[sc->layer_cnt] = temp;
  1373. cv->b.layerheads[dm_fore] = &sc->layers[sc->layer_cnt];
  1374. cv->b.layerheads[dm_back] = &sc->layers[ly_back];
  1375. ++sc->layer_cnt;
  1376. break;
  1377. case MIDL_DelLayer:
  1378. if ( sc->layer_cnt==2 ) /* May not delete the last foreground layer */
  1379. return;
  1380. if ( gwwv_ask(_("Cannot Be Undone"),(const char **) buts,0,1,_("This operation cannot be undone, do it anyway?"))==1 )
  1381. return;
  1382. SplinePointListsFree(sc->layers[layer].splines);
  1383. RefCharsFree(sc->layers[layer].refs);
  1384. ImageListsFree(sc->layers[layer].images);
  1385. UndoesFree(sc->layers[layer].undoes);
  1386. UndoesFree(sc->layers[layer].redoes);
  1387. for ( i=layer+1; i<sc->layer_cnt; ++i )
  1388. sc->layers[i-1] = sc->layers[i];
  1389. --sc->layer_cnt;
  1390. if ( layer==sc->layer_cnt )
  1391. cv->b.layerheads[dm_fore] = &sc->layers[layer-1];
  1392. break;
  1393. case MIDL_First:
  1394. if ( layer==ly_fore )
  1395. return;
  1396. temp = sc->layers[layer];
  1397. for ( i=layer-1; i>=ly_fore; --i )
  1398. sc->layers[i+1] = sc->layers[i];
  1399. sc->layers[i+1] = temp;
  1400. cv->b.layerheads[dm_fore] = &sc->layers[ly_fore];
  1401. break;
  1402. case MIDL_Earlier:
  1403. if ( layer==ly_fore )
  1404. return;
  1405. temp = sc->layers[layer];
  1406. sc->layers[layer] = sc->layers[layer-1];
  1407. sc->layers[layer-1] = temp;
  1408. cv->b.layerheads[dm_fore] = &sc->layers[layer-1];
  1409. break;
  1410. case MIDL_Later:
  1411. if ( layer==sc->layer_cnt-1 )
  1412. return;
  1413. temp = sc->layers[layer];
  1414. sc->layers[layer] = sc->layers[layer+1];
  1415. sc->layers[layer+1] = temp;
  1416. cv->b.layerheads[dm_fore] = &sc->layers[layer+1];
  1417. break;
  1418. case MIDL_Last:
  1419. if ( layer==sc->layer_cnt-1 )
  1420. return;
  1421. temp = sc->layers[layer];
  1422. for ( i=layer+1; i<sc->layer_cnt; ++i )
  1423. sc->layers[i-1] = sc->layers[i];
  1424. sc->layers[i-1] = temp;
  1425. cv->b.layerheads[dm_fore] = &sc->layers[i-1];
  1426. break;
  1427. }
  1428. CVLayers2Set(cv);
  1429. CVCharChangedUpdate(&cv->b);
  1430. }
  1431. static void Layer2Menu(CharView *cv,GEvent *event, int nolayer) {
  1432. GMenuItem mi[20];
  1433. int i;
  1434. static char *names[] = { N_("Layer Info..."), N_("New Layer..."), N_("Del Layer"), (char *) -1,
  1435. N_("_First"), N_("_Earlier"), N_("L_ater"), N_("_Last"), NULL };
  1436. static int mids[] = { MIDL_LayerInfo, MIDL_NewLayer, MIDL_DelLayer, -1,
  1437. MIDL_First, MIDL_Earlier, MIDL_Later, MIDL_Last, 0 };
  1438. int layer = CVLayer(&cv->b);
  1439. memset(mi,'\0',sizeof(mi));
  1440. for ( i=0; names[i]!=0; ++i ) {
  1441. if ( names[i]!=(char *) -1 ) {
  1442. mi[i].ti.text = (unichar_t *) _(names[i]);
  1443. mi[i].ti.text_is_1byte = true;
  1444. } else
  1445. mi[i].ti.line = true;
  1446. mi[i].ti.fg = COLOR_DEFAULT;
  1447. mi[i].ti.bg = COLOR_DEFAULT;
  1448. mi[i].mid = mids[i];
  1449. mi[i].invoke = CVLayer2Invoked;
  1450. if ( mids[i]!=MIDL_NewLayer && nolayer )
  1451. mi[i].ti.disabled = true;
  1452. if (( mids[i]==MIDL_First || mids[i]==MIDL_Earlier ) && layer==ly_fore )
  1453. mi[i].ti.disabled = true;
  1454. if (( mids[i]==MIDL_Last || mids[i]==MIDL_Later ) && layer==cv->b.sc->layer_cnt-1 )
  1455. mi[i].ti.disabled = true;
  1456. if ( mids[i]==MIDL_DelLayer && cv->b.sc->layer_cnt==2 )
  1457. mi[i].ti.disabled = true;
  1458. }
  1459. GMenuCreatePopupMenu(cvlayers2,event, mi);
  1460. }
  1461. static void Layer2Scroll(CharView *cv, GEvent *event) {
  1462. int off = 0;
  1463. enum sb sbt = event->u.control.u.sb.type;
  1464. if ( sbt==et_sb_top )
  1465. off = 0;
  1466. else if ( sbt==et_sb_bottom )
  1467. off = cv->b.sc->layer_cnt-1-CV_LAYERS2_VISLAYERS;
  1468. else if ( sbt==et_sb_up ) {
  1469. off = layer2.offtop-1;
  1470. } else if ( sbt==et_sb_down ) {
  1471. off = layer2.offtop+1;
  1472. } else if ( sbt==et_sb_uppage ) {
  1473. off = layer2.offtop-CV_LAYERS2_VISLAYERS+1;
  1474. } else if ( sbt==et_sb_downpage ) {
  1475. off = layer2.offtop+CV_LAYERS2_VISLAYERS-1;
  1476. } else /* if ( sbt==et_sb_thumb || sbt==et_sb_thumbrelease ) */ {
  1477. off = event->u.control.u.sb.pos;
  1478. }
  1479. if ( off>cv->b.sc->layer_cnt-1-CV_LAYERS2_VISLAYERS )
  1480. off = cv->b.sc->layer_cnt-1-CV_LAYERS2_VISLAYERS;
  1481. if ( off<0 ) off=0;
  1482. if ( off==layer2.offtop )
  1483. return;
  1484. layer2.offtop = off;
  1485. GScrollBarSetPos(GWidgetGetControl(cvlayers2,CID_SB),off);
  1486. GDrawRequestExpose(cvlayers2,NULL,false);
  1487. }
  1488. static int cvlayers2_e_h(GWindow gw, GEvent *event) {
  1489. CharView *cv = (CharView *) GDrawGetUserData(gw);
  1490. if ( event->type==et_destroy ) {
  1491. cvlayers2 = NULL;
  1492. return( true );
  1493. }
  1494. if ( cv==NULL )
  1495. return( true );
  1496. switch ( event->type ) {
  1497. case et_close:
  1498. GDrawSetVisible(gw,false);
  1499. break;
  1500. case et_char: case et_charup:
  1501. PostCharToWindow(cv->gw,event);
  1502. break;
  1503. case et_expose:
  1504. Layers2Expose(cv,gw,event);
  1505. break;
  1506. case et_mousedown: {
  1507. int layer = (event->u.mouse.y-CV_LAYERS2_HEADER_HEIGHT)/CV_LAYERS2_LINE_HEIGHT;
  1508. if ( event->u.mouse.y>CV_LAYERS2_HEADER_HEIGHT ) {
  1509. if ( layer<2 ) {
  1510. cv->b.drawmode = layer==0 ? dm_grid : dm_back;
  1511. layer2.active = layer;
  1512. } else if ( layer-1+layer2.offtop >= cv->b.sc->layer_cnt ) {
  1513. if ( event->u.mouse.button==3 )
  1514. Layer2Menu(cv,event,true);
  1515. else
  1516. GDrawBeep(NULL);
  1517. return(true);
  1518. } else {
  1519. layer2.active = layer+layer2.offtop;
  1520. cv->b.drawmode = dm_fore;
  1521. cv->b.layerheads[dm_fore] = &cv->b.sc->layers[layer-1+layer2.offtop];
  1522. }
  1523. GDrawRequestExpose(cvlayers2,NULL,false);
  1524. GDrawRequestExpose(cv->v,NULL,false);
  1525. GDrawRequestExpose(cv->gw,NULL,false); /* the logo (where the scrollbars join) shows what layer we are in */
  1526. if ( event->u.mouse.button==3 )
  1527. Layer2Menu(cv,event,cv->b.drawmode!=dm_fore);
  1528. else if ( event->u.mouse.clicks==2 && cv->b.drawmode==dm_fore ) {
  1529. if ( LayerDialog(cv->b.layerheads[cv->b.drawmode],cv->b.sc->parent))
  1530. CVCharChangedUpdate(&cv->b);
  1531. }
  1532. }
  1533. } break;
  1534. case et_controlevent:
  1535. if ( event->u.control.subtype == et_radiochanged ) {
  1536. enum drawmode dm = cv->b.drawmode;
  1537. int tmpcid = -1;
  1538. int tmplayer = -1;
  1539. switch(GGadgetGetCid(event->u.control.g)) {
  1540. case CID_VFore:
  1541. CVShows.showfore = cv->showfore = GGadgetIsChecked(event->u.control.g);
  1542. if ( CVShows.showback )
  1543. cv->showback[0] |= 2;
  1544. else
  1545. cv->showback[0] &= ~2;
  1546. break;
  1547. case CID_VBack:
  1548. CVShows.showback = GGadgetIsChecked(event->u.control.g);
  1549. if ( CVShows.showback )
  1550. cv->showback[0] |= 1;
  1551. else
  1552. cv->showback[0] &= ~1;
  1553. cv->back_img_out_of_date = true;
  1554. break;
  1555. case CID_VGrid:
  1556. CVShows.showgrids = cv->showgrids = GGadgetIsChecked(event->u.control.g);
  1557. break;
  1558. default:
  1559. tmpcid = GGadgetGetCid(event->u.control.g);
  1560. tmplayer = tmpcid - CID_VBase;
  1561. if (tmpcid < 0 || tmplayer < 0) break;
  1562. // We check that the layer is valid (since the code does not presently, as far as Frank knows, handle layer deletion).
  1563. // We also check that the CID is within the allocated range (although this may not be necessary since the checkbox would not exist otherwise).
  1564. if (tmplayer > 0 && tmplayer < 999 && tmplayer < cv->b.sc->parent->layer_cnt) {
  1565. if (GGadgetIsChecked(event->u.control.g)) {
  1566. cv->showback[tmplayer>>5]|=(1<<(tmplayer&31));
  1567. } else {
  1568. cv->showback[tmplayer>>5]&=~(1<<(tmplayer&31));
  1569. }
  1570. }
  1571. break;
  1572. }
  1573. GDrawRequestExpose(cv->v,NULL,false);
  1574. if ( dm!=cv->b.drawmode )
  1575. GDrawRequestExpose(cv->gw,NULL,false); /* the logo (where the scrollbars join) shows what layer we are in */
  1576. } else
  1577. Layer2Scroll(cv,event);
  1578. break;
  1579. }
  1580. return( true );
  1581. }
  1582. /* This is used for Type 3 fonts. CVMakeLayers is used for other fonts. */
  1583. static void CVMakeLayers2(CharView *cv) {
  1584. GRect r;
  1585. GWindowAttrs wattrs;
  1586. GGadgetCreateData gcd[25];
  1587. GTextInfo label[25];
  1588. static GBox radio_box = { bt_none, bs_rect, 0, 0, 0, 0, 0, 0, 0, 0, COLOR_DEFAULT, COLOR_DEFAULT, 0, 0, 0, 0, 0, 0, 0 };
  1589. FontRequest rq;
  1590. int i;
  1591. extern int _GScrollBar_Width;
  1592. if ( layer2.clut==NULL )
  1593. layer2.clut = _BDFClut(4);
  1594. if ( cvlayers2!=NULL )
  1595. return;
  1596. memset(&wattrs,0,sizeof(wattrs));
  1597. wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_positioned|wam_isdlg;
  1598. wattrs.event_masks = -1;
  1599. wattrs.cursor = ct_mypointer;
  1600. wattrs.positioned = true;
  1601. wattrs.is_dlg = true;
  1602. wattrs.utf8_window_title = _("Layers");
  1603. r.width = GGadgetScale(CV_LAYERS2_WIDTH); r.height = CV_LAYERS2_HEIGHT;
  1604. if ( cvlayersoff.x==-9999 ) {
  1605. cvlayersoff.x = -r.width-6;
  1606. cvlayersoff.y = cv->mbh+CV_TOOLS_HEIGHT+45/*25*/; /* 45 is right if there's decor, 25 when none. twm gives none, kde gives decor */
  1607. }
  1608. r.x = cvlayersoff.x; r.y = cvlayersoff.y;
  1609. if ( palettes_docked ) { r.x = 0; r.y=CV_TOOLS_HEIGHT+2; }
  1610. cvlayers2 = CreatePalette( cv->gw, &r, cvlayers2_e_h, NULL, &wattrs, cv->v );
  1611. memset(&label,0,sizeof(label));
  1612. memset(&gcd,0,sizeof(gcd));
  1613. if ( layersfont==NULL ) {
  1614. memset(&rq,'\0',sizeof(rq));
  1615. rq.utf8_family_name = SANS_UI_FAMILIES;
  1616. rq.point_size = -12;
  1617. rq.weight = 400;
  1618. layersfont = GDrawInstanciateFont(cvlayers2,&rq);
  1619. layersfont = GResourceFindFont("LayersPalette.Font",layersfont);
  1620. }
  1621. for ( i=0; i<sizeof(label)/sizeof(label[0]); ++i )
  1622. label[i].font = layersfont;
  1623. layer2.font = layersfont;
  1624. gcd[0].gd.pos.width = GDrawPointsToPixels(cv->gw,_GScrollBar_Width);
  1625. gcd[0].gd.pos.x = CV_LAYERS2_WIDTH-gcd[0].gd.pos.width;
  1626. gcd[0].gd.pos.y = CV_LAYERS2_HEADER_HEIGHT+2*CV_LAYERS2_LINE_HEIGHT;
  1627. gcd[0].gd.pos.height = CV_LAYERS2_HEIGHT-gcd[0].gd.pos.y;
  1628. gcd[0].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels|gg_sb_vert;
  1629. gcd[0].gd.cid = CID_SB;
  1630. gcd[0].creator = GScrollBarCreate;
  1631. layer2.sb_start = gcd[0].gd.pos.x;
  1632. /* GT: Abbreviation for "Visible" */
  1633. label[1].text = (unichar_t *) _("V");
  1634. label[1].text_is_1byte = true;
  1635. gcd[1].gd.label = &label[1];
  1636. gcd[1].gd.pos.x = 7; gcd[1].gd.pos.y = 5;
  1637. gcd[1].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels|gg_utf8_popup;
  1638. gcd[1].gd.popup_msg = (unichar_t *) _("Is Layer Visible?");
  1639. gcd[1].creator = GLabelCreate;
  1640. label[2].text = (unichar_t *) _("Layer");
  1641. label[2].text_is_1byte = true;
  1642. gcd[2].gd.label = &label[2];
  1643. gcd[2].gd.pos.x = 30; gcd[2].gd.pos.y = 5;
  1644. gcd[2].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels|gg_utf8_popup;
  1645. gcd[2].gd.popup_msg = (unichar_t *) _("Is Layer Editable?");
  1646. gcd[2].creator = GLabelCreate;
  1647. gcd[3].gd.pos.x = 5; gcd[3].gd.pos.y = CV_LAYERS2_HEADER_HEIGHT+(CV_LAYERS2_LINE_HEIGHT-12)/2;
  1648. gcd[3].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels|gg_utf8_popup;
  1649. gcd[3].gd.cid = CID_VGrid;
  1650. gcd[3].gd.popup_msg = (unichar_t *) _("Is Layer Visible?");
  1651. gcd[3].gd.box = &radio_box;
  1652. gcd[3].creator = GCheckBoxCreate;
  1653. gcd[4].gd.pos.x = 5; gcd[4].gd.pos.y = gcd[3].gd.pos.y+CV_LAYERS2_LINE_HEIGHT;
  1654. gcd[4].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels|gg_utf8_popup;
  1655. gcd[4].gd.cid = CID_VBack;
  1656. gcd[4].gd.popup_msg = (unichar_t *) _("Is Layer Visible?");
  1657. gcd[4].gd.box = &radio_box;
  1658. gcd[4].creator = GCheckBoxCreate;
  1659. gcd[5].gd.pos.x = 5; gcd[5].gd.pos.y = gcd[4].gd.pos.y+CV_LAYERS2_LINE_HEIGHT;
  1660. gcd[5].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels|gg_utf8_popup;
  1661. gcd[5].gd.cid = CID_VFore;
  1662. gcd[5].gd.popup_msg = (unichar_t *) _("Is Layer Visible?");
  1663. gcd[5].gd.box = &radio_box;
  1664. gcd[5].creator = GCheckBoxCreate;
  1665. int wi = 6; // Widget index.
  1666. int ly = 0;
  1667. // We want to look at the unhandled layers.
  1668. if (ly <= ly_back) ly = ly_back + 1;
  1669. if (ly <= ly_fore) ly = ly_fore + 1;
  1670. if (ly <= ly_grid) ly = ly_grid + 1;
  1671. while (ly < cv->b.sc->parent->layer_cnt && wi < 24) {
  1672. gcd[wi].gd.pos.x = 5; gcd[wi].gd.pos.y = gcd[wi-1].gd.pos.y+CV_LAYERS2_LINE_HEIGHT;
  1673. gcd[wi].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels|gg_utf8_popup;
  1674. gcd[wi].gd.cid = CID_VBase + ly; // There are plenty of CID values available for these above CID_VBase.
  1675. gcd[wi].gd.popup_msg = (unichar_t *) _("Is Layer Visible?");
  1676. gcd[wi].gd.box = &radio_box;
  1677. gcd[wi].creator = GCheckBoxCreate;
  1678. ly++;
  1679. wi++;
  1680. }
  1681. if ( cv->showgrids ) gcd[3].gd.flags |= gg_cb_on;
  1682. if ( cv->showback[0]&1 ) gcd[4].gd.flags |= gg_cb_on;
  1683. if ( cv->showfore ) gcd[5].gd.flags |= gg_cb_on;
  1684. GGadgetsCreate(cvlayers2,gcd);
  1685. if ( cvvisible[0] )
  1686. GDrawSetVisible(cvlayers2,true);
  1687. }
  1688. static void LayersSwitch(CharView *cv) {
  1689. }
  1690. void SC_MoreLayers(SplineChar *sc, Layer *old) { /* We've added more layers */
  1691. CharView *curcv, *cv;
  1692. if ( sc->parent==NULL || !sc->parent->multilayer )
  1693. return;
  1694. for ( cv=(CharView *) (sc->views); cv!=NULL ; cv=(CharView *) (cv->b.next) ) {
  1695. cv->b.layerheads[dm_fore] = &cv->b.sc->layers[cv->b.layerheads[dm_fore]-old];
  1696. cv->b.layerheads[dm_back] = &cv->b.sc->layers[ly_back];
  1697. }
  1698. if ( cvtools==NULL )
  1699. return;
  1700. curcv = GDrawGetUserData(cvtools);
  1701. if ( curcv==NULL || curcv->b.sc!=sc )
  1702. return;
  1703. CVLayers2Set(curcv);
  1704. }
  1705. void SCLayersChange(SplineChar *sc) { /* many of the foreground layers need to be redrawn */
  1706. CharView *curcv;
  1707. if ( cvtools==NULL || !sc->parent->multilayer )
  1708. return;
  1709. curcv = GDrawGetUserData(cvtools);
  1710. if ( curcv==NULL || curcv->b.sc!=sc )
  1711. return;
  1712. CVLayers2Set(curcv);
  1713. }
  1714. void CVLayerChange(CharView *cv) { /* Current layer needs to be redrawn */
  1715. CharView *curcv;
  1716. int layer;
  1717. if ( cvtools==NULL || !cv->b.sc->parent->multilayer )
  1718. return;
  1719. curcv = GDrawGetUserData(cvtools);
  1720. if ( curcv!=cv )
  1721. return;
  1722. if ( cv->b.drawmode==dm_grid || cv->b.drawmode==dm_back )
  1723. return;
  1724. layer = CVLayer(&cv->b);
  1725. BDFCharFree(layer2.layers[layer+1]);
  1726. layer2.layers[layer+1] = BDFCharFromLayer(cv->b.sc,layer);
  1727. GDrawRequestExpose(cvlayers2,NULL,false);
  1728. }
  1729. /* Update the state of the controls of the non-type3 layers palette to the given character view */
  1730. /* New widgets are not allocated here. For that, see CVLCheckLayerCount(). */
  1731. static void CVLayers1Set(CharView *cv) {
  1732. int i, top;
  1733. GGadgetSetChecked(GWidgetGetControl(cvlayers,CID_VFore),cv->showfore);
  1734. GGadgetSetChecked(GWidgetGetControl(cvlayers,CID_VBack),cv->showback[0]&1);
  1735. GGadgetSetChecked(GWidgetGetControl(cvlayers,CID_VGrid),cv->showgrids);
  1736. /* clear old layer previews */
  1737. layerinfo.offtop = 0;
  1738. for ( i=2; i<layerinfo.current_layers; ++i ) {
  1739. BDFCharFree(layerinfo.layers[i]);
  1740. layerinfo.layers[i]=NULL;
  1741. }
  1742. /* reallocate enough space if necessary */
  1743. if ( cv->b.sc->layer_cnt+1>=layerinfo.max_layers ) {
  1744. top = cv->b.sc->layer_cnt+10;
  1745. if ( layerinfo.layers==NULL )
  1746. layerinfo.layers = calloc(top,sizeof(BDFChar *));
  1747. else {
  1748. layerinfo.layers = realloc(layerinfo.layers,top*sizeof(BDFChar *));
  1749. for ( i=layerinfo.current_layers; i<top; ++i )
  1750. layerinfo.layers[i] = NULL;
  1751. }
  1752. layerinfo.max_layers = top;
  1753. }
  1754. layerinfo.current_layers = cv->b.sc->layer_cnt+1;
  1755. for ( i=ly_fore; i<cv->b.sc->layer_cnt; ++i )
  1756. layerinfo.layers[i+1] = BDFCharFromLayer(cv->b.sc,i);
  1757. layerinfo.active = CVLayer(&cv->b)+1;
  1758. if ( layerinfo.visible_layers==0 ) {
  1759. GRect size;
  1760. GDrawGetSize(cvlayers,&size);
  1761. layerinfo.visible_layers=(size.height-layer_header_height)/layer_height;
  1762. }
  1763. GScrollBarSetBounds(GWidgetGetControl(cvlayers,CID_SB),0,cv->b.sc->layer_cnt+1-2, layerinfo.visible_layers);
  1764. if ( layerinfo.offtop>cv->b.sc->layer_cnt-1-layerinfo.visible_layers )
  1765. layerinfo.offtop = cv->b.sc->layer_cnt-1-layerinfo.visible_layers;
  1766. if ( layerinfo.offtop<0 ) layerinfo.offtop = 0;
  1767. GScrollBarSetPos(GWidgetGetControl(cvlayers,CID_SB),layerinfo.offtop);
  1768. for ( i=0; i<cv->b.sc->layer_cnt; i++ ) {
  1769. GGadgetSetChecked(GWidgetGetControl(cvlayers,CID_VBase+i),cv->showback[i>>5]&(1<<(i&31)));
  1770. }
  1771. layerinfo.active = CVLayer(&cv->b); /* the index of the active layer */
  1772. GDrawRequestExpose(cvlayers,NULL,false);
  1773. }
  1774. /* Update the layers palette to reflect the given character view. No new gadgets
  1775. * are created or hid here, only the state of existing gadgets is changed.
  1776. * New layer gadgets are created in CVLCheckLayerCount(). */
  1777. void CVLayersSet(CharView *cv) {
  1778. if( cv )
  1779. onCollabSessionStateChanged( 0, cv->b.fv );
  1780. if ( cv->b.sc->parent->multilayer ) {
  1781. CVLayers2Set(cv);
  1782. return;
  1783. }
  1784. /* This is for the non-type3 layers palette: */
  1785. CVLayers1Set(cv);
  1786. }
  1787. /**
  1788. * Get the offset at the right hand size of the eyeball to show/hide
  1789. * a layer. This is the x offset where the Q/C indicators might be drawn.
  1790. */
  1791. static int32 Layers_getOffsetAtRightOfViewLayer(CharView *cv)
  1792. {
  1793. int32 ret = 64;
  1794. GGadget *v = GWidgetGetControl(cvlayers,CID_VBack);
  1795. if( v )
  1796. {
  1797. GRect size;
  1798. GGadgetGetSize(v,&size);
  1799. ret = 7 + size.width;
  1800. }
  1801. return ret;
  1802. }
  1803. /* Draw the fg/bg, cubic/quadratic columns, plus layer preview and label name */
  1804. static void LayersExpose(CharView *cv,GWindow pixmap,GEvent *event) {
  1805. int i, ll, y;
  1806. const char *str;
  1807. GRect r;
  1808. struct _GImage base;
  1809. GImage gi;
  1810. Color mocolor = ACTIVE_BORDER; /* mouse over color */
  1811. int ww;
  1812. int yt = .7*layer_height; /* vertical spacer to add when drawing text in the row */
  1813. int column_width;
  1814. int quadcol, fgcol, editcol;
  1815. if ( event->u.expose.rect.y+event->u.expose.rect.height<layer_header_height )
  1816. return;
  1817. int offsetAtRightOfViewLayer = Layers_getOffsetAtRightOfViewLayer(cv);
  1818. column_width = layerinfo.column_width;
  1819. GDrawSetDither(NULL, false); /* on 8 bit displays we don't want any dithering */
  1820. ww=layerinfo.sb_start;
  1821. memset(&gi,0,sizeof(gi));
  1822. memset(&base,0,sizeof(base));
  1823. gi.u.image = &base;
  1824. base.image_type = it_index;
  1825. base.clut = layer2.clut;
  1826. base.trans = -1;
  1827. GDrawSetFont(pixmap,layerinfo.font);
  1828. quadcol=fgcol=offsetAtRightOfViewLayer;
  1829. if ( layerscols & LSHOW_CUBIC )
  1830. {
  1831. /* show quad col */
  1832. quadcol = offsetAtRightOfViewLayer;
  1833. fgcol = offsetAtRightOfViewLayer+column_width;
  1834. }
  1835. if ( layerscols & LSHOW_FG )
  1836. {
  1837. /* show fg col */
  1838. fgcol = quadcol+column_width;
  1839. }
  1840. // editcol is the X offset where the layer name label should be drawn
  1841. editcol = fgcol+column_width;
  1842. int bottomOfLast = 0;
  1843. /* loop once per layer, where 0==guides, 1=back, 2=fore, etc */
  1844. for ( i=(event->u.expose.rect.y-layer_header_height)/layer_height;
  1845. i<(event->u.expose.rect.y+event->u.expose.rect.height+layer_height-layer_header_height)/layer_height;
  1846. ++i ) {
  1847. ll = i-1+layerinfo.offtop;
  1848. if ( ll>=cv->b.sc->layer_cnt || ll<-1 ) continue;
  1849. y = layer_header_height + i*layer_height;
  1850. bottomOfLast = y + layer_height;
  1851. if ( y<layer_header_height ) continue;
  1852. /* draw quadratic/cubic toggle */
  1853. if ( layerscols & LSHOW_CUBIC ) {
  1854. if ( layerinfo.mo_layer==ll && layerinfo.mo_col==CID_QBase ) {
  1855. r.x = quadcol; r.width = column_width;
  1856. r.y = y;
  1857. r.height = layer_height;
  1858. GDrawFillRect(pixmap,&r,mocolor);
  1859. }
  1860. str = ( ll>=0 && ll<cv->b.sc->layer_cnt ? (cv->b.sc->layers[ll].order2? "Q" : "C") : " ");
  1861. GDrawDrawText8(pixmap, quadcol, y + yt,
  1862. (char *) str,-1,GDrawGetDefaultForeground(NULL));
  1863. }
  1864. /* draw fg/bg toggle */
  1865. if ( layerscols & LSHOW_FG ) {
  1866. if ( layerinfo.mo_layer==ll && layerinfo.mo_col==CID_FBase ) {
  1867. r.x = fgcol; r.width = column_width;
  1868. r.y = y;
  1869. r.height = layer_height;
  1870. GDrawFillRect(pixmap,&r,mocolor);
  1871. }
  1872. str = ( ll>=0 && ll<cv->b.sc->layer_cnt ? (cv->b.sc->layers[ll].background? "B" : "F") : "#");
  1873. GDrawDrawText8(pixmap, fgcol, y + yt,
  1874. (char *) str,-1,GDrawGetDefaultForeground(NULL));
  1875. }
  1876. /* draw layer thumbnail and label */
  1877. if ( ll==layerinfo.active ) {
  1878. r.x = editcol; r.width = ww-r.x;
  1879. r.y = y;
  1880. r.height = layer_height;
  1881. GDrawFillRect(pixmap,&r,GDrawGetDefaultForeground(NULL));
  1882. } else if ( layerinfo.mo_layer==ll && layerinfo.mo_col==CID_EBase ) {
  1883. r.x = editcol; r.width = ww-r.x;
  1884. r.y = y;
  1885. r.height = layer_height;
  1886. GDrawFillRect(pixmap,&r,mocolor);
  1887. }
  1888. r.x=editcol;
  1889. if ( ll==-1 || ll==0 || ll==1) {
  1890. str = ll==-1 ? _("Guide") : (ll==0 ?_("Back") : _("Fore")) ;
  1891. GDrawDrawText8(pixmap,r.x+2,y + yt,
  1892. (char *) str,-1,ll==layerinfo.active?0xffffff:GDrawGetDefaultForeground(NULL));
  1893. } else if ( ll>=layerinfo.current_layers ) {
  1894. break; /* no more layers to draw! */
  1895. } else if ( ll>=0 && layerinfo.layers[ll]!=NULL ) {
  1896. BDFChar *bdfc = layerinfo.layers[ll];
  1897. base.data = bdfc->bitmap;
  1898. base.bytes_per_line = bdfc->bytes_per_line;
  1899. base.width = bdfc->xmax-bdfc->xmin+1;
  1900. base.height = bdfc->ymax-bdfc->ymin+1;
  1901. // GDrawDrawImage(pixmap,&gi,NULL,
  1902. // r.x+2+bdfc->xmin,
  1903. // y+as-bdfc->ymax);
  1904. str = cv->b.sc->parent->layers[ll].name;
  1905. if ( !str || !*str ) str="-";
  1906. GDrawDrawText8(pixmap, r.x+2, y + yt,
  1907. (char *) str,-1,ll==layerinfo.active?0xffffff:GDrawGetDefaultForeground(NULL));
  1908. }
  1909. }
  1910. if( bottomOfLast )
  1911. {
  1912. GGadgetSetY(GWidgetGetControl(cvlayers,CID_AddLayer), bottomOfLast + 2 );
  1913. GGadgetSetY(GWidgetGetControl(cvlayers,CID_RemoveLayer), bottomOfLast + 2 );
  1914. GGadgetSetY(GWidgetGetControl(cvlayers,CID_LayersMenu), bottomOfLast + 2 );
  1915. }
  1916. }
  1917. /* Remove the layer rename edit box. If save!=0, then record the text as the new layer name. */
  1918. static void CVLRemoveEdit(CharView *cv, int save) {
  1919. if ( layerinfo.rename_active ) {
  1920. GGadget *g = GWidgetGetControl(cvlayers,CID_Edit);
  1921. const unichar_t *str = GGadgetGetTitle(g);
  1922. int l = layerinfo.active;
  1923. if ( save
  1924. && layerinfo.active>=0 && str!=NULL && str[0]!='\0'
  1925. && uc_strcmp( str,cv->b.sc->parent->layers[l].name) ) {
  1926. free( cv->b.sc->parent->layers[l].name );
  1927. cv->b.sc->parent->layers[l].name = cu_copy( str );
  1928. CVLCheckLayerCount(cv,true);
  1929. CVLayersSet(cv);
  1930. }
  1931. GGadgetSetVisible(g,false);
  1932. GDrawRequestExpose(cvlayers,NULL,false);
  1933. layerinfo.rename_active = 0;
  1934. CVInfoDrawText(cv,cv->gw);
  1935. }
  1936. }
  1937. /* Make sure we've got the right number of gadgets in the layers palette, and that
  1938. * they are positioned properly. Their state are updated in CVLayers1Set().
  1939. * If resize, then make the palette fit the layers up to a max number of layers. */
  1940. static void CVLCheckLayerCount(CharView *cv, int resize) {
  1941. SplineChar *sc = cv->b.sc;
  1942. int i;
  1943. GGadgetCreateData gcd[4];
  1944. GTextInfo label[3];
  1945. GRect size;
  1946. int width;
  1947. int maxwidth=0;
  1948. int togsize=0;
  1949. int x, y;
  1950. int column_width = layerinfo.column_width;
  1951. char namebuf[40];
  1952. int viscol=0, quadcol, fgcol, editcol;
  1953. extern int _GScrollBar_Width;
  1954. int offsetAtRightOfViewLayer = Layers_getOffsetAtRightOfViewLayer(cv);
  1955. if (layerinfo.rename_active) CVLRemoveEdit(cv,true);
  1956. quadcol=fgcol=offsetAtRightOfViewLayer;
  1957. if ( layerscols & LSHOW_CUBIC )
  1958. {
  1959. quadcol = offsetAtRightOfViewLayer;
  1960. fgcol = offsetAtRightOfViewLayer+column_width;
  1961. }
  1962. if ( layerscols & LSHOW_FG )
  1963. {
  1964. fgcol = quadcol+column_width;
  1965. }
  1966. // editcol is the X offset where the layer name label should be drawn
  1967. editcol = fgcol+column_width;
  1968. /* First figure out if we need to create any new widgets. If we have more */
  1969. /* widgets than we need, we just set them to be invisible. */
  1970. if ( sc->layer_cnt > layers_max ) {
  1971. memset(&label,0,sizeof(label));
  1972. memset(&gcd,0,sizeof(gcd));
  1973. for ( i=layers_max; i<sc->layer_cnt; ++i ) {
  1974. /* for each new layer, create new widgets */
  1975. /* Visibility toggle */
  1976. gcd[0].gd.flags = gg_enabled|gg_utf8_popup;
  1977. gcd[0].gd.cid = CID_VBase+i;
  1978. gcd[0].gd.popup_msg = (unichar_t *) _("Is Layer Visible?");
  1979. gcd[0].creator = GVisibilityBoxCreate;
  1980. GGadgetsCreate(cvlayers,gcd);
  1981. GVisibilityBoxSetToMinWH(GWidgetGetControl(cvlayers,CID_VBase+i));
  1982. }
  1983. layers_max = sc->layer_cnt;
  1984. }
  1985. /* Then position everything, and name it properly */
  1986. GDrawSetFont(cvlayers,layerinfo.font); /* for width finding code, need this */
  1987. /* First need to position the add, remove, and layers gadgets */
  1988. GGadgetGetSize(GWidgetGetControl(cvlayers,CID_RemoveLayer),&size);
  1989. x = 7+size.width;
  1990. y = layer_header_height;
  1991. GGadgetMove(GWidgetGetControl(cvlayers,CID_AddLayer), x, 5);
  1992. GGadgetSetSize(GWidgetGetControl(cvlayers,CID_AddLayer),&size);
  1993. GGadgetGetSize(GWidgetGetControl(cvlayers,CID_AddLayer),&size);
  1994. x += size.width;
  1995. GGadgetGetSize(GWidgetGetControl(cvlayers,CID_LayersMenu),&size);
  1996. GGadgetMove(GWidgetGetControl(cvlayers,CID_LayersMenu), x+5, 5+(y-8-size.height)/2);
  1997. maxwidth=x+5+size.width;
  1998. if ( !resize )
  1999. {
  2000. /* adjust the number of layers that can be visible in the palette */
  2001. GDrawGetSize(cvlayers,&size);
  2002. layerinfo.visible_layers=(size.height-layer_header_height)/layer_height;
  2003. if ( layerinfo.offtop+layerinfo.visible_layers>=sc->layer_cnt )
  2004. layerinfo.offtop = sc->layer_cnt-layerinfo.visible_layers;
  2005. if ( layerinfo.offtop<0 ) layerinfo.offtop=0;
  2006. }
  2007. if ( layerinfo.visible_layers<2 ) layerinfo.visible_layers=2;
  2008. /* Now position each layer row */
  2009. for ( i=-1; i<layers_max; ++i ) {
  2010. GGadget *v = GWidgetGetControl(cvlayers,CID_VBase+i);
  2011. width=0;
  2012. togsize = editcol;
  2013. if ( i>=0 && i<sc->layer_cnt ) {
  2014. char *hasmn = strchr(sc->parent->layers[i].name,'_');
  2015. if ( hasmn==NULL && i>=2 && i<9 && strlen(sc->parent->layers[i].name)<30 ) {
  2016. /* For the first 10 or so layers, add a mnemonic like "(_3)" to the name label */
  2017. /* if it does not already have a mnemonic. */
  2018. /* sprintf(namebuf, "%s (_%d)", sc->parent->layers[i].name, i+1); */
  2019. sprintf(namebuf, "%s", sc->parent->layers[i].name);
  2020. } else if ( hasmn==NULL ) {
  2021. sprintf(namebuf,"%s", i==-1 ? _("Guide") : (i==0 ?_("Back") : _("Fore")) );
  2022. }
  2023. width = GDrawGetText8Width(cvlayers, namebuf, -1);
  2024. width += 10; // padding takes up some space.
  2025. if ( width+togsize>maxwidth ) maxwidth = width + togsize;
  2026. } else if ( i==-1 ) {
  2027. if ( width+togsize>maxwidth ) maxwidth = width + togsize;
  2028. }
  2029. if ( i+1<layerinfo.offtop || i>=layerinfo.offtop+layerinfo.visible_layers ||
  2030. (sc->layer_cnt<=layerinfo.visible_layers && i>=sc->layer_cnt)) {
  2031. /* layer is currently scrolled out of palette */
  2032. GGadgetSetVisible(v,false);
  2033. } else {
  2034. GGadgetMove(v,viscol ,y);
  2035. GGadgetSetVisible(v,true);
  2036. y += layer_height;
  2037. }
  2038. }
  2039. /* Update the scroll bar */
  2040. if ( sc->layer_cnt+1<=layerinfo.visible_layers ) {
  2041. /* don't need the scroll bar, so turn it off */
  2042. GGadgetSetVisible(GWidgetGetControl(cvlayers,CID_SB),false);
  2043. } else {
  2044. if( !resize )
  2045. {
  2046. GGadget *sb = GWidgetGetControl(cvlayers,CID_SB);
  2047. maxwidth += 2 + GDrawPointsToPixels(cv->gw,_GScrollBar_Width);
  2048. GScrollBarSetBounds(sb,0,sc->layer_cnt,layerinfo.visible_layers);
  2049. GScrollBarSetPos(sb,cv->layers_off_top);
  2050. GGadgetSetVisible(sb,true);
  2051. }
  2052. }
  2053. /* Resize the palette to fit */
  2054. if ( resize )
  2055. {
  2056. y += GDrawPointsToPixels(NULL,3);
  2057. GDrawGetSize(cvlayers,&size);
  2058. GDrawResize(cvlayers,maxwidth,y+layer_footer_height);
  2059. }
  2060. GDrawGetSize(cvlayers,&size);
  2061. layerinfo.sb_start = size.width
  2062. - (sc->layer_cnt+1<=layerinfo.visible_layers ? 0 : GDrawPointsToPixels(cv->gw,_GScrollBar_Width));
  2063. GGadget *sb = GWidgetGetControl(cvlayers,CID_SB);
  2064. GGadgetResize(sb, GDrawPointsToPixels(cv->gw,_GScrollBar_Width), size.height-layer_header_height);
  2065. GGadgetMove(sb,layerinfo.sb_start,layer_header_height);
  2066. GDrawRequestExpose(cvlayers,NULL,false);
  2067. }
  2068. /* Respond to scroll events from cvlayers scrollbar. */
  2069. static void LayerScroll(CharView *cv, GEvent *event) {
  2070. int off = 0;
  2071. enum sb sbt = event->u.control.u.sb.type;
  2072. if ( sbt==et_sb_top )
  2073. off = 0;
  2074. else if ( sbt==et_sb_bottom )
  2075. off = cv->b.sc->layer_cnt-layerinfo.visible_layers;
  2076. else if ( sbt==et_sb_up ) {
  2077. off = cv->layers_off_top-1;
  2078. } else if ( sbt==et_sb_down ) {
  2079. off = cv->layers_off_top+1;
  2080. } else if ( sbt==et_sb_uppage ) {
  2081. off = cv->layers_off_top-layerinfo.visible_layers+1;
  2082. } else if ( sbt==et_sb_downpage ) {
  2083. off = cv->layers_off_top+layerinfo.visible_layers-1;
  2084. } else /* if ( sbt==et_sb_thumb || sbt==et_sb_thumbrelease ) */ {
  2085. off = event->u.control.u.sb.pos;
  2086. }
  2087. if ( off>cv->b.sc->layer_cnt-layerinfo.visible_layers )
  2088. off = cv->b.sc->layer_cnt-layerinfo.visible_layers;
  2089. if ( off<0 ) off=0;
  2090. if ( off==cv->layers_off_top )
  2091. return;
  2092. cv->layers_off_top = off;
  2093. layerinfo.offtop = off;
  2094. CVLCheckLayerCount(cv, false);
  2095. GScrollBarSetPos(GWidgetGetControl(cvlayers,CID_SB),off);
  2096. GDrawRequestExpose(cvlayers,NULL,false);
  2097. }
  2098. /* Layers palette menu ids */
  2099. #define LMID_LayerInfo 1
  2100. #define LMID_NewLayer 2
  2101. #define LMID_DelLayer 3
  2102. #define LMID_Fill 4
  2103. #define LMID_First 5
  2104. #define LMID_Up 6
  2105. #define LMID_Down 7
  2106. #define LMID_Last 8
  2107. #define LMID_Foreground 9
  2108. #define LMID_Background 10
  2109. #define LMID_Cubic 11
  2110. #define LMID_Quadratic 12
  2111. #define LMID_ShowCubic 13
  2112. #define LMID_ShowFore 14
  2113. /* Return a unique layer name based on base.
  2114. * This just appends a number to base until the name is not found. */
  2115. static char *UniqueLayerName(SplineChar *sc, const char *base)
  2116. {
  2117. static char buffer[100];
  2118. const char *basestr=base;
  2119. int i=1, c;
  2120. if ( basestr==NULL || basestr[0]=='\0' ) basestr=_("Layer");
  2121. while (1) {
  2122. if (i==1) sprintf( buffer,"%s",basestr );
  2123. else sprintf( buffer,"%s %d",basestr, i );
  2124. for (c=0; c<sc->layer_cnt; c++) {
  2125. if (!strcmp(sc->parent->layers[c].name,buffer)) break;
  2126. }
  2127. if ( c==sc->layer_cnt ) break;
  2128. i++;
  2129. }
  2130. return buffer;
  2131. }
  2132. /* Layers palette menu selection */
  2133. static void CVLayerInvoked(GWindow v, GMenuItem *mi, GEvent *e) {
  2134. CharView *cv = (CharView *) GDrawGetUserData(v);
  2135. int layer = CVLayer(&cv->b);
  2136. SplineChar *sc = cv->b.sc;
  2137. Layer temp;
  2138. int i;
  2139. char *buts[3];
  2140. buts[0] = _("_Yes"); buts[1]=_("_No"); buts[2] = NULL;
  2141. switch ( mi->mid ) {
  2142. case LMID_Fill:
  2143. cv->showfilled = !cv->showfilled;
  2144. CVRegenFill(cv);
  2145. GDrawRequestExpose(cv->v,NULL,false);
  2146. break;
  2147. case LMID_ShowCubic:
  2148. layerscols=(layerscols&~LSHOW_CUBIC)|((layerscols&LSHOW_CUBIC)?0:1);
  2149. CVLCheckLayerCount(cv, true);
  2150. break;
  2151. case LMID_ShowFore:
  2152. layerscols=(layerscols&~LSHOW_FG)|((layerscols&LSHOW_FG)?0:2);
  2153. CVLCheckLayerCount(cv, true);
  2154. break;
  2155. case LMID_Foreground:
  2156. if ( layer>ly_fore && cv->b.sc->parent->layers[layer].background==1) {
  2157. SFLayerSetBackground(cv->b.sc->parent,layer,0);
  2158. GDrawRequestExpose(cvlayers,NULL,false);
  2159. }
  2160. break;
  2161. case LMID_Background:
  2162. if ( layer>=ly_fore && cv->b.sc->parent->layers[layer].background==0) {
  2163. SFLayerSetBackground(cv->b.sc->parent,layer,1);
  2164. GDrawRequestExpose(cvlayers,NULL,false);
  2165. }
  2166. break;
  2167. case LMID_Cubic:
  2168. if ( layer!=ly_grid && cv->b.sc->layers[layer].order2 ) {
  2169. SFConvertLayerToOrder3(cv->b.sc->parent, layer);
  2170. GDrawRequestExpose(cvlayers,NULL,false);
  2171. cv->back_img_out_of_date = true;
  2172. }
  2173. break;
  2174. case LMID_Quadratic:
  2175. if ( layer!=ly_grid && !cv->b.sc->layers[layer].order2 ) {
  2176. SFConvertLayerToOrder2(cv->b.sc->parent, layer);
  2177. GDrawRequestExpose(cvlayers,NULL,false);
  2178. cv->back_img_out_of_date = true;
  2179. }
  2180. break;
  2181. case LMID_NewLayer:
  2182. SFAddLayer(cv->b.sc->parent, /* font of the glyph in the charview */
  2183. UniqueLayerName(sc,_("Back")), /* Name */
  2184. 0, /* 0=cubic, 1=quad */
  2185. 1); /* 1=back, 0=fore */
  2186. layer=cv->b.sc->parent->layer_cnt-1;
  2187. cv->showback[layer>>5] |= (1<<(layer&31)); /* make it visible */
  2188. CVLCheckLayerCount(cv, true); /* update widget existence */
  2189. CVLayersSet(cv); /* update widget state */
  2190. break;
  2191. case LMID_DelLayer:
  2192. layer = CVLayer((CharViewBase *) cv); /* the index of the active layer */
  2193. if (layer==ly_fore || layer==ly_back || layer==ly_grid)
  2194. return;
  2195. if ( gwwv_ask(_("Cannot Be Undone"),(const char **) buts,0,1,_("This operation cannot be undone, do it anyway?"))==1 )
  2196. return;
  2197. SFRemoveLayer(cv->b.sc->parent, layer);
  2198. CVLCheckLayerCount(cv, true); /* update widget existence */
  2199. CVLayersSet(cv); /* update widget state */
  2200. break;
  2201. case LMID_First: /* move layer contents to top */
  2202. if ( layer==ly_fore )
  2203. return;
  2204. temp = sc->layers[layer];
  2205. for ( i=layer-1; i>=ly_fore; --i )
  2206. sc->layers[i+1] = sc->layers[i];
  2207. sc->layers[i+1] = temp;
  2208. cv->b.layerheads[dm_fore] = &sc->layers[ly_fore];
  2209. break;
  2210. case LMID_Up: /* move layer contents one up */
  2211. if ( layer==ly_fore )
  2212. return;
  2213. temp = sc->layers[layer];
  2214. sc->layers[layer] = sc->layers[layer-1];
  2215. sc->layers[layer-1] = temp;
  2216. cv->b.layerheads[dm_fore] = &sc->layers[layer-1];
  2217. break;
  2218. case LMID_Down: /* move layer contents one down */
  2219. if ( layer==sc->layer_cnt-1 )
  2220. return;
  2221. temp = sc->layers[layer];
  2222. sc->layers[layer] = sc->layers[layer+1];
  2223. sc->layers[layer+1] = temp;
  2224. cv->b.layerheads[dm_fore] = &sc->layers[layer+1];
  2225. break;
  2226. case LMID_Last:
  2227. if ( layer==sc->layer_cnt-1 )
  2228. return;
  2229. temp = sc->layers[layer]; /* move layer contents to bottom */
  2230. for ( i=layer+1; i<sc->layer_cnt; ++i )
  2231. sc->layers[i-1] = sc->layers[i];
  2232. sc->layers[i-1] = temp;
  2233. cv->b.layerheads[dm_fore] = &sc->layers[i-1];
  2234. break;
  2235. }
  2236. CVLayersSet(cv);
  2237. CVCharChangedUpdate(&cv->b);
  2238. }
  2239. /* Pop up the layers palette context menu */
  2240. static void LayerMenu(CharView *cv,GEvent *event, int nolayer) {
  2241. GMenuItem mi[20];
  2242. int i;
  2243. static char *names[] = {
  2244. /*N_("Rename Layer..."),*/
  2245. N_("New Layer"),
  2246. N_("Del Layer"),
  2247. (char *) -1,
  2248. N_("Shift Contents To _First"),
  2249. N_("Shift Contents _Up"),
  2250. N_("Shift Contents _Down"),
  2251. N_("Shift Contents To _Last"),
  2252. (char *) -1,
  2253. N_("Make Foreground"),/* or N_("Make Background"), */
  2254. N_("Make Cubic"), /* or N_("Make Quadratic"), */
  2255. (char *) -1,
  2256. N_("Fill"),
  2257. (char *) -1,
  2258. N_("Show Cubic Column"),
  2259. N_("Show Fore/Back Column"),
  2260. NULL,
  2261. };
  2262. static int mids[] = {
  2263. /*LMID_RenameLayer,*/
  2264. LMID_NewLayer,
  2265. LMID_DelLayer,
  2266. -1,
  2267. LMID_First,
  2268. LMID_Up,
  2269. LMID_Down,
  2270. LMID_Last,
  2271. -1,
  2272. LMID_Foreground, /* or LMID_Background, */
  2273. LMID_Cubic, /* or LMID_Quadratic, */
  2274. -1,
  2275. LMID_Fill,
  2276. -1,
  2277. LMID_ShowCubic,
  2278. LMID_ShowFore,
  2279. 0
  2280. };
  2281. int layer = CVLayer(&cv->b);
  2282. memset(mi,'\0',sizeof(mi));
  2283. for ( i=0; names[i]!=0; ++i ) {
  2284. if ( names[i]!=(char *) -1 ) {
  2285. mi[i].ti.text = (unichar_t *) _(names[i]);
  2286. mi[i].ti.text_is_1byte = true;
  2287. mi[i].ti.text_in_resource = true;
  2288. } else
  2289. mi[i].ti.line = true;
  2290. mi[i].ti.fg = COLOR_DEFAULT;
  2291. mi[i].ti.bg = COLOR_DEFAULT;
  2292. mi[i].mid = mids[i];
  2293. mi[i].invoke = CVLayerInvoked;
  2294. /*if ( mids[i]!=LMID_NewLayer && nolayer )
  2295. mi[i].ti.disabled = true;*/
  2296. if ( ( mids[i]==LMID_First || mids[i]==LMID_Up ) && ( layer==-1 || layer==0) )
  2297. mi[i].ti.disabled = true;
  2298. else if ( ( mids[i]==LMID_Last || mids[i]==LMID_Down ) && (layer==ly_grid || layer==cv->b.sc->layer_cnt-1) )
  2299. mi[i].ti.disabled = true;
  2300. else if ( mids[i]==LMID_DelLayer && ( layer<2 || cv->b.sc->layer_cnt==2) )
  2301. mi[i].ti.disabled = true;
  2302. else if ( mids[i]==LMID_Fill ) {
  2303. mi[i].ti.checkable = 1;
  2304. mi[i].ti.checked = cv->showfilled;
  2305. } else if ( mids[i]==LMID_Foreground ) {
  2306. if ( layer>=0 ) {
  2307. if ( ! cv->b.sc->layers[layer].background ) {
  2308. mi[i].mid = LMID_Background;
  2309. mi[i].ti.text = (unichar_t *) _("Make Background");
  2310. }
  2311. } else {
  2312. mi[i].ti.disabled = true;
  2313. }
  2314. } else if ( mids[i]==LMID_Cubic ) {
  2315. if ( ! cv->b.sc->layers[layer].order2 ) {
  2316. mi[i].mid = LMID_Quadratic;
  2317. mi[i].ti.text = (unichar_t *) _("Make Quadratic");
  2318. }
  2319. } else if ( mids[i]==LMID_ShowCubic ) {
  2320. mi[i].ti.checkable = 1;
  2321. mi[i].ti.checked = (layerscols & LSHOW_CUBIC)?1:0;
  2322. } else if ( mids[i]==LMID_ShowFore ) {
  2323. mi[i].ti.checkable = 1;
  2324. mi[i].ti.checked = (layerscols & LSHOW_FG)?1:0;
  2325. }
  2326. }
  2327. GMenuCreatePopupMenu(cvlayers, event, mi);
  2328. }
  2329. /* Scan for which layer and column one clicks on in the layers 1 palette */
  2330. /* -1 is the guides layer, 0 is default back, 1 default fore, etc. */
  2331. /* col will be set to either -1 for none, CID_VBase, CID_QBase, CID_FBase, or CID_EBase */
  2332. static int CVLScanForItem(int x, int y, int *col) {
  2333. int l=(y-layer_header_height)/layer_height + layerinfo.offtop - 1;
  2334. int viscol=0, quadcol, fgcol, editcol;
  2335. int cw=layerinfo.column_width;
  2336. quadcol=fgcol=viscol;
  2337. if ( layerscols & LSHOW_CUBIC ) { quadcol = viscol+cw; fgcol=viscol+cw; }
  2338. if ( layerscols & LSHOW_FG ) { fgcol = quadcol+cw; }
  2339. editcol=fgcol+cw;
  2340. *col=-1;
  2341. if ( x>0 && x<viscol+cw ) *col=CID_VBase;
  2342. /**
  2343. * The two below options, CID_QBase and CID_FBase allow the curve
  2344. * type and foreground/background to be changed simply by clicking
  2345. * on them. The cubic/quadratic and background/foreground
  2346. * attributes should NOT be buttons that can change these
  2347. * attributes, they should only SHOW the attribute. Changing the
  2348. * attributes can be done in Font Info, Layers, and is done
  2349. * infrequently and has a lot of implications so shouldn't be
  2350. * easily done by mistake.
  2351. */
  2352. // else if ( (layerscols & LSHOW_CUBIC) && x>=quadcol && x<quadcol+cw ) *col=CID_QBase;
  2353. // else if ( (layerscols & LSHOW_FG) && x>=fgcol && x<fgcol+cw ) *col=CID_FBase;
  2354. else if ( x>=editcol ) *col=CID_EBase;
  2355. return l;
  2356. }
  2357. /* Called in response to some event where we want to change the current layer. */
  2358. void CVLSelectLayer(CharView *cv, int layer) {
  2359. enum drawmode dm = cv->b.drawmode;
  2360. if ( layer<-1 || layer>=cv->b.sc->layer_cnt )
  2361. return;
  2362. if ( layer==-1 ) {
  2363. cv->b.drawmode = dm_grid;
  2364. cv->lastselpt = NULL;
  2365. } else {
  2366. if ( layer==1 ) {
  2367. cv->b.drawmode = dm_fore;
  2368. cv->lastselpt = NULL;
  2369. } else {
  2370. cv->b.drawmode = dm_back;
  2371. cv->b.layerheads[dm_back] = &cv->b.sc->layers[layer];
  2372. cv->lastselpt = NULL;
  2373. }
  2374. CVDebugFree(cv->dv);
  2375. SplinePointListsFree(cv->b.gridfit); cv->b.gridfit = NULL;
  2376. FreeType_FreeRaster(cv->oldraster); cv->oldraster = NULL;
  2377. FreeType_FreeRaster(cv->raster); cv->raster = NULL;
  2378. cv->show_ft_results = false;
  2379. }
  2380. layerinfo.active = CVLayer(&cv->b); /* the index of the active layer */
  2381. CVRegenFill(cv);
  2382. GDrawRequestExpose(cv->v,NULL,false);
  2383. if (cvlayers2) GDrawRequestExpose(cvlayers2,NULL,false);
  2384. if (cvlayers) GDrawRequestExpose(cvlayers,NULL,false);
  2385. if ( dm!=cv->b.drawmode )
  2386. GDrawRequestExpose(cv->gw,NULL,false); /* the logo (where the scrollbars join) shows what layer we are in */
  2387. CVInfoDrawText(cv,cv->gw);
  2388. }
  2389. static int cvlayers_e_h(GWindow gw, GEvent *event) {
  2390. CharView *cv = (CharView *) GDrawGetUserData(gw);
  2391. char *buts[3];
  2392. buts[0] = _("_Yes"); buts[1]=_("_No"); buts[2] = NULL;
  2393. if ( event->type==et_destroy )
  2394. {
  2395. cvlayers = NULL;
  2396. return( true );
  2397. }
  2398. if ( cv==NULL )
  2399. return( true );
  2400. switch ( event->type ) {
  2401. case et_close:
  2402. GDrawSetVisible(gw,false);
  2403. break;
  2404. case et_char: case et_charup:
  2405. if ( event->u.chr.keysym == GK_Return) {
  2406. CVLRemoveEdit(cv, true);
  2407. } else if ( event->u.chr.keysym == GK_Escape) {
  2408. CVLRemoveEdit(cv, false);
  2409. } else PostCharToWindow(cv->gw,event);
  2410. break;
  2411. case et_mousemove: {
  2412. int l, col;
  2413. l = CVLScanForItem(event->u.mouse.x,event->u.mouse.y, &col);
  2414. if ( l!=layerinfo.mo_layer || col!=layerinfo.mo_col ) {
  2415. layerinfo.mo_layer = l;
  2416. layerinfo.mo_col = col;
  2417. GDrawRequestExpose(cvlayers,NULL,false);
  2418. }
  2419. return( true );
  2420. } break;
  2421. case et_mousedown: {
  2422. if ( layerinfo.rename_active ) CVLRemoveEdit(cv, true);
  2423. } break;
  2424. case et_mouseup: {
  2425. int l, x, cid, h;
  2426. GGadget *g;
  2427. l = CVLScanForItem(event->u.mouse.x,event->u.mouse.y, &cid);
  2428. if ( cid==CID_EBase && l>=-1 && l<cv->b.sc->layer_cnt )
  2429. {
  2430. /* Need to check for this BEFORE checking for right click! */
  2431. if ( event->u.mouse.button==1 && event->u.mouse.clicks==2 )
  2432. {
  2433. /* bring up edit box for layer name */
  2434. if ( l<2 )
  2435. return ( true );
  2436. x = 7+(1+((layerscols&LSHOW_CUBIC)?1:0)+((layerscols&LSHOW_FG)?1:0))*layerinfo.column_width;
  2437. g = GWidgetGetControl(cvlayers,CID_Edit);
  2438. h = 1.5*layer_height;
  2439. GGadgetResize(g, layerinfo.sb_start-x, h);
  2440. GGadgetMove(g, x,layer_header_height+(l+1.5+layerinfo.offtop)*layer_height-h/2);
  2441. GGadgetSetVisible(g,true);
  2442. /* GGadgetSetTitle8((GTextField*)g, cv->b.sc->parent->layers[l].name); */
  2443. GGadgetSetTitle8(g, cv->b.sc->parent->layers[l].name);
  2444. layerinfo.active=l;
  2445. layerinfo.rename_active=1;
  2446. return ( true );
  2447. }
  2448. CVLSelectLayer(cv, l);
  2449. }
  2450. /* right click to pop up menu */
  2451. if ( event->u.mouse.button==3 ) {
  2452. LayerMenu(cv,event,true);
  2453. return(true);
  2454. }
  2455. /* otherwise, deal with clicking up on the various controls */
  2456. if ( l<-1 || l>=cv->b.sc->layer_cnt)
  2457. return (true);
  2458. if ( cid==CID_QBase) {
  2459. if (l>=0) { /* don't try to adjust if calling for guides layer */
  2460. if (cv->b.sc->layers[l].order2)
  2461. SFConvertLayerToOrder3(cv->b.sc->parent, l);
  2462. else
  2463. SFConvertLayerToOrder2(cv->b.sc->parent, l);
  2464. cv->back_img_out_of_date = true;
  2465. GDrawRequestExpose(cvlayers,NULL,false);
  2466. GDrawRequestExpose(cv->v,NULL,false);
  2467. }
  2468. } else if ( cid==CID_FBase) {
  2469. if (l>1) { /* don't try to adjust if calling guides, default fore or back layer */
  2470. if (cv->b.sc->layers[l].background)
  2471. SFLayerSetBackground(cv->b.sc->parent,l,0);
  2472. else
  2473. SFLayerSetBackground(cv->b.sc->parent,l,1);
  2474. GDrawRequestExpose(cvlayers,NULL,false);
  2475. GDrawRequestExpose(cv->v,NULL,false);
  2476. }
  2477. }
  2478. } break; /* case et_mouseup */
  2479. case et_expose:
  2480. LayersExpose(cv,gw,event);
  2481. break;
  2482. case et_resize:
  2483. if ( event->u.resize.sized ) {
  2484. CVLCheckLayerCount(cv,false); /* update widget existence, but do not resize */
  2485. }
  2486. break;
  2487. case et_controlevent:
  2488. if ( event->u.control.subtype == et_buttonactivate ) {
  2489. int cid = GGadgetGetCid(event->u.control.g);
  2490. int layer;
  2491. switch( cid ) {
  2492. case CID_AddLayer: {
  2493. SplineChar *sc = cv->b.sc;
  2494. /* This adds a new layer to the end of the current layers list.
  2495. * Somehow it is created as an invisible layer. */
  2496. SFAddLayer(cv->b.sc->parent, /* font of the glyph in the charview */
  2497. UniqueLayerName(sc,_("Back")), /* Name */
  2498. 0, /* 0=cubic, 1=quad */
  2499. 1); /* 1=back, 0=fore */
  2500. layer=cv->b.sc->parent->layer_cnt-1;
  2501. cv->showback[layer>>5] |= (1<<(layer&31)); /* make it visible */
  2502. CVLCheckLayerCount(cv,true); /* update widget existence */
  2503. CVLayersSet(cv); /* update widget state */
  2504. } break;
  2505. case CID_RemoveLayer:
  2506. layer = CVLayer((CharViewBase *) cv); /* the index of the active layer */
  2507. if (layer==ly_fore || layer==ly_back || layer==ly_grid)
  2508. return ( true );
  2509. if ( gwwv_ask(_("Cannot Be Undone"),(const char **) buts,0,1,_("This operation cannot be undone, do it anyway?"))==1 )
  2510. return ( true );
  2511. SFRemoveLayer(cv->b.sc->parent, layer);
  2512. CVLCheckLayerCount(cv,true); /* update widget existence */
  2513. CVLayersSet(cv); /* update widget state */
  2514. break;
  2515. case CID_RenameLayer: {
  2516. /* *** */
  2517. int x = 7+(1+((layerscols&LSHOW_CUBIC)?1:0)+((layerscols&LSHOW_FG)?1:0))*layerinfo.column_width;
  2518. GGadget *g = GWidgetGetControl(cvlayers,CID_Edit);
  2519. layer = CVLayer((CharViewBase *) cv); /* the index of the active layer */
  2520. /* layer = layerinfo.active */ /* the index of the active layer */
  2521. GGadgetResize(g, layerinfo.sb_start-x,1.5*layer_height);
  2522. GGadgetMove(g, x,layer_header_height+(layer+1+layerinfo.offtop)*layer_height);
  2523. GGadgetSetVisible(g,true);
  2524. GGadgetSetTitle8(g, cv->b.sc->parent->layers[layer].name);
  2525. layerinfo.rename_active=1;
  2526. CVLCheckLayerCount(cv,true); /* update widget existence */
  2527. CVLayersSet(cv); /* update widget state */
  2528. GDrawRequestExpose(cvtools,NULL,false);
  2529. } break;
  2530. }
  2531. } else if ( event->u.control.subtype == et_radiochanged ) {
  2532. enum drawmode dm = cv->b.drawmode;
  2533. int cid = GGadgetGetCid(event->u.control.g);
  2534. switch( cid ) {
  2535. case CID_VFore:
  2536. CVShows.showfore = cv->showfore = GGadgetIsChecked(event->u.control.g);
  2537. GDrawRequestExpose(cv->v,NULL,false);
  2538. break;
  2539. case CID_VBack:
  2540. CVShows.showback = GGadgetIsChecked(event->u.control.g);
  2541. if ( CVShows.showback )
  2542. cv->showback[0] |= 1;
  2543. else
  2544. cv->showback[0] &= ~1;
  2545. cv->back_img_out_of_date = true;
  2546. GDrawRequestExpose(cv->v,NULL,false);
  2547. break;
  2548. case CID_VGrid:
  2549. CVShows.showgrids = cv->showgrids = GGadgetIsChecked(event->u.control.g);
  2550. GDrawRequestExpose(cv->v,NULL,false);
  2551. break;
  2552. case CID_EFore:
  2553. cv->b.drawmode = dm_fore;
  2554. cv->lastselpt = NULL;
  2555. CVDebugFree(cv->dv);
  2556. SplinePointListsFree(cv->b.gridfit); cv->b.gridfit = NULL;
  2557. FreeType_FreeRaster(cv->oldraster); cv->oldraster = NULL;
  2558. FreeType_FreeRaster(cv->raster); cv->raster = NULL;
  2559. cv->show_ft_results = false;
  2560. break;
  2561. case CID_EBack:
  2562. cv->b.drawmode = dm_back;
  2563. cv->b.layerheads[dm_back] = &cv->b.sc->layers[ly_back];
  2564. cv->lastselpt = NULL;
  2565. CVDebugFree(cv->dv);
  2566. SplinePointListsFree(cv->b.gridfit); cv->b.gridfit = NULL;
  2567. FreeType_FreeRaster(cv->oldraster); cv->oldraster = NULL;
  2568. FreeType_FreeRaster(cv->raster); cv->raster = NULL;
  2569. cv->show_ft_results = false;
  2570. break;
  2571. case CID_EGrid:
  2572. cv->b.drawmode = dm_grid;
  2573. cv->lastselpt = NULL;
  2574. break;
  2575. default:
  2576. if ( cid>=CID_VBase-1 && cid<CID_VBase+999) {
  2577. cid -= CID_VBase;
  2578. if ( GGadgetIsChecked(event->u.control.g))
  2579. cv->showback[cid>>5] |= (1<<(cid&31));
  2580. else
  2581. cv->showback[cid>>5] &= ~(1<<(cid&31));
  2582. cv->back_img_out_of_date = true;
  2583. GDrawRequestExpose(cv->v,NULL,false);
  2584. if ( dm!=cv->b.drawmode )
  2585. GDrawRequestExpose(cv->gw,NULL,false); /* the logo (where the scrollbars join) shows what layer we are in */
  2586. }
  2587. }
  2588. } else if ( event->u.control.subtype == et_scrollbarchange ) {
  2589. LayerScroll(cv,event);
  2590. }
  2591. break; /* case et_controlevent */
  2592. default: {
  2593. } break;
  2594. } /* switch ( event->type ) */
  2595. return( true );
  2596. }
  2597. /* Set to true the editable field for the current layer, and false for the other layers. */
  2598. void CVSetLayer(CharView *cv,int layer) {
  2599. /* Update the drawmode of cv */
  2600. if ( layer == ly_grid )
  2601. cv->b.drawmode = dm_grid;
  2602. else if (layer == ly_fore )
  2603. cv->b.drawmode = dm_fore;
  2604. else {
  2605. cv->b.drawmode = dm_back;
  2606. cv->b.layerheads[dm_back] = &cv->b.sc->layers[layer];
  2607. }
  2608. if ( cvlayers!=NULL && GDrawGetUserData(cvlayers)==cv )
  2609. GDrawRequestExpose(cvlayers,NULL,false);
  2610. }
  2611. /* Check if a key press corresponds to a mnemonic the palette knows about. */
  2612. int CVPaletteMnemonicCheck(GEvent *event) {
  2613. static struct strmatch { char *str; int cid; } strmatch[] = {
  2614. /* GT: Foreground, make it short */
  2615. { N_("F_ore"), CID_EFore },
  2616. /* GT: Background, make it short */
  2617. { N_("_Back"), CID_EBack },
  2618. /* GT: Guide layer, make it short */
  2619. { N_("_Guide"), CID_EGrid },
  2620. { NULL, 0 }
  2621. };
  2622. unichar_t mn, mnc;
  2623. int j, i, ch;
  2624. char *foo;
  2625. GEvent fake;
  2626. GGadget *g;
  2627. CharView *cv;
  2628. SplineFont *parent;
  2629. int curlayer;
  2630. if ( cvtools==NULL )
  2631. return( false );
  2632. cv = GDrawGetUserData(cvtools);
  2633. parent = cv->b.sc->parent;
  2634. curlayer = CVLayer(&cv->b); /* the index of the active layer */
  2635. if ( isdigit(event->u.chr.keysym) ) {
  2636. int off = event->u.chr.keysym - '0';
  2637. g = GWidgetGetControl(cvlayers, CID_EBase+off-1);
  2638. if ( off-1<parent->layer_cnt && off!=curlayer ) {
  2639. CVLSelectLayer(cv, off);
  2640. if ( cv->b.sc->parent->multilayer )
  2641. GDrawRequestExpose(cvlayers2,NULL,false);
  2642. else
  2643. return( true );
  2644. }
  2645. }
  2646. /* mnemonic is encoded in the layer name */
  2647. for ( j=0; j<2; ++j ) {
  2648. for ( i=0; j==0 ? i<parent->layer_cnt : strmatch[i].str!=NULL; ++i ) {
  2649. for ( foo = j==0 ? parent->layers[i].name : _(strmatch[i].str);
  2650. (ch=utf8_ildb((const char **) &foo))!=0; )
  2651. if ( ch=='_' )
  2652. break;
  2653. if ( ch=='_' )
  2654. mnc = utf8_ildb((const char **) &foo);
  2655. else
  2656. mnc = 0;
  2657. mn = mnc;
  2658. if ( islower(mn)) mnc = toupper(mn);
  2659. else if ( isupper(mn)) mnc = tolower(mn);
  2660. if ( event->u.chr.chars[0]==mn || event->u.chr.chars[0]==mnc ) {
  2661. if ( cv->b.sc->parent->multilayer ) {
  2662. fake.type = et_mousedown;
  2663. fake.w = cvlayers;
  2664. fake.u.mouse.x = 40;
  2665. if ( strmatch[i].cid==CID_EGrid ) {
  2666. fake.u.mouse.y = CV_LAYERS2_HEADER_HEIGHT+12;
  2667. } else if ( strmatch[i].cid==CID_EBack ) {
  2668. fake.u.mouse.y = CV_LAYERS2_HEADER_HEIGHT+12+CV_LAYERS2_LINE_HEIGHT;
  2669. } else {
  2670. fake.u.mouse.y = CV_LAYERS2_HEADER_HEIGHT+12+2*CV_LAYERS2_LINE_HEIGHT;
  2671. }
  2672. cvlayers2_e_h(cvlayers2,&fake);
  2673. } else {
  2674. CVLSelectLayer(cv, i);
  2675. GDrawRequestExpose(cvlayers,NULL,false);
  2676. }
  2677. return( true );
  2678. }
  2679. }
  2680. }
  2681. return( false );
  2682. }
  2683. /* This is used for fonts other than Type 3 fonts. CVMakeLayers2() is used for Type 3.
  2684. * Only the basics of the palette are set up here, with the widgets for the default fore, back,
  2685. * and guides layers. The palette is updated to actual character views in CVLCheckLayerCount(). */
  2686. GWindow CVMakeLayers(CharView *cv) {
  2687. GRect r,size;
  2688. GWindowAttrs wattrs;
  2689. GGadgetCreateData gcd[25];
  2690. GTextInfo label[25];
  2691. GGadget *gadget;
  2692. FontRequest rq;
  2693. extern int _GScrollBar_Width;
  2694. int i=0;
  2695. int viscol=0;
  2696. if ( cvlayers!=NULL )
  2697. return( cvlayers );
  2698. /* Initialize layerinfo */
  2699. if ( layerinfo.clut==NULL )
  2700. layerinfo.clut = _BDFClut(4);
  2701. if ( layersfont==NULL ) {
  2702. memset(&rq,'\0',sizeof(rq));
  2703. rq.utf8_family_name = SANS_UI_FAMILIES;
  2704. rq.point_size = -12;
  2705. rq.weight = 400;
  2706. layersfont = GDrawInstanciateFont(cvlayers2,&rq);
  2707. layersfont = GResourceFindFont("LayersPalette.Font",layersfont);
  2708. }
  2709. layerinfo.font = layersfont;
  2710. /* Initialize palette window */
  2711. memset(&wattrs,0,sizeof(wattrs));
  2712. wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_positioned|wam_isdlg;
  2713. wattrs.event_masks = -1;
  2714. wattrs.cursor = ct_mypointer;
  2715. wattrs.positioned = true;
  2716. wattrs.is_dlg = true;
  2717. wattrs.utf8_window_title = _("Layers");
  2718. r.width = GGadgetScale(104); r.height = CV_LAYERS_HEIGHT;
  2719. if ( cvlayersoff.x==-9999 ) {
  2720. /* Offset of window on screen, by default make it sit just below the tools palette */
  2721. cvlayersoff.x = -r.width-6;
  2722. cvlayersoff.y = cv->mbh+CV_TOOLS_HEIGHT+45/*25*/; /* 45 is right if there's decor, 25 when none. twm gives none, kde gives decor */
  2723. }
  2724. r.x = cvlayersoff.x; r.y = cvlayersoff.y;
  2725. if ( palettes_docked ) { r.x = 0; r.y=CV_TOOLS_HEIGHT+2; }
  2726. cvlayers = CreatePalette( cv->gw, &r, cvlayers_e_h, NULL, &wattrs, cv->v );
  2727. memset(&label,0,sizeof(label));
  2728. memset(&gcd,0,sizeof(gcd));
  2729. int32 plusw = GDrawGetText8Width(cv->gw, _("+"), -1);
  2730. int32 plush = GDrawGetText8Height(cv->gw, _("+"), -1);
  2731. plusw = GDrawPointsToPixels(NULL,plusw+4);
  2732. plush = GDrawPointsToPixels(NULL,plush+4);
  2733. plush = MAX( plush, plusw ); // make it square.
  2734. /* Remove Layer button */
  2735. label[0].text = (unichar_t *) _("-");
  2736. label[0].text_is_1byte = true;
  2737. gcd[i].gd.label = &label[0];
  2738. gcd[i].gd.pos.x = 7; gcd[i].gd.pos.y = 5;
  2739. gcd[i].gd.pos.width = plusw; gcd[i].gd.pos.height = plush;
  2740. gcd[i].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels|gg_utf8_popup;
  2741. gcd[i].gd.cid = CID_RemoveLayer;
  2742. gcd[i].gd.popup_msg = (unichar_t *) _("Delete the current layer");
  2743. gcd[i].creator = GButtonCreate;
  2744. ++i;
  2745. /* Add Layer button */
  2746. label[1].text = (unichar_t *) _("+");
  2747. label[1].text_is_1byte = true;
  2748. gcd[i].gd.label = &label[1];
  2749. gcd[i].gd.pos.x = 30; gcd[i].gd.pos.y = 5;
  2750. gcd[i].gd.pos.width = plusw; gcd[i].gd.pos.height = plush;
  2751. gcd[i].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels|gg_utf8_popup;
  2752. gcd[i].gd.cid = CID_AddLayer;
  2753. gcd[i].gd.popup_msg = (unichar_t *) _("Add a new layer");
  2754. gcd[i].creator = GButtonCreate;
  2755. ++i;
  2756. /* "Layers" label next to the add and remove buttons */
  2757. label[2].text = (unichar_t *) "";
  2758. label[2].text_is_1byte = true;
  2759. gcd[i].gd.label = &label[2];
  2760. gcd[i].gd.pos.x = 47; gcd[i].gd.pos.y = 5;
  2761. gcd[i].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels|gg_utf8_popup;
  2762. gcd[i].gd.cid = CID_LayersMenu;
  2763. /* gcd[i].gd.popup_msg = (unichar_t *) _("Rename the current layer"); */
  2764. gcd[i].creator = GLabelCreate;
  2765. ++i;
  2766. /* Default visibility toggles for Fore, Back, and Guides */
  2767. gcd[i].gd.pos.x = viscol; gcd[i].gd.pos.y = 38;
  2768. gcd[i].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels|gg_utf8_popup;
  2769. if ( cv->showgrids ) gcd[i].gd.flags |= gg_cb_on;
  2770. gcd[i].gd.cid = CID_VGrid;
  2771. gcd[i].gd.popup_msg = (unichar_t *) _("Is Layer Visible?");
  2772. gcd[i].creator = GVisibilityBoxCreate;
  2773. ++i;
  2774. gcd[i].gd.pos.x = viscol; gcd[i].gd.pos.y = 38;
  2775. gcd[i].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels|gg_utf8_popup;
  2776. if ( cv->showback[0]&1 ) gcd[i].gd.flags |= gg_cb_on;
  2777. gcd[i].gd.cid = CID_VBack;
  2778. gcd[i].gd.popup_msg = (unichar_t *) _("Is Layer Visible?");
  2779. gcd[i].creator = GVisibilityBoxCreate;
  2780. ++i;
  2781. gcd[i].gd.pos.x = viscol; gcd[i].gd.pos.y = 21;
  2782. gcd[i].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels|gg_utf8_popup;
  2783. if ( cv->showfore ) gcd[i].gd.flags |= gg_cb_on;
  2784. gcd[i].gd.cid = CID_VFore;
  2785. gcd[i].gd.popup_msg = (unichar_t *) _("Is Layer Visible?");
  2786. gcd[i].creator = GVisibilityBoxCreate;
  2787. ++i;
  2788. /* Scroll bar */
  2789. gcd[i].gd.pos.width = GDrawPointsToPixels(cv->gw,_GScrollBar_Width);
  2790. gcd[i].gd.pos.x = 0; /* <- these get updated to real values later */
  2791. gcd[i].gd.pos.y = 0;
  2792. gcd[i].gd.pos.height = 50;
  2793. gcd[i].gd.flags = gg_enabled|gg_pos_in_pixels|gg_sb_vert;
  2794. gcd[i].gd.cid = CID_SB;
  2795. gcd[i].creator = GScrollBarCreate;
  2796. layerinfo.sb_start = gcd[i].gd.pos.x;
  2797. ++i;
  2798. /* Edit box for in place layer rename */
  2799. gcd[i].gd.pos.width=gcd[i].gd.pos.height=1;
  2800. gcd[i].gd.flags = gg_enabled|gg_pos_in_pixels|gg_utf8_popup;
  2801. gcd[i].gd.cid = CID_Edit;
  2802. gcd[i].gd.popup_msg = (unichar_t *) _("Type in new layer name");
  2803. gcd[i].creator = GTextFieldCreate;
  2804. ++i;
  2805. GGadgetsCreate(cvlayers,gcd);
  2806. if ( cvvisible[0] )
  2807. GDrawSetVisible(cvlayers,true);
  2808. layers_max=2;
  2809. gadget=GWidgetGetControl(cvlayers,CID_AddLayer);
  2810. GGadgetGetSize(gadget,&size);
  2811. layer_header_height = 0;
  2812. layer_footer_height = size.y + size.height;
  2813. GGadgetGetSize(GWidgetGetControl(cvlayers,CID_VGrid),&size);
  2814. layer_height = size.height;
  2815. int32 w = GDrawGetText8Width(cvlayers, "W", -1);
  2816. layerinfo.column_width = w+6;
  2817. layerinfo.active = CVLayer(&cv->b); /* the index of the active layer */
  2818. layerinfo.mo_col = -2; /* -2 forces this variable to be updated. afterwords it will be -1 for nothing, or >=0 */
  2819. layerinfo.mo_layer = -2;
  2820. layerinfo.offtop = 0;
  2821. layerinfo.rename_active = 0;
  2822. GVisibilityBoxSetToMinWH(GWidgetGetControl(cvlayers,CID_VGrid));
  2823. GVisibilityBoxSetToMinWH(GWidgetGetControl(cvlayers,CID_VBack));
  2824. GVisibilityBoxSetToMinWH(GWidgetGetControl(cvlayers,CID_VFore));
  2825. return( cvlayers );
  2826. }
  2827. /* ***************** CVTools and other common palette functions follow ************ */
  2828. static void CVPopupInvoked(GWindow v, GMenuItem *mi, GEvent *e) {
  2829. CharView *cv = (CharView *) GDrawGetUserData(v);
  2830. int pos;
  2831. pos = mi->mid;
  2832. if ( pos==cvt_spiro ) {
  2833. CVChangeSpiroMode(cv);
  2834. } else if ( cv->had_control ) {
  2835. if ( cv->cb1_tool!=pos ) {
  2836. cv->cb1_tool = cv_cb1_tool = pos;
  2837. GDrawRequestExpose(cvtools,NULL,false);
  2838. }
  2839. } else {
  2840. if ( cv->b1_tool!=pos ) {
  2841. cv->b1_tool = cv_b1_tool = pos;
  2842. GDrawRequestExpose(cvtools,NULL,false);
  2843. }
  2844. }
  2845. CVToolsSetCursor(cv,cv->had_control?ksm_control:0,NULL);
  2846. }
  2847. static void CVPopupLayerInvoked(GWindow v, GMenuItem *mi, GEvent *e) {
  2848. CharView *cv = (CharView *) GDrawGetUserData(v);
  2849. int layer = mi->mid==0 ? 1 : mi->mid==1 ? 0 : -1;
  2850. if ( layerinfo.active!=layer )
  2851. CVLSelectLayer(cv, layer);
  2852. }
  2853. static void CVPopupSelectInvoked(GWindow v, GMenuItem *mi, GEvent *e) {
  2854. CharView *cv = (CharView *) GDrawGetUserData(v);
  2855. switch ( mi->mid ) {
  2856. case 0:
  2857. CVPGetInfo(cv);
  2858. break;
  2859. case 1:
  2860. if ( cv->p.ref!=NULL )
  2861. CharViewCreate(cv->p.ref->sc,(FontView *) (cv->b.fv),-1);
  2862. break;
  2863. case 2:
  2864. CVAddAnchor(cv);
  2865. break;
  2866. case 3:
  2867. CVMakeClipPath(cv);
  2868. break;
  2869. case MIDL_MakeLine: {
  2870. _CVMenuMakeLine((CharViewBase *) cv,mi->mid==MIDL_MakeArc, e!=NULL && (e->u.mouse.state&ksm_meta));
  2871. break;
  2872. }
  2873. case MIDL_MakeArc: {
  2874. _CVMenuMakeLine((CharViewBase *) cv,mi->mid==MIDL_MakeArc, e!=NULL && (e->u.mouse.state&ksm_meta));
  2875. break;
  2876. }
  2877. case MIDL_InsertPtOnSplineAt: {
  2878. _CVMenuInsertPt( cv );
  2879. break;
  2880. }
  2881. case MIDL_NamePoint: {
  2882. if ( cv->p.sp )
  2883. _CVMenuNamePoint( cv, cv->p.sp );
  2884. break;
  2885. }
  2886. case MIDL_NameContour: {
  2887. _CVMenuNameContour( cv );
  2888. break;
  2889. }
  2890. }
  2891. }
  2892. void CVToolsPopup(CharView *cv, GEvent *event) {
  2893. GMenuItem mi[125];
  2894. int i=0;
  2895. int j=0;
  2896. int anysel=0;
  2897. static char *selectables[] = { N_("Get Info..."), N_("Open Reference"), N_("Add Anchor"), NULL };
  2898. memset(mi,'\0',sizeof(mi));
  2899. anysel = CVTestSelectFromEvent(cv,event);
  2900. if( anysel )
  2901. {
  2902. mi[i].ti.text = (unichar_t *) _("Curve");
  2903. mi[i].ti.text_is_1byte = true;
  2904. mi[i].ti.fg = COLOR_DEFAULT;
  2905. mi[i].ti.bg = COLOR_DEFAULT;
  2906. mi[i].mid = MID_Curve;
  2907. mi[i].invoke = CVMenuPointType;
  2908. i++;
  2909. mi[i].ti.text = (unichar_t *) _("HVCurve");
  2910. mi[i].ti.text_is_1byte = true;
  2911. mi[i].ti.fg = COLOR_DEFAULT;
  2912. mi[i].ti.bg = COLOR_DEFAULT;
  2913. mi[i].mid = MID_HVCurve;
  2914. mi[i].invoke = CVMenuPointType;
  2915. i++;
  2916. mi[i].ti.text = (unichar_t *) _("Corner");
  2917. mi[i].ti.text_is_1byte = true;
  2918. mi[i].ti.fg = COLOR_DEFAULT;
  2919. mi[i].ti.bg = COLOR_DEFAULT;
  2920. mi[i].mid = MID_Corner;
  2921. mi[i].invoke = CVMenuPointType;
  2922. i++;
  2923. mi[i].ti.text = (unichar_t *) _("Tangent");
  2924. mi[i].ti.text_is_1byte = true;
  2925. mi[i].ti.fg = COLOR_DEFAULT;
  2926. mi[i].ti.bg = COLOR_DEFAULT;
  2927. mi[i].mid = MID_Tangent;
  2928. mi[i].invoke = CVMenuPointType;
  2929. i++;
  2930. mi[i].ti.line = true;
  2931. mi[i].ti.fg = COLOR_DEFAULT;
  2932. mi[i].ti.bg = COLOR_DEFAULT;
  2933. i++;
  2934. mi[i].ti.text = (unichar_t *) _("Merge");
  2935. mi[i].ti.text_is_1byte = true;
  2936. mi[i].ti.fg = COLOR_DEFAULT;
  2937. mi[i].ti.bg = COLOR_DEFAULT;
  2938. mi[i].mid = MID_Merge;
  2939. mi[i].invoke = CVMerge;
  2940. i++;
  2941. mi[i].ti.text = (unichar_t *) _("Merge to Line");
  2942. mi[i].ti.text_is_1byte = true;
  2943. mi[i].ti.fg = COLOR_DEFAULT;
  2944. mi[i].ti.bg = COLOR_DEFAULT;
  2945. mi[i].mid = MID_MergeToLine;
  2946. mi[i].invoke = CVMergeToLine;
  2947. i++;
  2948. mi[i].ti.text = (unichar_t *) _("Align Points");
  2949. mi[i].ti.text_is_1byte = true;
  2950. mi[i].ti.fg = COLOR_DEFAULT;
  2951. mi[i].ti.bg = COLOR_DEFAULT;
  2952. mi[i].mid = MID_Average;
  2953. mi[i].invoke = CVMenuConstrain;
  2954. i++;
  2955. }
  2956. if( !anysel )
  2957. {
  2958. for ( i=0;i<=cvt_skew; ++i ) {
  2959. char *msg = _(popupsres[i]);
  2960. if ( cv->b.sc->inspiro && hasspiro()) {
  2961. if ( i==cvt_spirog2 )
  2962. msg = _("Add a g2 curve point");
  2963. else if ( i==cvt_spiroleft )
  2964. msg = _("Add a left \"tangent\" point");
  2965. else if ( i==cvt_spiroright )
  2966. msg = _("Add a right \"tangent\" point");
  2967. }
  2968. mi[i].ti.text = (unichar_t *) msg;
  2969. mi[i].ti.text_is_1byte = true;
  2970. mi[i].ti.fg = COLOR_DEFAULT;
  2971. mi[i].ti.bg = COLOR_DEFAULT;
  2972. mi[i].mid = i;
  2973. mi[i].invoke = CVPopupInvoked;
  2974. }
  2975. }
  2976. if( !anysel )
  2977. {
  2978. if ( cvlayers!=NULL && !cv->b.sc->parent->multilayer ) {
  2979. mi[i].ti.line = true;
  2980. mi[i].ti.fg = COLOR_DEFAULT;
  2981. mi[i++].ti.bg = COLOR_DEFAULT;
  2982. for ( j=0;j<3; ++j, ++i ) {
  2983. mi[i].ti.text = (unichar_t *) _(editablelayers[j]);
  2984. mi[i].ti.text_in_resource = true;
  2985. mi[i].ti.text_is_1byte = true;
  2986. mi[i].ti.fg = COLOR_DEFAULT;
  2987. mi[i].ti.bg = COLOR_DEFAULT;
  2988. mi[i].mid = j;
  2989. mi[i].invoke = CVPopupLayerInvoked;
  2990. }
  2991. }
  2992. }
  2993. if( i > 0 ) {
  2994. mi[i].ti.line = true;
  2995. mi[i].ti.fg = COLOR_DEFAULT;
  2996. mi[i++].ti.bg = COLOR_DEFAULT;
  2997. }
  2998. for ( j=0; selectables[j]!=0; ++j )
  2999. {
  3000. if ( (!anysel && j!=2 ) ||
  3001. ( j==0 && cv->p.spline ) ||
  3002. ( j==1 && !cv->p.ref ))
  3003. {
  3004. // don't show them a disabled item
  3005. continue;
  3006. // or, if the above "continue;" is commented then keep the entry
  3007. // but don't let them select it
  3008. mi[i].ti.disabled = true;
  3009. }
  3010. mi[i].ti.text = (unichar_t *) _(selectables[j]);
  3011. mi[i].ti.text_is_1byte = true;
  3012. mi[i].ti.fg = COLOR_DEFAULT;
  3013. mi[i].ti.bg = COLOR_DEFAULT;
  3014. mi[i].mid = j;
  3015. mi[i].invoke = CVPopupSelectInvoked;
  3016. i++;
  3017. }
  3018. if ( anysel ) {
  3019. mi[i].ti.text = (unichar_t *)_("Name Point...");
  3020. mi[i].ti.text_is_1byte = true;
  3021. mi[i].ti.fg = COLOR_DEFAULT;
  3022. mi[i].ti.bg = COLOR_DEFAULT;
  3023. mi[i].mid = MIDL_NamePoint;
  3024. mi[i].invoke = CVPopupSelectInvoked;
  3025. i++;
  3026. }
  3027. if ( cv->b.sc->parent->multilayer ) {
  3028. mi[i].ti.text = (unichar_t *) _("Make Clip Path");
  3029. mi[i].ti.text_is_1byte = true;
  3030. mi[i].ti.fg = COLOR_DEFAULT;
  3031. mi[i].ti.bg = COLOR_DEFAULT;
  3032. mi[i].mid = j;
  3033. mi[i].invoke = CVPopupSelectInvoked;
  3034. i++;
  3035. }
  3036. int cnt = CVCountSelectedPoints(cv);
  3037. printf(".... count:%d\n", cnt );
  3038. if( cnt > 1 ) {
  3039. mi[i].ti.text = (unichar_t *) _("Make Line");
  3040. mi[i].ti.text_is_1byte = true;
  3041. mi[i].ti.fg = COLOR_DEFAULT;
  3042. mi[i].ti.bg = COLOR_DEFAULT;
  3043. mi[i].mid = MIDL_MakeLine;
  3044. mi[i].invoke = CVPopupSelectInvoked;
  3045. i++;
  3046. mi[i].ti.text = (unichar_t *) _("Make Arc");
  3047. mi[i].ti.text_is_1byte = true;
  3048. mi[i].ti.fg = COLOR_DEFAULT;
  3049. mi[i].ti.bg = COLOR_DEFAULT;
  3050. mi[i].mid = MIDL_MakeArc;
  3051. mi[i].invoke = CVPopupSelectInvoked;
  3052. i++;
  3053. mi[i].ti.text = (unichar_t *) _("Insert Point On Spline At...");
  3054. mi[i].ti.text_is_1byte = true;
  3055. mi[i].ti.fg = COLOR_DEFAULT;
  3056. mi[i].ti.bg = COLOR_DEFAULT;
  3057. mi[i].mid = MIDL_InsertPtOnSplineAt;
  3058. mi[i].invoke = CVPopupSelectInvoked;
  3059. i++;
  3060. mi[i].ti.text = (unichar_t *) _("Name Point");
  3061. mi[i].ti.text_is_1byte = true;
  3062. mi[i].ti.fg = COLOR_DEFAULT;
  3063. mi[i].ti.bg = COLOR_DEFAULT;
  3064. mi[i].mid = MIDL_NamePoint;
  3065. mi[i].invoke = CVPopupSelectInvoked;
  3066. i++;
  3067. mi[i].ti.text = (unichar_t *) _("Name Contour");
  3068. mi[i].ti.text_is_1byte = true;
  3069. mi[i].ti.fg = COLOR_DEFAULT;
  3070. mi[i].ti.bg = COLOR_DEFAULT;
  3071. mi[i].mid = MIDL_NameContour;
  3072. mi[i].invoke = CVPopupSelectInvoked;
  3073. i++;
  3074. }
  3075. cv->had_control = (event->u.mouse.state&ksm_control)?1:0;
  3076. GMenuCreatePopupMenuWithName(cv->v,event, "Popup", mi);
  3077. }
  3078. static void CVPaletteCheck(CharView *cv) {
  3079. if ( cvtools==NULL ) {
  3080. if ( palettes_fixed ) {
  3081. cvtoolsoff.x = 0; cvtoolsoff.y = 0;
  3082. }
  3083. CVMakeTools(cv);
  3084. }
  3085. if ( cv->b.sc->parent->multilayer && cvlayers2==NULL ) {
  3086. if ( palettes_fixed ) {
  3087. cvlayersoff.x = 0; cvlayersoff.y = CV_TOOLS_HEIGHT+45/*25*/; /* 45 is right if there's decor, 25 when none. twm gives none, kde gives decor */
  3088. }
  3089. CVMakeLayers2(cv);
  3090. } else if ( !cv->b.sc->parent->multilayer && cvlayers==NULL ) {
  3091. if ( palettes_fixed ) {
  3092. cvlayersoff.x = 0; cvlayersoff.y = CV_TOOLS_HEIGHT+45/*25*/; /* 45 is right if there's decor, 25 when none. twm gives none, kde gives decor */
  3093. }
  3094. CVMakeLayers(cv);
  3095. }
  3096. }
  3097. int CVPaletteIsVisible(CharView *cv,int which) {
  3098. CVPaletteCheck(cv);
  3099. if ( which==1 )
  3100. return( cvtools!=NULL && GDrawIsVisible(cvtools) );
  3101. if ( cv->b.sc->parent->multilayer )
  3102. return( cvlayers2!=NULL && GDrawIsVisible(cvlayers2));
  3103. return( cvlayers!=NULL && GDrawIsVisible(cvlayers) );
  3104. }
  3105. void CVPaletteSetVisible(CharView *cv,int which,int visible) {
  3106. CVPaletteCheck(cv);
  3107. if ( which==1 && cvtools!=NULL)
  3108. GDrawSetVisible(cvtools,visible );
  3109. else if ( which==0 && cv->b.sc->parent->multilayer && cvlayers2!=NULL )
  3110. GDrawSetVisible(cvlayers2,visible );
  3111. else if ( which==0 && cvlayers!=NULL )
  3112. GDrawSetVisible(cvlayers,visible );
  3113. cvvisible[which] = visible;
  3114. SavePrefs(true);
  3115. }
  3116. void CVPalettesRaise(CharView *cv) {
  3117. if ( cvtools!=NULL && GDrawIsVisible(cvtools))
  3118. GDrawRaise(cvtools);
  3119. if ( cvlayers!=NULL && GDrawIsVisible(cvlayers))
  3120. GDrawRaise(cvlayers);
  3121. if ( cvlayers2!=NULL && GDrawIsVisible(cvlayers2))
  3122. GDrawRaise(cvlayers2);
  3123. }
  3124. void _CVPaletteActivate(CharView *cv,int force) {
  3125. CharView *old;
  3126. CVPaletteCheck(cv);
  3127. if ( layers2_active!=-1 && layers2_active!=cv->b.sc->parent->multilayer ) {
  3128. if ( !cvvisible[0] ) {
  3129. if ( cvlayers2!=NULL ) GDrawSetVisible(cvlayers2,false);
  3130. if ( cvlayers !=NULL ) GDrawSetVisible(cvlayers,false);
  3131. } else if ( layers2_active && cvlayers!=NULL ) {
  3132. if ( cvlayers2!=NULL ) GDrawSetVisible(cvlayers2,false);
  3133. GDrawSetVisible(cvlayers,true);
  3134. } else if ( !layers2_active && cvlayers2!=NULL ) {
  3135. if ( cvlayers !=NULL ) GDrawSetVisible(cvlayers,false);
  3136. GDrawSetVisible(cvlayers2,true);
  3137. }
  3138. }
  3139. layers2_active = cv->b.sc->parent->multilayer;
  3140. if ( (old = GDrawGetUserData(cvtools))!=cv || force) {
  3141. if ( old!=NULL ) {
  3142. SaveOffsets(old->gw,cvtools,&cvtoolsoff);
  3143. if ( old->b.sc->parent->multilayer )
  3144. SaveOffsets(old->gw,cvlayers2,&cvlayersoff);
  3145. else
  3146. SaveOffsets(old->gw,cvlayers,&cvlayersoff);
  3147. }
  3148. GDrawSetUserData(cvtools,cv);
  3149. if ( cv->b.sc->parent->multilayer ) {
  3150. LayersSwitch(cv);
  3151. GDrawSetUserData(cvlayers2,cv);
  3152. } else {
  3153. GDrawSetUserData(cvlayers,cv);
  3154. CVLCheckLayerCount(cv,true);
  3155. }
  3156. if ( palettes_docked ) {
  3157. ReparentFixup(cvtools,cv->v,0,0,CV_TOOLS_WIDTH,CV_TOOLS_HEIGHT);
  3158. if ( cv->b.sc->parent->multilayer )
  3159. ReparentFixup(cvlayers2,cv->v,0,CV_TOOLS_HEIGHT+2,0,0);
  3160. else
  3161. ReparentFixup(cvlayers,cv->v,0,CV_TOOLS_HEIGHT+2,0,0);
  3162. } else {
  3163. if ( cvvisible[0]) {
  3164. if ( cv->b.sc->parent->multilayer )
  3165. RestoreOffsets(cv->gw,cvlayers2,&cvlayersoff);
  3166. else
  3167. RestoreOffsets(cv->gw,cvlayers,&cvlayersoff);
  3168. }
  3169. if ( cvvisible[1])
  3170. RestoreOffsets(cv->gw,cvtools,&cvtoolsoff);
  3171. }
  3172. GDrawSetVisible(cvtools,cvvisible[1]);
  3173. if ( cv->b.sc->parent->multilayer )
  3174. GDrawSetVisible(cvlayers2,cvvisible[0]);
  3175. else
  3176. GDrawSetVisible(cvlayers,cvvisible[0]);
  3177. if ( cvvisible[1]) {
  3178. cv->showing_tool = cvt_none;
  3179. CVToolsSetCursor(cv,0,NULL);
  3180. GDrawRequestExpose(cvtools,NULL,false);
  3181. }
  3182. if ( cvvisible[0])
  3183. CVLayersSet(cv);
  3184. }
  3185. if ( bvtools!=NULL ) {
  3186. BitmapView *bv = GDrawGetUserData(bvtools);
  3187. if ( bv!=NULL ) {
  3188. SaveOffsets(bv->gw,bvtools,&bvtoolsoff);
  3189. SaveOffsets(bv->gw,bvlayers,&bvlayersoff);
  3190. if ( !bv->shades_hidden )
  3191. SaveOffsets(bv->gw,bvshades,&bvshadesoff);
  3192. GDrawSetUserData(bvtools,NULL);
  3193. GDrawSetUserData(bvlayers,NULL);
  3194. GDrawSetUserData(bvshades,NULL);
  3195. }
  3196. GDrawSetVisible(bvtools,false);
  3197. GDrawSetVisible(bvlayers,false);
  3198. GDrawSetVisible(bvshades,false);
  3199. }
  3200. }
  3201. void CVPaletteActivate(CharView *cv) {
  3202. _CVPaletteActivate(cv,false);
  3203. }
  3204. void CV_LayerPaletteCheck(SplineFont *sf) {
  3205. CharView *old;
  3206. if ( cvlayers!=NULL ) {
  3207. if ( (old = GDrawGetUserData(cvlayers))!=NULL ) {
  3208. if ( old->b.sc->parent==sf )
  3209. _CVPaletteActivate(old,true);
  3210. }
  3211. }
  3212. }
  3213. /* make the charview point to the correct layer heads for the specified glyph */
  3214. void SFLayerChange(SplineFont *sf) {
  3215. CharView *old, *cv;
  3216. int i;
  3217. for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
  3218. SplineChar *sc = sf->glyphs[i];
  3219. for ( cv=(CharView *) (sc->views); cv!=NULL; cv=(CharView *) (cv->b.next) ) {
  3220. cv->b.layerheads[dm_back] = &sc->layers[ly_back];
  3221. cv->b.layerheads[dm_fore] = &sc->layers[ly_fore];
  3222. cv->b.layerheads[dm_grid] = &sf->grid;
  3223. }
  3224. }
  3225. if ( cvtools==NULL )
  3226. return; /* No charviews open */
  3227. old = GDrawGetUserData(cvtools);
  3228. if ( old==NULL || old->b.sc->parent!=sf ) /* Irrelevant */
  3229. return;
  3230. _CVPaletteActivate(old,true);
  3231. }
  3232. void CVPalettesHideIfMine(CharView *cv) {
  3233. if ( cvtools==NULL )
  3234. return;
  3235. if ( GDrawGetUserData(cvtools)==cv ) {
  3236. SaveOffsets(cv->gw,cvtools,&cvtoolsoff);
  3237. GDrawSetVisible(cvtools,false);
  3238. GDrawSetUserData(cvtools,NULL);
  3239. if ( cv->b.sc->parent->multilayer && cvlayers2!=NULL ) {
  3240. SaveOffsets(cv->gw,cvlayers2,&cvlayersoff);
  3241. GDrawSetVisible(cvlayers2,false);
  3242. GDrawSetUserData(cvlayers2,NULL);
  3243. } else {
  3244. SaveOffsets(cv->gw,cvlayers,&cvlayersoff);
  3245. GDrawSetVisible(cvlayers,false);
  3246. GDrawSetUserData(cvlayers,NULL);
  3247. }
  3248. }
  3249. }
  3250. int CVPalettesWidth(void) {
  3251. return( GGadgetScale(CV_LAYERS2_WIDTH));
  3252. }
  3253. /* ************************************************************************** */
  3254. /* **************************** Bitmap Palettes ***************************** */
  3255. /* ************************************************************************** */
  3256. static void BVLayersSet(BitmapView *bv) {
  3257. GGadgetSetChecked(GWidgetGetControl(bvlayers,CID_VFore),bv->showfore);
  3258. GGadgetSetChecked(GWidgetGetControl(bvlayers,CID_VBack),bv->showoutline);
  3259. GGadgetSetChecked(GWidgetGetControl(bvlayers,CID_VGrid),bv->showgrid);
  3260. }
  3261. static int bvlayers_e_h(GWindow gw, GEvent *event) {
  3262. BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
  3263. if ( event->type==et_destroy ) {
  3264. bvlayers = NULL;
  3265. return( true );
  3266. }
  3267. if ( bv==NULL )
  3268. return( true );
  3269. switch ( event->type ) {
  3270. case et_close:
  3271. GDrawSetVisible(gw,false);
  3272. break;
  3273. case et_char: case et_charup:
  3274. PostCharToWindow(bv->gw,event);
  3275. break;
  3276. case et_controlevent:
  3277. if ( event->u.control.subtype == et_radiochanged ) {
  3278. switch(GGadgetGetCid(event->u.control.g)) {
  3279. case CID_VFore:
  3280. BVShows.showfore = bv->showfore = GGadgetIsChecked(event->u.control.g);
  3281. break;
  3282. case CID_VBack:
  3283. BVShows.showoutline = bv->showoutline = GGadgetIsChecked(event->u.control.g);
  3284. break;
  3285. case CID_VGrid:
  3286. BVShows.showgrid = bv->showgrid = GGadgetIsChecked(event->u.control.g);
  3287. break;
  3288. }
  3289. GDrawRequestExpose(bv->v,NULL,false);
  3290. }
  3291. break;
  3292. }
  3293. return( true );
  3294. }
  3295. GWindow BVMakeLayers(BitmapView *bv) {
  3296. GRect r;
  3297. GWindowAttrs wattrs;
  3298. GGadgetCreateData gcd[8], boxes[2], *hvarray[5][3];
  3299. GTextInfo label[8];
  3300. static GBox radio_box = { bt_none, bs_rect, 0, 0, 0, 0, 0, 0, 0, 0, COLOR_DEFAULT, COLOR_DEFAULT, 0, 0, 0, 0, 0, 0, 0 };
  3301. FontRequest rq;
  3302. int i;
  3303. if ( bvlayers!=NULL )
  3304. return(bvlayers);
  3305. memset(&wattrs,0,sizeof(wattrs));
  3306. wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_positioned|wam_isdlg;
  3307. wattrs.event_masks = -1;
  3308. wattrs.cursor = ct_mypointer;
  3309. wattrs.positioned = true;
  3310. wattrs.is_dlg = true;
  3311. wattrs.utf8_window_title = _("Layers");
  3312. r.width = GGadgetScale(BV_LAYERS_WIDTH); r.height = BV_LAYERS_HEIGHT;
  3313. r.x = -r.width-6; r.y = bv->mbh+BV_TOOLS_HEIGHT+45/*25*/; /* 45 is right if there's decor, is in kde, not in twm. Sigh */
  3314. if ( palettes_docked ) {
  3315. r.x = 0; r.y = BV_TOOLS_HEIGHT+4;
  3316. } else if ( palettes_fixed ) {
  3317. r.x = 0; r.y = BV_TOOLS_HEIGHT+45;
  3318. }
  3319. bvlayers = CreatePalette( bv->gw, &r, bvlayers_e_h, bv, &wattrs, bv->v );
  3320. memset(&label,0,sizeof(label));
  3321. memset(&gcd,0,sizeof(gcd));
  3322. memset(&boxes,0,sizeof(boxes));
  3323. if ( layersfont==NULL ) {
  3324. memset(&rq,'\0',sizeof(rq));
  3325. rq.utf8_family_name = SANS_UI_FAMILIES;
  3326. rq.point_size = -12;
  3327. rq.weight = 400;
  3328. layersfont = GDrawInstanciateFont(cvlayers2,&rq);
  3329. layersfont = GResourceFindFont("LayersPalette.Font",layersfont);
  3330. }
  3331. for ( i=0; i<sizeof(label)/sizeof(label[0]); ++i )
  3332. label[i].font = layersfont;
  3333. /* GT: Abbreviation for "Visible" */
  3334. label[0].text = (unichar_t *) _("V");
  3335. label[0].text_is_1byte = true;
  3336. gcd[0].gd.label = &label[0];
  3337. gcd[0].gd.pos.x = 7; gcd[0].gd.pos.y = 5;
  3338. gcd[0].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels|gg_utf8_popup;
  3339. gcd[0].gd.popup_msg = (unichar_t *) _("Is Layer Visible?");
  3340. gcd[0].creator = GLabelCreate;
  3341. label[1].text = (unichar_t *) "Layer";
  3342. label[1].text_is_1byte = true;
  3343. gcd[1].gd.label = &label[1];
  3344. gcd[1].gd.pos.x = 23; gcd[1].gd.pos.y = 5;
  3345. gcd[1].gd.flags = gg_enabled|gg_visible|gg_pos_in_pixels|gg_utf8_popup;
  3346. gcd[1].gd.popup_msg = (unichar_t *) _("Is Layer Visible?");
  3347. gcd[1].creator = GLabelCreate;
  3348. hvarray[0][0] = &gcd[0]; hvarray[0][1] = &gcd[1]; hvarray[0][2] = NULL;
  3349. gcd[2].gd.pos.x = 5; gcd[2].gd.pos.y = 21;
  3350. gcd[2].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels|gg_utf8_popup;
  3351. gcd[2].gd.cid = CID_VFore;
  3352. gcd[2].gd.popup_msg = (unichar_t *) _("Is Layer Visible?");
  3353. gcd[2].gd.box = &radio_box;
  3354. gcd[2].creator = GCheckBoxCreate;
  3355. label[2].text = (unichar_t *) _("Bitmap");
  3356. label[2].text_is_1byte = true;
  3357. gcd[2].gd.label = &label[2];
  3358. hvarray[1][0] = &gcd[2]; hvarray[1][1] = GCD_ColSpan; hvarray[1][2] = NULL;
  3359. gcd[3].gd.pos.x = 5; gcd[3].gd.pos.y = 37;
  3360. gcd[3].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels|gg_utf8_popup;
  3361. gcd[3].gd.cid = CID_VBack;
  3362. gcd[3].gd.popup_msg = (unichar_t *) _("Is Layer Visible?");
  3363. gcd[3].gd.box = &radio_box;
  3364. gcd[3].creator = GCheckBoxCreate;
  3365. label[3].text = (unichar_t *) _("Outline");
  3366. label[3].text_is_1byte = true;
  3367. gcd[3].gd.label = &label[3];
  3368. hvarray[2][0] = &gcd[3]; hvarray[2][1] = GCD_ColSpan; hvarray[2][2] = NULL;
  3369. gcd[4].gd.pos.x = 5; gcd[4].gd.pos.y = 53;
  3370. gcd[4].gd.flags = gg_enabled|gg_visible|gg_dontcopybox|gg_pos_in_pixels|gg_utf8_popup;
  3371. gcd[4].gd.cid = CID_VGrid;
  3372. gcd[4].gd.popup_msg = (unichar_t *) _("Is Layer Visible?");
  3373. gcd[4].gd.box = &radio_box;
  3374. gcd[4].creator = GCheckBoxCreate;
  3375. label[4].text = (unichar_t *) _("_Guide");
  3376. label[4].text_is_1byte = true;
  3377. label[4].text_in_resource = true;
  3378. gcd[4].gd.label = &label[4];
  3379. hvarray[3][0] = &gcd[4]; hvarray[3][1] = GCD_ColSpan; hvarray[3][2] = NULL;
  3380. hvarray[4][0] = NULL;
  3381. if ( bv->showfore ) gcd[2].gd.flags |= gg_cb_on;
  3382. if ( bv->showoutline ) gcd[3].gd.flags |= gg_cb_on;
  3383. if ( bv->showgrid ) gcd[4].gd.flags |= gg_cb_on;
  3384. boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
  3385. boxes[0].gd.flags = gg_enabled|gg_visible;
  3386. boxes[0].gd.u.boxelements = hvarray[0];
  3387. boxes[0].creator = GHVGroupCreate;
  3388. GGadgetsCreate(bvlayers,boxes);
  3389. GHVBoxFitWindow(boxes[0].ret);
  3390. if ( bvvisible[0] )
  3391. GDrawSetVisible(bvlayers,true);
  3392. return( bvlayers );
  3393. }
  3394. struct shades_layout {
  3395. int depth;
  3396. int div;
  3397. int cnt; /* linear number of squares */
  3398. int size;
  3399. };
  3400. static void BVShadesDecompose(BitmapView *bv, struct shades_layout *lay) {
  3401. GRect r;
  3402. int temp;
  3403. GDrawGetSize(bvshades,&r);
  3404. lay->depth = BDFDepth(bv->bdf);
  3405. lay->div = 255/((1<<lay->depth)-1);
  3406. lay->cnt = lay->depth==8 ? 16 : lay->depth;
  3407. temp = r.width>r.height ? r.height : r.width;
  3408. lay->size = (temp-8+1)/lay->cnt - 1;
  3409. }
  3410. static void BVShadesExpose(GWindow pixmap, BitmapView *bv, GRect *r) {
  3411. struct shades_layout lay;
  3412. GRect old;
  3413. int i,j,index;
  3414. GRect block;
  3415. Color bg = default_background;
  3416. int greybg = (3*COLOR_RED(bg)+6*COLOR_GREEN(bg)+COLOR_BLUE(bg))/10;
  3417. GDrawSetLineWidth(pixmap,0);
  3418. BVShadesDecompose(bv,&lay);
  3419. GDrawPushClip(pixmap,r,&old);
  3420. for ( i=0; i<=lay.cnt; ++i ) {
  3421. int p = 3+i*(lay.size+1);
  3422. int m = 8+lay.cnt*(lay.size+1);
  3423. GDrawDrawLine(pixmap,p,0,p,m,bg);
  3424. GDrawDrawLine(pixmap,0,p,m,p,bg);
  3425. }
  3426. block.width = block.height = lay.size;
  3427. for ( i=0; i<lay.cnt; ++i ) {
  3428. block.y = 4 + i*(lay.size+1);
  3429. for ( j=0; j<lay.cnt; ++j ) {
  3430. block.x = 4 + j*(lay.size+1);
  3431. index = (i*lay.cnt+j)*lay.div;
  3432. if (( bv->color >= index - lay.div/2 &&
  3433. bv->color <= index + lay.div/2 ) ||
  3434. ( bv->color_under_cursor >= index - lay.div/2 &&
  3435. bv->color_under_cursor <= index + lay.div/2 )) {
  3436. GRect outline;
  3437. outline.x = block.x-1; outline.y = block.y-1;
  3438. outline.width = block.width+1; outline.height = block.height+1;
  3439. GDrawDrawRect(pixmap,&outline,
  3440. ( bv->color >= index - lay.div/2 &&
  3441. bv->color <= index + lay.div/2 )?0x00ff00:0xffffff);
  3442. }
  3443. index = (255-index) * greybg / 255;
  3444. GDrawFillRect(pixmap,&block,0x010101*index);
  3445. }
  3446. }
  3447. }
  3448. static void BVShadesMouse(BitmapView *bv, GEvent *event) {
  3449. struct shades_layout lay;
  3450. int i, j;
  3451. GGadgetEndPopup();
  3452. if ( event->type == et_mousemove && !bv->shades_down )
  3453. return;
  3454. BVShadesDecompose(bv,&lay);
  3455. if ( event->u.mouse.x<4 || event->u.mouse.y<4 ||
  3456. event->u.mouse.x>=4+lay.cnt*(lay.size+1) ||
  3457. event->u.mouse.y>=4+lay.cnt*(lay.size+1) )
  3458. return;
  3459. i = (event->u.mouse.y-4)/(lay.size+1);
  3460. j = (event->u.mouse.x-4)/(lay.size+1);
  3461. if ( bv->color != (i*lay.cnt + j)*lay.div ) {
  3462. bv->color = (i*lay.cnt + j)*lay.div;
  3463. GDrawRequestExpose(bvshades,NULL,false);
  3464. }
  3465. if ( event->type == et_mousedown ) bv->shades_down = true;
  3466. else if ( event->type == et_mouseup ) bv->shades_down = false;
  3467. if ( event->type == et_mouseup )
  3468. GDrawRequestExpose(bv->gw,NULL,false);
  3469. }
  3470. static int bvshades_e_h(GWindow gw, GEvent *event) {
  3471. BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
  3472. if ( event->type==et_destroy ) {
  3473. bvshades = NULL;
  3474. return( true );
  3475. }
  3476. if ( bv==NULL )
  3477. return( true );
  3478. switch ( event->type ) {
  3479. case et_expose:
  3480. BVShadesExpose(gw,bv,&event->u.expose.rect);
  3481. break;
  3482. case et_mousemove:
  3483. case et_mouseup:
  3484. case et_mousedown:
  3485. BVShadesMouse(bv,event);
  3486. break;
  3487. break;
  3488. case et_char: case et_charup:
  3489. PostCharToWindow(bv->gw,event);
  3490. break;
  3491. case et_destroy:
  3492. break;
  3493. case et_close:
  3494. GDrawSetVisible(gw,false);
  3495. break;
  3496. }
  3497. return( true );
  3498. }
  3499. static GWindow BVMakeShades(BitmapView *bv) {
  3500. GRect r;
  3501. GWindowAttrs wattrs;
  3502. if ( bvshades!=NULL )
  3503. return( bvshades );
  3504. memset(&wattrs,0,sizeof(wattrs));
  3505. wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_positioned|wam_isdlg/*|wam_backcol*/;
  3506. wattrs.event_masks = -1;
  3507. wattrs.cursor = ct_eyedropper;
  3508. wattrs.positioned = true;
  3509. wattrs.is_dlg = true;
  3510. wattrs.background_color = 0xffffff;
  3511. wattrs.utf8_window_title = _("Shades");
  3512. r.width = BV_SHADES_HEIGHT; r.height = r.width;
  3513. r.x = -r.width-6; r.y = bv->mbh+225;
  3514. if ( palettes_docked ) {
  3515. r.x = 0; r.y = BV_TOOLS_HEIGHT+BV_LAYERS_HEIGHT+4;
  3516. } else if ( palettes_fixed ) {
  3517. r.x = 0; r.y = BV_TOOLS_HEIGHT+BV_LAYERS_HEIGHT+90;
  3518. }
  3519. bvshades = CreatePalette( bv->gw, &r, bvshades_e_h, bv, &wattrs, bv->v );
  3520. bv->shades_hidden = BDFDepth(bv->bdf)==1;
  3521. if ( bvvisible[2] && !bv->shades_hidden )
  3522. GDrawSetVisible(bvshades,true);
  3523. return( bvshades );
  3524. }
  3525. static char *bvpopups[] = { N_("Pointer"), N_("Magnify (Minify with alt)"),
  3526. N_("Set/Clear Pixels"), N_("Draw a Line"),
  3527. N_("Shift Entire Bitmap"), N_("Scroll Bitmap") };
  3528. static void BVToolsExpose(GWindow pixmap, BitmapView *bv, GRect *r) {
  3529. GRect old;
  3530. /* Note: If you change this ordering, change enum bvtools */
  3531. static GImage *buttons[][2] = { { &GIcon_pointer, &GIcon_magnify },
  3532. { &GIcon_pencil, &GIcon_line },
  3533. { &GIcon_shift, &GIcon_hand }};
  3534. int i,j,norm;
  3535. int tool = bv->cntrldown?bv->cb1_tool:bv->b1_tool;
  3536. int dither = GDrawSetDither(NULL,false);
  3537. GDrawPushClip(pixmap,r,&old);
  3538. GDrawSetLineWidth(pixmap,0);
  3539. for ( i=0; i<sizeof(buttons)/sizeof(buttons[0]); ++i ) for ( j=0; j<2; ++j ) {
  3540. GDrawDrawImage(pixmap,buttons[i][j],NULL,j*27+1,i*27+1);
  3541. norm = (i*2+j!=tool);
  3542. GDrawDrawLine(pixmap,j*27,i*27,j*27+25,i*27,norm?0xe0e0e0:0x707070);
  3543. GDrawDrawLine(pixmap,j*27,i*27,j*27,i*27+25,norm?0xe0e0e0:0x707070);
  3544. GDrawDrawLine(pixmap,j*27,i*27+25,j*27+25,i*27+25,norm?0x707070:0xe0e0e0);
  3545. GDrawDrawLine(pixmap,j*27+25,i*27,j*27+25,i*27+25,norm?0x707070:0xe0e0e0);
  3546. }
  3547. GDrawPopClip(pixmap,&old);
  3548. GDrawSetDither(NULL,dither);
  3549. }
  3550. void BVToolsSetCursor(BitmapView *bv, int state,char *device) {
  3551. int shouldshow;
  3552. static enum bvtools tools[bvt_max2+1] = { bvt_none };
  3553. int cntrl;
  3554. if ( tools[0] == bvt_none ) {
  3555. tools[bvt_pointer] = ct_mypointer;
  3556. tools[bvt_magnify] = ct_magplus;
  3557. tools[bvt_pencil] = ct_pencil;
  3558. tools[bvt_line] = ct_line;
  3559. tools[bvt_shift] = ct_shift;
  3560. tools[bvt_hand] = ct_myhand;
  3561. tools[bvt_minify] = ct_magminus;
  3562. tools[bvt_eyedropper] = ct_eyedropper;
  3563. tools[bvt_setwidth] = ct_setwidth;
  3564. tools[bvt_setvwidth] = ct_updown;
  3565. tools[bvt_rect] = ct_rect;
  3566. tools[bvt_filledrect] = ct_filledrect;
  3567. tools[bvt_elipse] = ct_elipse;
  3568. tools[bvt_filledelipse] = ct_filledelipse;
  3569. }
  3570. shouldshow = bvt_none;
  3571. if ( bv->active_tool!=bvt_none )
  3572. shouldshow = bv->active_tool;
  3573. else if ( bv->pressed_display!=bvt_none )
  3574. shouldshow = bv->pressed_display;
  3575. else if ( device==NULL || strcmp(device,"Mouse1")==0 ) {
  3576. if ( (state&(ksm_shift|ksm_control)) && (state&ksm_button4))
  3577. shouldshow = bvt_magnify;
  3578. else if ( (state&(ksm_shift|ksm_control)) && (state&ksm_button5))
  3579. shouldshow = bvt_minify;
  3580. else if ( (state&ksm_control) && (state&(ksm_button2|ksm_super)) )
  3581. shouldshow = bv->cb2_tool;
  3582. else if ( (state&(ksm_button2|ksm_super)) )
  3583. shouldshow = bv->b2_tool;
  3584. else if ( (state&ksm_control) )
  3585. shouldshow = bv->cb1_tool;
  3586. else
  3587. shouldshow = bv->b1_tool;
  3588. } else if ( strcmp(device,"eraser")==0 )
  3589. shouldshow = bv->er_tool;
  3590. else if ( strcmp(device,"stylus")==0 ) {
  3591. if ( (state&(ksm_button2|ksm_control|ksm_super)) )
  3592. shouldshow = bv->s2_tool;
  3593. else
  3594. shouldshow = bv->s1_tool;
  3595. }
  3596. if ( shouldshow==bvt_magnify && (state&ksm_meta))
  3597. shouldshow = bvt_minify;
  3598. if ( (shouldshow==bvt_pencil || shouldshow==bvt_line) && (state&ksm_meta) && bv->bdf->clut!=NULL )
  3599. shouldshow = bvt_eyedropper;
  3600. if ( shouldshow!=bv->showing_tool ) {
  3601. GDrawSetCursor(bv->v,tools[shouldshow]);
  3602. if ( bvtools != NULL )
  3603. GDrawSetCursor(bvtools,tools[shouldshow]);
  3604. bv->showing_tool = shouldshow;
  3605. }
  3606. if ( device==NULL || strcmp(device,"stylus")==0 ) {
  3607. cntrl = (state&ksm_control)?1:0;
  3608. if ( device!=NULL && (state&ksm_button2))
  3609. cntrl = true;
  3610. if ( cntrl != bv->cntrldown ) {
  3611. bv->cntrldown = cntrl;
  3612. GDrawRequestExpose(bvtools,NULL,false);
  3613. }
  3614. }
  3615. }
  3616. static void BVToolsMouse(BitmapView *bv, GEvent *event) {
  3617. int i = (event->u.mouse.y/27), j = (event->u.mouse.x/27);
  3618. int pos;
  3619. int isstylus = event->u.mouse.device!=NULL && strcmp(event->u.mouse.device,"stylus")==0;
  3620. int styluscntl = isstylus && (event->u.mouse.state&0x200);
  3621. if(j >= 2)
  3622. return; /* If the wm gave me a window the wrong size */
  3623. pos = i*2 + j;
  3624. GGadgetEndPopup();
  3625. if ( pos<0 || pos>=bvt_max )
  3626. pos = bvt_none;
  3627. if ( event->type == et_mousedown ) {
  3628. if ( isstylus && event->u.mouse.button==2 )
  3629. /* Not a real button press, only touch counts. This is a modifier */;
  3630. else {
  3631. bv->pressed_tool = bv->pressed_display = pos;
  3632. bv->had_control = ((event->u.mouse.state&ksm_control) || styluscntl)?1:0;
  3633. event->u.chr.state |= (1<<(7+event->u.mouse.button));
  3634. }
  3635. } else if ( event->type == et_mousemove ) {
  3636. if ( bv->pressed_tool==bvt_none && pos!=bvt_none ) {
  3637. /* Not pressed */
  3638. if ( !bv->shades_hidden && strcmp(bvpopups[pos],"Set/Clear Pixels")==0 )
  3639. GGadgetPreparePopup8(bvtools,_("Set/Clear Pixels\n(Eyedropper with alt)"));
  3640. else
  3641. GGadgetPreparePopup8(bvtools,_(bvpopups[pos]));
  3642. } else if ( pos!=bv->pressed_tool || bv->had_control != (((event->u.mouse.state&ksm_control)||styluscntl)?1:0) )
  3643. bv->pressed_display = bvt_none;
  3644. else
  3645. bv->pressed_display = bv->pressed_tool;
  3646. } else if ( event->type == et_mouseup ) {
  3647. if ( pos!=bv->pressed_tool || bv->had_control != (((event->u.mouse.state&ksm_control)||styluscntl)?1:0) )
  3648. bv->pressed_tool = bv->pressed_display = bvt_none;
  3649. else {
  3650. if ( event->u.mouse.device!=NULL && strcmp(event->u.mouse.device,"eraser")==0 )
  3651. bv->er_tool = pos;
  3652. else if ( isstylus ) {
  3653. if ( event->u.mouse.button==2 )
  3654. /* Only thing that matters is touch which maps to button 1 */;
  3655. else if ( bv->had_control )
  3656. bv->s2_tool = pos;
  3657. else
  3658. bv->s1_tool = pos;
  3659. } else if ( bv->had_control && event->u.mouse.button==2 )
  3660. bv->cb2_tool = pos;
  3661. else if ( event->u.mouse.button==2 )
  3662. bv->b2_tool = pos;
  3663. else if ( bv->had_control ) {
  3664. if ( bv->cb1_tool!=pos ) {
  3665. bv->cb1_tool = pos;
  3666. GDrawRequestExpose(bvtools,NULL,false);
  3667. }
  3668. } else {
  3669. if ( bv->b1_tool!=pos ) {
  3670. bv->b1_tool = pos;
  3671. GDrawRequestExpose(bvtools,NULL,false);
  3672. }
  3673. }
  3674. bv->pressed_tool = bv->pressed_display = bvt_none;
  3675. }
  3676. event->u.mouse.state &= ~(1<<(7+event->u.mouse.button));
  3677. }
  3678. BVToolsSetCursor(bv,event->u.mouse.state,event->u.mouse.device);
  3679. }
  3680. static int bvtools_e_h(GWindow gw, GEvent *event) {
  3681. BitmapView *bv = (BitmapView *) GDrawGetUserData(gw);
  3682. if ( event->type==et_destroy ) {
  3683. bvtools = NULL;
  3684. return( true );
  3685. }
  3686. if ( bv==NULL )
  3687. return( true );
  3688. switch ( event->type ) {
  3689. case et_expose:
  3690. BVToolsExpose(gw,bv,&event->u.expose.rect);
  3691. break;
  3692. case et_mousedown:
  3693. BVToolsMouse(bv,event);
  3694. break;
  3695. case et_mousemove:
  3696. BVToolsMouse(bv,event);
  3697. break;
  3698. case et_mouseup:
  3699. BVToolsMouse(bv,event);
  3700. break;
  3701. case et_crossing:
  3702. bv->pressed_display = bvt_none;
  3703. BVToolsSetCursor(bv,event->u.mouse.state,event->u.mouse.device);
  3704. break;
  3705. case et_char: case et_charup:
  3706. if ( bv->had_control != ((event->u.chr.state&ksm_control)?1:0) )
  3707. bv->pressed_display = bvt_none;
  3708. PostCharToWindow(bv->gw,event);
  3709. break;
  3710. case et_close:
  3711. GDrawSetVisible(gw,false);
  3712. break;
  3713. }
  3714. return( true );
  3715. }
  3716. GWindow BVMakeTools(BitmapView *bv) {
  3717. GRect r;
  3718. GWindowAttrs wattrs;
  3719. if ( bvtools!=NULL )
  3720. return( bvtools );
  3721. memset(&wattrs,0,sizeof(wattrs));
  3722. wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_positioned|wam_isdlg;
  3723. wattrs.event_masks = -1;
  3724. wattrs.cursor = ct_mypointer;
  3725. wattrs.positioned = true;
  3726. wattrs.is_dlg = true;
  3727. wattrs.utf8_window_title = _("Tools");
  3728. r.width = BV_TOOLS_WIDTH; r.height = BV_TOOLS_HEIGHT;
  3729. r.x = -r.width-6; r.y = bv->mbh+20;
  3730. if ( palettes_fixed || palettes_docked ) {
  3731. r.x = 0; r.y = 0;
  3732. }
  3733. bvtools = CreatePalette( bv->gw, &r, bvtools_e_h, bv, &wattrs, bv->v );
  3734. if ( bvvisible[1] )
  3735. GDrawSetVisible(bvtools,true);
  3736. return( bvtools );
  3737. }
  3738. static void BVPopupInvoked(GWindow v, GMenuItem *mi,GEvent *e) {
  3739. BitmapView *bv = (BitmapView *) GDrawGetUserData(v);
  3740. int pos;
  3741. pos = mi->mid;
  3742. if ( bv->had_control ) {
  3743. if ( bv->cb1_tool!=pos ) {
  3744. bv->cb1_tool = pos;
  3745. GDrawRequestExpose(bvtools,NULL,false);
  3746. }
  3747. } else {
  3748. if ( bv->b1_tool!=pos ) {
  3749. bv->b1_tool = pos;
  3750. GDrawRequestExpose(bvtools,NULL,false);
  3751. }
  3752. }
  3753. BVToolsSetCursor(bv,bv->had_control?ksm_control:0,NULL);
  3754. }
  3755. void BVToolsPopup(BitmapView *bv, GEvent *event) {
  3756. GMenuItem mi[21];
  3757. int i, j;
  3758. memset(mi,'\0',sizeof(mi));
  3759. for ( i=0;i<6; ++i ) {
  3760. mi[i].ti.text = (unichar_t *) _(bvpopups[i]);
  3761. mi[i].ti.text_is_1byte = true;
  3762. mi[i].ti.fg = COLOR_DEFAULT;
  3763. mi[i].ti.bg = COLOR_DEFAULT;
  3764. mi[i].mid = i;
  3765. mi[i].invoke = BVPopupInvoked;
  3766. }
  3767. mi[i].ti.text = (unichar_t *) _("Rectangle");
  3768. mi[i].ti.text_is_1byte = true;
  3769. mi[i].ti.fg = COLOR_DEFAULT;
  3770. mi[i].ti.bg = COLOR_DEFAULT;
  3771. mi[i].mid = bvt_rect;
  3772. mi[i++].invoke = BVPopupInvoked;
  3773. mi[i].ti.text = (unichar_t *) _("Filled Rectangle"); mi[i].ti.text_is_1byte = true;
  3774. mi[i].ti.fg = COLOR_DEFAULT;
  3775. mi[i].ti.bg = COLOR_DEFAULT;
  3776. mi[i].mid = bvt_filledrect;
  3777. mi[i++].invoke = BVPopupInvoked;
  3778. mi[i].ti.text = (unichar_t *) _("Ellipse"); mi[i].ti.text_is_1byte = true;
  3779. mi[i].ti.fg = COLOR_DEFAULT;
  3780. mi[i].ti.bg = COLOR_DEFAULT;
  3781. mi[i].mid = bvt_elipse;
  3782. mi[i++].invoke = BVPopupInvoked;
  3783. mi[i].ti.text = (unichar_t *) _("Filled Ellipse"); mi[i].ti.text_is_1byte = true;
  3784. mi[i].ti.fg = COLOR_DEFAULT;
  3785. mi[i].ti.bg = COLOR_DEFAULT;
  3786. mi[i].mid = bvt_filledelipse;
  3787. mi[i++].invoke = BVPopupInvoked;
  3788. mi[i].ti.fg = COLOR_DEFAULT;
  3789. mi[i].ti.bg = COLOR_DEFAULT;
  3790. mi[i++].ti.line = true;
  3791. for ( j=0; j<6; ++j, ++i ) {
  3792. mi[i].ti.text = (unichar_t *) BVFlipNames[j];
  3793. mi[i].ti.text_is_1byte = true;
  3794. mi[i].ti.fg = COLOR_DEFAULT;
  3795. mi[i].ti.bg = COLOR_DEFAULT;
  3796. mi[i].mid = j;
  3797. mi[i].invoke = BVMenuRotateInvoked;
  3798. }
  3799. if ( bv->fv->b.sf->onlybitmaps ) {
  3800. mi[i].ti.fg = COLOR_DEFAULT;
  3801. mi[i].ti.bg = COLOR_DEFAULT;
  3802. mi[i++].ti.line = true;
  3803. mi[i].ti.text = (unichar_t *) _("Set _Width...");
  3804. mi[i].ti.text_is_1byte = true;
  3805. mi[i].ti.text_in_resource = true;
  3806. mi[i].ti.fg = COLOR_DEFAULT;
  3807. mi[i].ti.bg = COLOR_DEFAULT;
  3808. mi[i].mid = bvt_setwidth;
  3809. mi[i].invoke = BVPopupInvoked;
  3810. }
  3811. bv->had_control = (event->u.mouse.state&ksm_control)?1:0;
  3812. GMenuCreatePopupMenu(bv->v,event, mi);
  3813. }
  3814. static void BVPaletteCheck(BitmapView *bv) {
  3815. if ( bvtools==NULL ) {
  3816. BVMakeTools(bv);
  3817. BVMakeLayers(bv);
  3818. BVMakeShades(bv);
  3819. }
  3820. }
  3821. int BVPaletteIsVisible(BitmapView *bv,int which) {
  3822. BVPaletteCheck(bv);
  3823. if ( which==1 )
  3824. return( bvtools!=NULL && GDrawIsVisible(bvtools) );
  3825. if ( which==2 )
  3826. return( bvshades!=NULL && GDrawIsVisible(bvshades) );
  3827. return( bvlayers!=NULL && GDrawIsVisible(bvlayers) );
  3828. }
  3829. void BVPaletteSetVisible(BitmapView *bv,int which,int visible) {
  3830. BVPaletteCheck(bv);
  3831. if ( which==1 && bvtools!=NULL)
  3832. GDrawSetVisible(bvtools,visible );
  3833. else if ( which==2 && bvshades!=NULL)
  3834. GDrawSetVisible(bvshades,visible );
  3835. else if ( which==0 && bvlayers!=NULL )
  3836. GDrawSetVisible(bvlayers,visible );
  3837. bvvisible[which] = visible;
  3838. SavePrefs(true);
  3839. }
  3840. void BVPaletteActivate(BitmapView *bv) {
  3841. BitmapView *old;
  3842. BVPaletteCheck(bv);
  3843. if ( (old = GDrawGetUserData(bvtools))!=bv ) {
  3844. if ( old!=NULL ) {
  3845. SaveOffsets(old->gw,bvtools,&bvtoolsoff);
  3846. SaveOffsets(old->gw,bvlayers,&bvlayersoff);
  3847. SaveOffsets(old->gw,bvshades,&bvshadesoff);
  3848. }
  3849. GDrawSetUserData(bvtools,bv);
  3850. GDrawSetUserData(bvlayers,bv);
  3851. GDrawSetUserData(bvshades,bv);
  3852. if ( palettes_docked ) {
  3853. ReparentFixup(bvtools,bv->v,0,0,BV_TOOLS_WIDTH,BV_TOOLS_HEIGHT);
  3854. ReparentFixup(bvlayers,bv->v,0,BV_TOOLS_HEIGHT+2,0,0);
  3855. ReparentFixup(bvshades,bv->v,0,BV_TOOLS_HEIGHT+BV_TOOLS_HEIGHT+4,0,0);
  3856. } else {
  3857. if ( bvvisible[0])
  3858. RestoreOffsets(bv->gw,bvlayers,&bvlayersoff);
  3859. if ( bvvisible[1])
  3860. RestoreOffsets(bv->gw,bvtools,&bvtoolsoff);
  3861. if ( bvvisible[2] && !bv->shades_hidden )
  3862. RestoreOffsets(bv->gw,bvshades,&bvshadesoff);
  3863. }
  3864. GDrawSetVisible(bvtools,bvvisible[1]);
  3865. GDrawSetVisible(bvlayers,bvvisible[0]);
  3866. GDrawSetVisible(bvshades,bvvisible[2] && bv->bdf->clut!=NULL);
  3867. if ( bvvisible[1]) {
  3868. bv->showing_tool = bvt_none;
  3869. BVToolsSetCursor(bv,0,NULL);
  3870. GDrawRequestExpose(bvtools,NULL,false);
  3871. }
  3872. if ( bvvisible[0])
  3873. BVLayersSet(bv);
  3874. if ( bvvisible[2] && !bv->shades_hidden )
  3875. GDrawRequestExpose(bvtools,NULL,false);
  3876. }
  3877. if ( cvtools!=NULL ) {
  3878. CharView *cv = GDrawGetUserData(cvtools);
  3879. if ( cv!=NULL ) {
  3880. SaveOffsets(cv->gw,cvtools,&cvtoolsoff);
  3881. SaveOffsets(cv->gw,cvlayers,&cvlayersoff);
  3882. GDrawSetUserData(cvtools,NULL);
  3883. if ( cvlayers!=NULL )
  3884. GDrawSetUserData(cvlayers,NULL);
  3885. if ( cvlayers2!=NULL )
  3886. GDrawSetUserData(cvlayers2,NULL);
  3887. }
  3888. GDrawSetVisible(cvtools,false);
  3889. if ( cvlayers!=NULL )
  3890. GDrawSetVisible(cvlayers,false);
  3891. if ( cvlayers2!=NULL )
  3892. GDrawSetVisible(cvlayers2,false);
  3893. }
  3894. }
  3895. void BVPalettesHideIfMine(BitmapView *bv) {
  3896. if ( bvtools==NULL )
  3897. return;
  3898. if ( GDrawGetUserData(bvtools)==bv ) {
  3899. SaveOffsets(bv->gw,bvtools,&bvtoolsoff);
  3900. SaveOffsets(bv->gw,bvlayers,&bvlayersoff);
  3901. SaveOffsets(bv->gw,bvshades,&bvshadesoff);
  3902. GDrawSetVisible(bvtools,false);
  3903. GDrawSetVisible(bvlayers,false);
  3904. GDrawSetVisible(bvshades,false);
  3905. GDrawSetUserData(bvtools,NULL);
  3906. GDrawSetUserData(bvlayers,NULL);
  3907. GDrawSetUserData(bvshades,NULL);
  3908. }
  3909. }
  3910. void CVPaletteDeactivate(void) {
  3911. if ( cvtools!=NULL ) {
  3912. CharView *cv = GDrawGetUserData(cvtools);
  3913. if ( cv!=NULL ) {
  3914. SaveOffsets(cv->gw,cvtools,&cvtoolsoff);
  3915. GDrawSetUserData(cvtools,NULL);
  3916. if ( cv->b.sc->parent->multilayer && cvlayers2!=NULL ) {
  3917. SaveOffsets(cv->gw,cvlayers2,&cvlayersoff);
  3918. GDrawSetUserData(cvlayers2,NULL);
  3919. } else if ( cvlayers!=NULL ) {
  3920. SaveOffsets(cv->gw,cvlayers,&cvlayersoff);
  3921. GDrawSetUserData(cvlayers,NULL);
  3922. }
  3923. }
  3924. GDrawSetVisible(cvtools,false);
  3925. if ( cvlayers!=NULL )
  3926. GDrawSetVisible(cvlayers,false);
  3927. if ( cvlayers2!=NULL )
  3928. GDrawSetVisible(cvlayers2,false);
  3929. }
  3930. if ( bvtools!=NULL ) {
  3931. BitmapView *bv = GDrawGetUserData(bvtools);
  3932. if ( bv!=NULL ) {
  3933. SaveOffsets(bv->gw,bvtools,&bvtoolsoff);
  3934. SaveOffsets(bv->gw,bvlayers,&bvlayersoff);
  3935. SaveOffsets(bv->gw,bvshades,&bvshadesoff);
  3936. GDrawSetUserData(bvtools,NULL);
  3937. GDrawSetUserData(bvlayers,NULL);
  3938. GDrawSetUserData(bvshades,NULL);
  3939. }
  3940. GDrawSetVisible(bvtools,false);
  3941. GDrawSetVisible(bvlayers,false);
  3942. GDrawSetVisible(bvshades,false);
  3943. }
  3944. }
  3945. void BVPaletteColorChange(BitmapView *bv) {
  3946. if ( bvshades!=NULL )
  3947. GDrawRequestExpose(bvshades,NULL,false);
  3948. GDrawRequestExpose(bv->gw,NULL,false);
  3949. }
  3950. void BVPaletteColorUnderChange(BitmapView *bv,int color_under) {
  3951. if ( bvshades!=NULL && color_under!=bv->color_under_cursor ) {
  3952. bv->color_under_cursor = color_under;
  3953. GDrawRequestExpose(bvshades,NULL,false);
  3954. }
  3955. }
  3956. void BVPaletteChangedChar(BitmapView *bv) {
  3957. if ( bvshades!=NULL && bvvisible[2]) {
  3958. int hidden = bv->bdf->clut==NULL;
  3959. if ( hidden!=bv->shades_hidden ) {
  3960. GDrawSetVisible(bvshades,!hidden);
  3961. bv->shades_hidden = hidden;
  3962. GDrawRequestExpose(bv->gw,NULL,false);
  3963. } else
  3964. GDrawRequestExpose(bvshades,NULL,false);
  3965. }
  3966. }
  3967. void PalettesChangeDocking(void) {
  3968. palettes_docked = !palettes_docked;
  3969. if ( palettes_docked ) {
  3970. if ( cvtools!=NULL ) {
  3971. CharView *cv = GDrawGetUserData(cvtools);
  3972. if ( cv!=NULL ) {
  3973. ReparentFixup(cvtools,cv->v,0,0,CV_TOOLS_WIDTH,CV_TOOLS_HEIGHT);
  3974. if ( cvlayers!=NULL )
  3975. ReparentFixup(cvlayers,cv->v,0,CV_TOOLS_HEIGHT+2,0,0);
  3976. if ( cvlayers2!=NULL )
  3977. ReparentFixup(cvlayers2,cv->v,0,CV_TOOLS_HEIGHT+2,0,0);
  3978. }
  3979. }
  3980. if ( bvtools!=NULL ) {
  3981. BitmapView *bv = GDrawGetUserData(bvtools);
  3982. if ( bv!=NULL ) {
  3983. ReparentFixup(bvtools,bv->v,0,0,BV_TOOLS_WIDTH,BV_TOOLS_HEIGHT);
  3984. ReparentFixup(bvlayers,bv->v,0,BV_TOOLS_HEIGHT+2,0,0);
  3985. ReparentFixup(bvshades,bv->v,0,BV_TOOLS_HEIGHT+BV_LAYERS_HEIGHT+4,0,0);
  3986. }
  3987. }
  3988. } else {
  3989. if ( cvtools!=NULL ) {
  3990. GDrawReparentWindow(cvtools,GDrawGetRoot(NULL),0,0);
  3991. if ( cvlayers!=NULL )
  3992. GDrawReparentWindow(cvlayers,GDrawGetRoot(NULL),0,CV_TOOLS_HEIGHT+2+45);
  3993. if ( cvlayers2!=NULL )
  3994. GDrawReparentWindow(cvlayers2,GDrawGetRoot(NULL),0,CV_TOOLS_HEIGHT+2+45);
  3995. }
  3996. if ( bvtools!=NULL ) {
  3997. GDrawReparentWindow(bvtools,GDrawGetRoot(NULL),0,0);
  3998. GDrawReparentWindow(bvlayers,GDrawGetRoot(NULL),0,BV_TOOLS_HEIGHT+2+45);
  3999. GDrawReparentWindow(bvshades,GDrawGetRoot(NULL),0,BV_TOOLS_HEIGHT+BV_LAYERS_HEIGHT+4+90);
  4000. }
  4001. }
  4002. SavePrefs(true);
  4003. }
  4004. int BVPalettesWidth(void) {
  4005. return( GGadgetScale(BV_LAYERS_WIDTH));
  4006. }