Index: config.doc
==================================================================
--- config.doc
+++ config.doc
@@ -80,10 +80,14 @@
 
 .pasteCommand
   The command to use for pasting text from the clipboard. When it asks for
   a single line of text, you can push SHIFT+INSERT to paste.
 
+.picedit.macro.?
+  Define a macro in the picture editor, if you push ALT and a letter,
+  will execute a SQL statement.
+
 .progress
   If positive, how many steps between dots in the progress report for the
   auto testing mode. If negative, number of milliseconds to sleep before
   each level is executed.
 

Index: picedit.c
==================================================================
--- picedit.c
+++ picedit.c
@@ -64,10 +64,11 @@
 
 static Uint8 cur_type;
 static Uint8 gsizes[16];
 static Picture*cur_pic;
 static Picture*spare_page;
+static sqlite3_stmt**macro[26];
 
 static void fn_valid_name(sqlite3_context*cxt,int argc,sqlite3_value**argv) {
   const char*s=sqlite3_value_text(*argv);
   if(!s || !*s || s[strspn(s,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-0123456789")]) {
     sqlite3_result_error(cxt,"Invalid name",-1);
@@ -158,10 +159,23 @@
   .xNext=vt_graph_next,
   .xOpen=vt_graph_open,
   .xRowid=vt_graph_rowid,
   .xUpdate=vt_graph_update,
 };
+
+static void*load_macros_1(xrm_db*db,void*usr,int loose,xrm_quark q) {
+  const char*txt;
+  if(q<Q_A || q>Q_Z) return 0;
+  if(!(db=xrm_sub(db,loose,q)) || !(txt=xrm_get(db))) return 0;
+  if(sqlite3_prepare_v3(userdb,txt,-1,SQLITE_PREPARE_PERSISTENT,macro+(q-Q_A),0)) fatal("Error in macro:  %s\n%s\n",txt,sqlite3_errmsg(userdb));
+  return 0;
+}
+
+static void*load_macros(xrm_db*db,void*usr) {
+  xrm_enumerate(db,load_macros_1,0);
+  return 0;
+}
 
 static int load_picture_file(void) {
   sqlite3_stmt*st=0;
   FILE*fp;
   char*nam;
@@ -910,10 +924,41 @@
           }
           goto redraw;
         }
         break;
       case SDL_KEYDOWN:
+        if((ev.key.keysym.mod&(KMOD_ALT|KMOD_META)) && ev.key.keysym.sym>=SDLK_a && ev.key.keysym.sym<=SDLK_z) {
+          sqlite3_stmt*st=macro[ev.key.keysym.sym-SDLK_a];
+          if(!st) goto redraw;
+          sqlite3_reset(st);
+          sqlite3_bind_int(st,sqlite3_bind_parameter_index(st,"$cc"),cc);
+          sqlite3_bind_int(st,sqlite3_bind_parameter_index(st,"$xx"),xx);
+          sqlite3_bind_int(st,sqlite3_bind_parameter_index(st,"$yy"),yy);
+          sqlite3_bind_int(st,sqlite3_bind_parameter_index(st,"$mx"),m.x);
+          sqlite3_bind_int(st,sqlite3_bind_parameter_index(st,"$my"),m.y);
+          sqlite3_bind_int(st,sqlite3_bind_parameter_index(st,"$mw"),m.w);
+          sqlite3_bind_int(st,sqlite3_bind_parameter_index(st,"$mh"),m.h);
+          while((i=sqlite3_step(st))==SQLITE_ROW) {
+            for(j=0;j<sqlite3_data_count(st);) switch(sqlite3_column_int(st,j++)) {
+              case 1:
+                xx=sqlite3_column_int(st,j++);
+                yy=sqlite3_column_int(st,j++);
+                break;
+              case 2:
+                m.x=sqlite3_column_int(st,j++);
+                m.y=sqlite3_column_int(st,j++);
+                m.w=sqlite3_column_int(st,j++);
+                m.h=sqlite3_column_int(st,j++);
+                break;
+              case 3:
+                cc=sqlite3_column_int(st,j++);
+                break;
+            }
+          }
+          if(i!=SQLITE_DONE) screen_message(sqlite3_errmsg(userdb));
+          goto redraw;
+        }
         switch(ev.key.keysym.sym) {
           case SDLK_ESCAPE: return;
           case SDLK_LEFTBRACKET: case SDLK_LEFTPAREN: --sel; m.x=m.y=m.w=m.h=0; goto redraw;
           case SDLK_RIGHTBRACKET: case SDLK_RIGHTPAREN: ++sel; m.x=m.y=m.w=m.h=0; goto redraw;
           case SDLK_1 ... SDLK_9: sel=ev.key.keysym.sym-SDLK_1; m.x=m.y=m.w=m.h=0; goto redraw;
@@ -1626,10 +1671,13 @@
   sqlite3_create_function(userdb,"VALID_NAME",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_valid_name,0,0);
   sqlite3_create_module(userdb,"GRAPH",&vt_graph,0);
   init_palette();
   optionquery[1]=Q_imageSize;
   picture_size=strtol(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"16",0,10);
+  optionquery[1]=Q_picedit;
+  optionquery[2]=Q_macro;
+  xrm_search(resourcedb,optionquery,optionquery,3,load_macros,0);
   if(!*gsizes) *gsizes=picture_size;
   set_cursor(XC_arrow);
   set_caption();
   i=sqlite3_prepare_v3(userdb,"SELECT `ID`,SUBSTR(`NAME`,1,LENGTH(`NAME`)-4),`TYPE` FROM `PICEDIT` WHERE `TYPE` ORDER BY `NAME` LIMIT ?1 OFFSET ?2;",-1,SQLITE_PREPARE_PERSISTENT,&st,0);
   if(i) fatal("SQL error (%d): %s\n",i,sqlite3_errmsg(userdb));

Index: quarks
==================================================================
--- quarks
+++ quarks
@@ -196,10 +196,14 @@
 
 ! Solutions
 saveSolutions
 solutionComment
 solutionTimestamp
+
+! Picture editor
+picedit
+macro
 
 ! SQL settings
 sqlFile
 sqlInit
 sqlExtensions

Index: quarks.h
==================================================================
--- quarks.h
+++ quarks.h
@@ -165,31 +165,33 @@
 #define Q_class 166
 #define Q_quiz 167
 #define Q_saveSolutions 168
 #define Q_solutionComment 169
 #define Q_solutionTimestamp 170
-#define Q_sqlFile 171
-#define Q_sqlInit 172
-#define Q_sqlExtensions 173
-#define Q_sqlMemStatus 174
-#define Q_sqlSmallAllocations 175
-#define Q_sqlCoveringIndexScan 176
-#define Q_sqlPowerSafe 177
-#define Q_level 178
-#define Q_tracePrefix 179
-#define Q_stackProtection 180
-#define Q_maxObjects 181
-#define Q_traceAll 182
-#define Q_traceObject 183
-#define Q_showInventory 184
-#define Q_progress 185
-#define Q_autoSave 186
-#define Q_maxTrigger 187
-#define Q_pasteCommand 188
-#define Q_codepage 189
-#define Q_replaySpeed 190
-#define Q_autoWin 191
+#define Q_picedit 171
+#define Q_macro 172
+#define Q_sqlFile 173
+#define Q_sqlInit 174
+#define Q_sqlExtensions 175
+#define Q_sqlMemStatus 176
+#define Q_sqlSmallAllocations 177
+#define Q_sqlCoveringIndexScan 178
+#define Q_sqlPowerSafe 179
+#define Q_level 180
+#define Q_tracePrefix 181
+#define Q_stackProtection 182
+#define Q_maxObjects 183
+#define Q_traceAll 184
+#define Q_traceObject 185
+#define Q_showInventory 186
+#define Q_progress 187
+#define Q_autoSave 188
+#define Q_maxTrigger 189
+#define Q_pasteCommand 190
+#define Q_codepage 191
+#define Q_replaySpeed 192
+#define Q_autoWin 193
 static const char*const global_quarks[]={
   "screenWidth",
   "screenHeight",
   "margin",
   "palette",
@@ -356,10 +358,12 @@
   "class",
   "quiz",
   "saveSolutions",
   "solutionComment",
   "solutionTimestamp",
+  "picedit",
+  "macro",
   "sqlFile",
   "sqlInit",
   "sqlExtensions",
   "sqlMemStatus",
   "sqlSmallAllocations",