├── Guitor.winxhead ├── README ├── Makefile ├── setup.winxed ├── GuitorConstants.winxhead ├── examples ├── edit.winxed ├── text.winxed ├── winxed_repl.winxed ├── puzzle.winxed ├── boxes.winxed ├── graph.winxed ├── pizarra.winxed └── pokedit.winxed └── src └── GuitorNci.winxed /Guitor.winxhead: -------------------------------------------------------------------------------- 1 | // Guitor.winxhead 2 | 3 | // Declarations for Guitor 4 | 5 | $include "GuitorConstants.winxhead"; 6 | 7 | namespace Guitor 8 | { 9 | 10 | class Display; 11 | class Event; 12 | 13 | class Controller; 14 | class TopLevelWindow; 15 | class DialogWindow; 16 | class ChildWindow; 17 | class TextButton; 18 | class EditBox; 19 | class Menu; 20 | class MenuBar; 21 | 22 | } 23 | 24 | // End 25 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Guitor (C) 2011 Julián Albo 2 | 3 | Guitor is a parrot module for building GUI using Xlib. 4 | 5 | Use the Makefile or setup winxed 6 | 7 | Under development. Tested only with Linux amd64 and i386. 8 | 9 | 10 | To execute the examples without installing: 11 | 12 | winxed -L build/ examples/pizarra.winxed 13 | 14 | To execute without installing from other directory. 15 | 16 | wixed -L DIR/build -I DIR .... 17 | 18 | "DIR" means the directory WERE you have built Guitor, for example: 19 | /home/my_user/Guitor 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for WinxedXlib module 2 | 3 | SRCDIR = src/ 4 | INCLUDEDIR = ./ 5 | PIRDIR = pir/ 6 | BUILDDIR = build/ 7 | 8 | 9 | all: $(BUILDDIR)GuitorNci.pbc $(BUILDDIR)Guitor.pbc 10 | 11 | #--------------------------------------------------------------- 12 | 13 | # NCI 14 | 15 | $(BUILDDIR)GuitorNci.pbc: $(PIRDIR)GuitorNci.pir 16 | parrot -o $(BUILDDIR)GuitorNci.pbc $(PIRDIR)GuitorNci.pir 17 | 18 | $(PIRDIR)GuitorNci.pir: $(SRCDIR)GuitorNci.winxed 19 | winxed -c -o $(PIRDIR)GuitorNci.pir $(SRCDIR)GuitorNci.winxed 20 | 21 | # Main module 22 | 23 | $(BUILDDIR)Guitor.pbc: $(PIRDIR)Guitor.pir 24 | parrot -o $(BUILDDIR)Guitor.pbc $(PIRDIR)Guitor.pir 25 | 26 | $(PIRDIR)Guitor.pir: $(SRCDIR)Guitor.winxed $(INCLUDEDIR)Guitor.winxhead 27 | winxed -c -o $(PIRDIR)Guitor.pir $(SRCDIR)Guitor.winxed 28 | 29 | 30 | #--------------------------------------------------------------- 31 | 32 | clean: 33 | rm -f $(BUILDDIR)Guitor.pbc $(BUILDDIR)GuitorNci.pbc \ 34 | $(PIRDIR)Guitor.pir $(PIRDIR)GuitorNci.pir 35 | 36 | # End 37 | -------------------------------------------------------------------------------- /setup.winxed: -------------------------------------------------------------------------------- 1 | #! winxed 2 | # (C) 2011 Julián Albo 3 | 4 | /* 5 | = head1 NAME 6 | 7 | Setup for Guitor 8 | 9 | =head1 DESCRIPTION 10 | 11 | Setup program for Guitor using parrot distutils. 12 | 13 | =head1 USAGE 14 | 15 | Handle with care. 16 | 17 | =cut 18 | */ 19 | 20 | $load 'Getopt/Obj.pbc'; 21 | $load 'distutils.pbc'; 22 | 23 | //********************************************************************** 24 | 25 | function main(argv) 26 | { 27 | string progname = argv.shift(); 28 | 29 | var data = 30 | //BEGIN_JSON_SETUP 31 | { 32 | "name" : "Guitor", 33 | "version" : "0.0.0", 34 | 35 | "abstract" : "GUI contructor", 36 | "description" : "A winxed module for building GUI using Xlib", 37 | "keywords" : [ 38 | "Xlib", "winxed" 39 | ], 40 | 41 | "copyright_holder" : "Julián Albo", 42 | "license_type" : "Artistic License 2.0", 43 | "license_uri" : "http://www.perlfoundation.org/artistic_license_2_0", 44 | 45 | "pir_winxed" : { 46 | "pir/Guitor.pir" : "src/Guitor.winxed", 47 | "pir/GuitorNci.pir" : "src/GuitorNci.winxed" 48 | }, 49 | "pbc_pir" : { 50 | "build/Guitor.pbc" : "pir/Guitor.pir", 51 | "build/GuitorNci.pbc" : "pir/GuitorNci.pir" 52 | }, 53 | "inst_inc" : [ "Guitor.winxhead", "GuitorConstants.winxhead" ], 54 | "inst_lib" : [ "build/Guitor.pbc", "build/GuitorNci.pbc" ] 55 | } 56 | //END_JSON_SETUP 57 | ; 58 | 59 | setup(argv:[flat], data:[flat,named]); 60 | } 61 | 62 | // End 63 | -------------------------------------------------------------------------------- /GuitorConstants.winxhead: -------------------------------------------------------------------------------- 1 | // GuitorConstants.winxhead 2 | 3 | // Declarations for Guitor 4 | // Xlib constants commonly used 5 | 6 | namespace Guitor 7 | { 8 | 9 | // Line styles 10 | const int 11 | LineSolid = 0, 12 | LineOnOffDash = 1, 13 | LineDoubleDash = 2; 14 | 15 | // Coord modes 16 | const int 17 | CoordModeOrigin = 0, 18 | CoordModePrevious = 1; 19 | 20 | // GC logical function 21 | const int 22 | GXClear = 0x0, 23 | GXand = 0x1, 24 | GXandReverse = 0x2, 25 | GXcopy = 0x3, 26 | GXandInverted = 0x4, 27 | GXnoop = 0x5, 28 | GXxor = 0x6, 29 | GXor = 0x7, 30 | GXnor = 0x8, 31 | GXequiv = 0x9, 32 | GXinvert = 0xa, 33 | GXorReverse = 0xb, 34 | GXcopyInverted = 0xc, 35 | GXorInverted = 0xd, 36 | GXnand = 0xe, 37 | GXset = 0xf; 38 | 39 | // Subwindow modes 40 | const int 41 | ClipByChildren = 0, 42 | IncludeInferiors = 1; 43 | 44 | // Some commonly used values: 45 | const int None = 0; 46 | const int Success = 0; 47 | const int CurrentTime = 0; 48 | 49 | // Enter and Leave 50 | const int 51 | NotifyAncestor = 0, 52 | NotifyVirtual = 1, 53 | NotifyInferior = 2, 54 | NotifyNonlinear = 3, 55 | NotifyNonlinearVirtual = 4; 56 | 57 | // Focus revert type 58 | const int 59 | RevertToNone = 0, 60 | RevertToPointerRoot = 1, 61 | RevertToParent = 2; 62 | 63 | // Grab modes 64 | const int 65 | GrabModeSync = 0, 66 | GrabModeAsync = 1; 67 | 68 | // Property change modes 69 | const int 70 | PropModeReplace = 0, 71 | PropModePrepend = 1, 72 | PropModeAppend = 2; 73 | 74 | // WM hints 75 | const int InputHint = 1; 76 | 77 | // Some predefined atoms 78 | const int 79 | XA_PRIMARY = 1, 80 | XA_SECONDARY = 2, 81 | XA_ATOM = 4, 82 | XA_STRING = 31, 83 | XA_WM_COMMAND = 34, 84 | XA_WM_TRANSIENT_FOR = 68; 85 | 86 | namespace Events 87 | { 88 | 89 | // Event selection masks 90 | const int 91 | KeyPressMask = 0x00000001, 92 | KeyReleaseMask = 0x00000002, 93 | ButtonPressMask = 0x00000004, 94 | ButtonReleaseMask = 0x00000008, 95 | EnterWindowMask = 0x00000010, 96 | LeaveWindowMask = 0x00000020, 97 | PointerMotionMask = 0x00000040, 98 | ExposureMask = 0x00008000, 99 | StructureNotifyMask = 0x00020000, 100 | FocusChangeMask = 0x00200000; 101 | // Event types 102 | const int 103 | KeyPress = 2, 104 | KeyRelease = 3, 105 | ButtonPress = 4, 106 | ButtonRelease = 5, 107 | MotionNotify = 6, 108 | EnterNotify = 7, 109 | LeaveNotify = 8, 110 | FocusIn = 9, 111 | FocusOut = 10, 112 | Expose = 12, 113 | DestroyNotify = 17, 114 | UnmapNotify = 18, 115 | MapNotify = 19, 116 | ConfigureNotify = 22, 117 | SelectionClear = 29, 118 | SelectionRequest = 30, 119 | SelectionNotify = 31, 120 | ClientMessage = 33; 121 | 122 | // Key modifier masks 123 | const int 124 | ShiftMask = 1, 125 | LockMask = 1 << 1, 126 | ControlMask = 1 << 2, 127 | Mod1Mask = 1 << 3, 128 | Mod2Mask = 1 << 4, 129 | Mod3Mask = 1 << 5, 130 | Mod4Mask = 1 << 6, 131 | Mod5Mask = 1 << 7; 132 | 133 | } 134 | 135 | } 136 | 137 | // End 138 | -------------------------------------------------------------------------------- /examples/edit.winxed: -------------------------------------------------------------------------------- 1 | #! winxed 2 | 3 | // text example 4 | 5 | $load "Guitor.pbc"; 6 | 7 | $include "Guitor.winxhead"; 8 | 9 | using namespace Guitor; 10 | using namespace Guitor.Events; 11 | 12 | //********************************************************************** 13 | 14 | class EditWindow : TopLevelWindow 15 | { 16 | var font; 17 | var width; 18 | var height; 19 | var edit; 20 | var alive; 21 | function EditWindow(controller, string fontname) 22 | { 23 | var font = controller.display.CreateFont(fontname); 24 | self.font = font; 25 | int width = 200; 26 | int height = font.getHeight(); 27 | self.width = width; 28 | self.height = height; 29 | self.TopLevelWindow(controller, "Edit test", 30 | 4, 4, width + 10, height + 20); 31 | self.SetWMProtocols(['WM_TAKE_FOCUS', 'WM_DELETE_WINDOW' ]); 32 | 33 | var edit = new EditBox(self, 4, 4, 0, 0, font); 34 | self.edit = edit; 35 | self.alive = true; 36 | edit.Map(); 37 | 38 | self.OnClientMessage += function (event) { self.onclientmessage(event); }; 39 | self.OnConfigure += function (event) { self.onconfigure(event); }; 40 | self.OnDestroy += function (event) { self.ondestroy(event); }; 41 | edit.OnDestroy += function (event) { self.oneditdestroy(event); }; 42 | edit.OnKeyPress += function (event) { self.oneditkeypress(event); }; 43 | } 44 | function oneditdestroy(event) 45 | { 46 | self.edit = null; 47 | self.Destroy(); 48 | } 49 | function oneditkeypress(event) 50 | { 51 | switch (event.keyname()) { 52 | case "Return": 53 | say("Value: '", self.edit.getValue(), "'"); 54 | self.edit.Destroy(); 55 | break; 56 | case "Escape": 57 | say("Canceled"); 58 | self.edit.Destroy(); 59 | break; 60 | } 61 | } 62 | function ondestroy(event) 63 | { 64 | var controller = self.controller; 65 | controller.unregister(self); 66 | controller.Quit(); 67 | } 68 | function onconfigure(event) 69 | { 70 | int width = event.width(); 71 | self.width =: width; 72 | int height = event.height(); 73 | self.height =: height; 74 | var childheight = self.font.getHeight() + 6; 75 | if (childheight >= height) 76 | childheight = height - 4; 77 | self.edit.ResizeWindow(width - 10, childheight); 78 | } 79 | function onclientmessage(event) 80 | { 81 | int type = event.message_type(); 82 | if (type == self.InternAtom("WM_PROTOCOLS")) { 83 | int data0 = event.message_data(0); 84 | if (data0 == self.InternAtom("WM_DELETE_WINDOW")) { 85 | self.display.Flush(); 86 | self.SetInputFocus(RevertToParent); 87 | self.alive =: false; 88 | self.edit.Destroy(); 89 | //self.Destroy(); 90 | } 91 | else if (data0 == self.InternAtom("WM_TAKE_FOCUS")) { 92 | if (self.edit != null && self.alive) 93 | self.edit.SetInputFocus(RevertToParent); 94 | self.display.Flush(); 95 | } 96 | } 97 | } 98 | } 99 | 100 | //********************************************************************** 101 | 102 | function main(args) 103 | { 104 | int size; 105 | if (elements(args) > 1) 106 | size = args[1]; 107 | else 108 | size = 24; 109 | var controller = new Controller(); 110 | var w = new EditWindow(controller, "sans-" + string(size)); 111 | w.Map(); 112 | 113 | controller.MainLoop(); 114 | 115 | say('End'); 116 | controller.Close(); 117 | } 118 | 119 | // End. 120 | -------------------------------------------------------------------------------- /examples/text.winxed: -------------------------------------------------------------------------------- 1 | #! winxed 2 | 3 | // text example 4 | 5 | $load "Guitor.pbc"; 6 | 7 | $include "Guitor.winxhead"; 8 | 9 | using namespace Guitor; 10 | using namespace Guitor.Events; 11 | 12 | //********************************************************************** 13 | 14 | class TextWindow : TopLevelWindow 15 | { 16 | var width; 17 | var height; 18 | var text; 19 | var font; 20 | var chunks; 21 | var start; 22 | var menu; 23 | function TextWindow(controller, string text, string fontname) 24 | { 25 | if (fontname == null) 26 | fontname = "courier-12"; 27 | self.text = text; 28 | self.width = 600; 29 | self.height = 400; 30 | self.TopLevelWindow(controller, "Text and fonts test", 0, 0, 600, 400); 31 | var display = self.display; 32 | 33 | var font = display.CreateFont(fontname); 34 | //var font = display.getDefaultFont(); 35 | self.SetFont(font); 36 | self.font = font; 37 | self.start = 0; 38 | 39 | self.OnConfigure += function (event) { self.onconfigure(event); }; 40 | self.OnExpose += function (event) { self.onexpose(event); }; 41 | self.OnKeyPress += function (event) { self.onkeypress(event); }; 42 | self.OnButtonPress += function (event) { self.onbuttonpress(event); }; 43 | self.OnClientMessage += function (event) { self.onclientmessage(event); }; 44 | self.OnSelectionRequest += function (event) { self.onselectionrequest(event); }; 45 | self.OnDestroy += function (event) 46 | { 47 | var controller = self.controller; 48 | controller.unregister(self); 49 | controller.Quit(); 50 | }; 51 | var menu = new Menu(display, display.CreateFont("sans-14")); 52 | menu.push("close", function () { self.controller.pushaction(function() { self.Destroy(); } ); } ); 53 | menu.push("copy all", function () { self.copyall(); } ); 54 | self.menu = menu; 55 | } 56 | function drawall() 57 | { 58 | string text = self.text; 59 | int pos = 0; 60 | int hfont = self.font.getHeight(); 61 | int height = self.height; 62 | int y = 0; 63 | int start = self.start; 64 | int line = 0; 65 | for (int p in self.chunks) { 66 | if (line >= start) { 67 | y += hfont; 68 | if (y > height) 69 | break; 70 | self.DrawImageString(0, y, substr(self.text, pos, p - pos - 1)); 71 | } 72 | pos = p; 73 | ++line; 74 | } 75 | y += hfont; 76 | if (y <= height) 77 | self.DrawImageString(0, y, substr(self.text, pos)); 78 | } 79 | function copyall() 80 | { 81 | // Copy all text to clipboard 82 | int clipboard = self.InternAtom("CLIPBOARD"); 83 | self.SetSelectionOwner(clipboard, CurrentTime); 84 | } 85 | 86 | function onconfigure(event) 87 | { 88 | int width = event.width(); 89 | self.width =: width; 90 | self.height =: int(event.height()); 91 | var font = self.font; 92 | var display = self.display; 93 | string text = self.text; 94 | int chunks[] = [ ]; 95 | int len = length(text); 96 | string line; 97 | int pcurline = 0; 98 | int pnextline; 99 | do { 100 | if (pcurline > 0) 101 | push(chunks, pcurline); 102 | pnextline = indexof(text, "\n", pcurline); 103 | if (pnextline < 0) 104 | line = substr(text, pcurline); 105 | else 106 | line = substr(text, pcurline, pnextline - pcurline); 107 | 108 | int p = 0; 109 | while (font.getTextWidth(display, substr(line, p)) >= width) { 110 | int q = indexof(line, " ", p); 111 | if (q < 0) 112 | break; 113 | int q1 = q; 114 | while (font.getTextWidth(display, substr(line, p, q1 - p)) < width) { 115 | q = q1; 116 | q1 = indexof(line, " ", q + 1); 117 | if (q1 < 0) 118 | break; 119 | } 120 | p = q + 1; 121 | if (p > 0) 122 | push(chunks, pcurline + p); 123 | } 124 | 125 | if (pnextline >= 0) 126 | pcurline = pnextline + 1; 127 | } while (pnextline > 0); 128 | self.chunks = chunks; 129 | } 130 | function onexpose(event) 131 | { 132 | self.drawall(); 133 | } 134 | function onkeypress(event) 135 | { 136 | var display = self.display; 137 | string key = event.keyname(); 138 | switch (key) { 139 | case "Escape": 140 | self.Destroy(); 141 | break; 142 | case "Down": 143 | ++self.start; 144 | self.ClearArea(0, 0, 0, 0, 0); 145 | self.drawall(); 146 | break; 147 | case "Up": 148 | if (self.start > 0) { 149 | --self.start; 150 | self.ClearArea(0, 0, 0, 0, 0); 151 | self.drawall(); 152 | } 153 | break; 154 | } 155 | } 156 | function onbuttonpress(event) 157 | { 158 | self.menu.activate_from(self, event); 159 | } 160 | function onclientmessage(event) 161 | { 162 | self.text = null; 163 | self.chunks = null; 164 | self.Destroy(); 165 | } 166 | function onselectionrequest(event) 167 | { 168 | int requestor = event.requestor(); 169 | int selection = event.selection(); 170 | int target = event.target(); 171 | int property = event.property(); 172 | var display = self.display; 173 | 174 | int typeutf8 = self.InternAtom("UTF8_STRING"); 175 | // Request for supported types: answer only utf8 text. 176 | if (self.GetAtomName(target) == "TARGETS") { 177 | display.ChangePropertyInt32(requestor, 178 | property, target, PropModeReplace, typeutf8); 179 | } 180 | // Request for utf8 text: fine, do it. 181 | else if (target == typeutf8) { 182 | display.ChangePropertyString(requestor, 183 | property, target, PropModeReplace, self.text); 184 | } 185 | else 186 | return; 187 | 188 | var notify = new Event(SelectionNotify); 189 | // No much support for creating events yet, use the 190 | // raw StructView for a now. 191 | var data = notify.eventdata; 192 | var view = notify.getview(); 193 | view[data, 4] = requestor; 194 | view[data, 5] = selection; 195 | view[data, 6] = target; 196 | view[data, 7] = property; 197 | view[data, 8] = event.time(); 198 | display.SendEvent(requestor, false, 0, notify); 199 | } 200 | } 201 | 202 | //********************************************************************** 203 | 204 | function main(args) 205 | { 206 | string text; 207 | string font; 208 | int nargs = elements(args); 209 | var controller = new Controller(); 210 | if (nargs > 1) { 211 | string filename = args[1]; 212 | var file = open(filename, "r"); 213 | file.encoding("utf8"); 214 | text = file.readall(); 215 | } 216 | else 217 | text = "Hello, world!"; 218 | if (nargs > 2) 219 | font = args[2]; 220 | 221 | var textwindow = new TextWindow(controller, text, font); 222 | textwindow.SetWMProtocols(['WM_DELETE_WINDOW']); 223 | textwindow.Map(); 224 | 225 | controller.MainLoop(); 226 | 227 | say('End'); 228 | controller.Close(); 229 | } 230 | 231 | // End. 232 | -------------------------------------------------------------------------------- /examples/winxed_repl.winxed: -------------------------------------------------------------------------------- 1 | // winxed_repl.winxed 2 | 3 | // A Read-Eval-Print Loop for winxed 4 | 5 | $include "Guitor.winxhead"; 6 | 7 | $load "Guitor.pbc"; 8 | 9 | using namespace Guitor; 10 | 11 | $include_const "except_severity.pasm"; 12 | 13 | //************************************************************** 14 | 15 | // Compile the string passed embedded in a local function of a function 16 | // that passes the variables in stotage as lexicals. 17 | // Return the outer function. 18 | 19 | function parse_line(compiler, storage, string line) 20 | { 21 | string source = "function aux(__storage) {"; 22 | 23 | for (string name in storage) { 24 | var data = storage[name]; 25 | string type = data[0]; 26 | if (type == "var") 27 | source += "volatile "; 28 | source += type + " " + name + " = __storage['" + name + "'][1];"; 29 | } 30 | source += "var __result = function() { " + line + "; } ();"; 31 | for (string name in storage) { 32 | var data = storage[name]; 33 | string type = data[0]; 34 | source += "__storage['" + name + "'][1] = " + type + "(" + name + ");"; 35 | } 36 | 37 | source += " return __result; }"; 38 | 39 | var pir = compiler.compile(source, "pir":[named("target")] ); 40 | var pircomp = compreg("PIR"); 41 | var code = pircomp.compile(pir); 42 | 43 | var fun = code.all_subs()[0]; 44 | return fun; 45 | } 46 | 47 | function execute_line(storage, fun) 48 | { 49 | var result = fun(storage); 50 | return result; 51 | } 52 | 53 | //************************************************************** 54 | 55 | // Panel contains the output of the commands executed. 56 | 57 | class Panel : ChildWindow 58 | { 59 | var font; 60 | var text; 61 | var height; 62 | function Panel(parent, int x, int y, int width, int height, font) 63 | { 64 | self.font = font; 65 | string text[] = [ "Welcome!" ]; 66 | self.text = text; 67 | self.height = height; 68 | self.ChildWindow(parent, x, y, width, height); 69 | self.OnConfigure += function (event) { self.onconfigure(event); }; 70 | self.OnExpose += function (event) { self.onexpose(event); }; 71 | } 72 | function onconfigure(event) 73 | { 74 | self.height =: event.height(); 75 | } 76 | function onexpose(event) 77 | { 78 | self.ClearArea(0, 0, 0, 0, 0); 79 | self.drawall(); 80 | } 81 | function add(string str) 82 | { 83 | // Add str to current content, breaking it into lines, 84 | // avoiding to add blank line at end. 85 | var text = self.text; 86 | int pos = 0, npos; 87 | while ((npos = indexof(str, "\n", pos)) >= 0) { 88 | push(text, substr(str, pos, npos - pos)); 89 | pos = npos + 1; 90 | } 91 | if (pos < length(str)) 92 | push(text, substr(str, pos)); 93 | } 94 | function drawall() 95 | { 96 | var text = self.text; 97 | int ntext = elements(text); 98 | int lineheight = self.font.getHeight(); 99 | int nlines = self.height / lineheight; 100 | int start = ntext - nlines; 101 | if (start < 0) 102 | start = 0; 103 | for (int i = start, y = lineheight; i < ntext; ++i, y += lineheight) 104 | self.DrawImageString(0, y, text[i]); 105 | } 106 | } 107 | 108 | //************************************************************** 109 | 110 | // Main application window: contains a Panel and a EditBox 111 | 112 | class WinxedRepl : TopLevelWindow 113 | { 114 | var font; 115 | var width; 116 | var height; 117 | var command; 118 | var panel; 119 | var command_y; 120 | var command_height; 121 | var history; 122 | var histpos; 123 | var storage; 124 | var compiler; 125 | var exit_code; 126 | function WinxedRepl(controller, fontname) 127 | { 128 | var display = controller.display; 129 | var font = display.CreateFont(fontname); 130 | int width = 600, height = 400; 131 | int command_height = font.getHeight(); 132 | int command_y = height - command_height - 1; 133 | self.font = font; 134 | self.width = width; 135 | self.height = height; 136 | string history[]; 137 | self.history = history; 138 | self.histpos = -1; 139 | self.command_height = command_height; 140 | self.command_y = command_y; 141 | self.compiler = load_language("winxed"); 142 | 143 | // No way to declare variables yet, hardcode a few here: 144 | self.storage = { 145 | "n" : [ "int", 42 ], 146 | "j" : [ "string", "hi"], 147 | "p" : [ "var", null ] 148 | }; 149 | 150 | self.TopLevelWindow(controller, "Winxed REPL", 151 | 0, 0, width, height, 152 | { "background-color" : display.ParseColor("grey") } ); 153 | self.SetWMProtocols(['WM_TAKE_FOCUS', 'WM_DELETE_WINDOW' ]); 154 | var command = new EditBox(self, 155 | 1, command_y, width - 2, command_height, font); 156 | self.command = command; 157 | command.Map(); 158 | var panel = new Panel(self, 1, 1, width - 2, command_y - 2, font); 159 | self.panel = panel; 160 | panel.Map(); 161 | 162 | self.OnDestroy += function (event) { self.controller.Quit(); }; 163 | self.OnConfigure += function (event) { self.onconfigure(event); }; 164 | self.OnClientMessage += function (event) { self.onclientmessage(event); }; 165 | command.OnKeyPress += function (event) { self.oncommandkeypress(event); }; 166 | } 167 | function onconfigure(event) 168 | { 169 | int width = event.width(); 170 | int height = event.height(); 171 | int command_y = height - self.command_height - 1; 172 | self.width = width; 173 | self.height = height; 174 | self.command_y = command_y; 175 | var command = self.command; 176 | if (command != null) 177 | command.MoveResizeWindow(1, command_y, width - 2, self.command_height); 178 | var panel = self.panel; 179 | if (panel != null) { 180 | panel.ResizeWindow(width - 2, command_y - 2); 181 | } 182 | } 183 | function onclientmessage(event) 184 | { 185 | int type = event.message_type(); 186 | if (type == self.InternAtom("WM_PROTOCOLS")) { 187 | int data0 = event.message_data(0); 188 | if (data0 == self.InternAtom("WM_DELETE_WINDOW")) 189 | self.quit(); 190 | else if (data0 == self.InternAtom("WM_TAKE_FOCUS")) { 191 | if (self.command != null) 192 | self.command.SetInputFocus(RevertToParent); 193 | self.display.Flush(); 194 | } 195 | } 196 | } 197 | 198 | function quit() 199 | { 200 | var command = self.command; 201 | var panel = self.panel; 202 | self.command = null; 203 | self.panel = null; 204 | if (command != null) 205 | command.Destroy(); 206 | if (panel != null) 207 | panel.Destroy(); 208 | self.Destroy(); 209 | } 210 | function eval(string str) 211 | { 212 | var panel = self.panel; 213 | self.command.setValue(""); 214 | var interp = getinterp(); 215 | var savestdout = interp.stdout_handle(); 216 | var savestderr = interp.stderr_handle(); 217 | var out = new ["StringHandle"]; 218 | out.open("REPLout", "w"); 219 | interp.stdout_handle(out); 220 | interp.stderr_handle(out); 221 | var fun; 222 | try { 223 | fun = parse_line(self.compiler, self.storage, str); 224 | } 225 | catch (e) { 226 | interp.stdout_handle(savestdout); 227 | interp.stderr_handle(savestderr); 228 | panel.add("Error while compiling:"); 229 | out.close(); 230 | out.open("", "r"); 231 | panel.add(out.readall()); 232 | panel.add(e["message"]); 233 | panel.ClearArea(0, 0, 0, 0, 0); 234 | panel.drawall(); 235 | return; 236 | } 237 | try { 238 | var result = execute_line(self.storage, fun); 239 | interp.stdout_handle(savestdout); 240 | interp.stderr_handle(savestderr); 241 | out.close(); 242 | out.open("", "r"); 243 | panel.add(out.readall()); 244 | if (result != null) 245 | panel.add(result); 246 | } 247 | catch (e) { 248 | interp.stdout_handle(savestdout); 249 | interp.stderr_handle(savestderr); 250 | if (e["severity"] == EXCEPT_EXIT) { 251 | self.exit_code = e["exit_code"]; 252 | self.quit(); 253 | return; 254 | } 255 | panel.add(e["message"]); 256 | } 257 | panel.ClearArea(0, 0, 0, 0, 0); 258 | panel.drawall(); 259 | } 260 | function oncommandkeypress(event) 261 | { 262 | var history = self.history; 263 | int n = elements(history); 264 | switch (event.keyname()) { 265 | case "Return": 266 | string cmd = self.command.getValue(); 267 | self.histpos =: -1; 268 | if (length(cmd)) { 269 | push(history, cmd); 270 | self.eval(cmd); 271 | } 272 | break; 273 | case "Up": 274 | if (n) { 275 | int pos = self.histpos; 276 | if (pos != 0) { 277 | if (pos == -1) 278 | pos = n - 1; 279 | else 280 | --pos; 281 | self.command.setValue(history[pos]); 282 | self.histpos =: pos; 283 | } 284 | } 285 | break; 286 | case "Down": 287 | if (n) { 288 | int pos = self.histpos; 289 | if (pos < n && pos != -1) { 290 | ++pos; 291 | string str; 292 | if (pos > n) { 293 | pos = -1; 294 | str = ""; 295 | } 296 | else 297 | str = history[pos]; 298 | self.command.setValue(str); 299 | self.histpos =: pos; 300 | } 301 | } 302 | break; 303 | case "Escape": 304 | self.quit(); 305 | break; 306 | } 307 | } 308 | } 309 | 310 | //************************************************************** 311 | 312 | function main() 313 | { 314 | var controller = new Controller(); 315 | var repl = new WinxedRepl(controller, "Courier-12"); 316 | repl.Map(); 317 | controller.MainLoop(); 318 | var exit_code = repl.exit_code; 319 | controller.Close(); 320 | repl = null; 321 | controller = null; 322 | if (exit_code != null) 323 | exit(exit_code); 324 | } 325 | 326 | // End 327 | -------------------------------------------------------------------------------- /examples/puzzle.winxed: -------------------------------------------------------------------------------- 1 | #! winxed 2 | 3 | // puzzle 4 | 5 | $include "Guitor.winxhead"; 6 | 7 | $load "Guitor.pbc"; 8 | 9 | $loadlib "math_ops"; // For rand 10 | 11 | using namespace Guitor; 12 | 13 | //************************************************************** 14 | 15 | class Piece : ChildWindow 16 | { 17 | var puzzle; 18 | var width; 19 | var height; 20 | var label; 21 | var baseline; 22 | var x; 23 | function Piece(puzzle, x, y, width, height, string label) 24 | { 25 | self.puzzle = puzzle; 26 | var display = puzzle.display; 27 | self.ChildWindow(puzzle, x, y, width, height, 28 | { "background-color" : puzzle.background }); 29 | var font = puzzle.font; 30 | self.SetFont(font); 31 | int h = font.getHeight(); 32 | int baseline = (height - h) / 2 + font.getAscent(); 33 | int xpos = (width - self.getTextWidth(label)) / 2; 34 | self.width = width; 35 | self.height = height; 36 | self.label = label; 37 | self.baseline = baseline; 38 | self.x = xpos; 39 | self.OnExpose += function (event) { self.onexpose(event); }; 40 | self.OnButtonPress += function(event) { self.onbuttonpress(event); }; 41 | } 42 | function onexpose(event) 43 | { 44 | var puzzle = self.puzzle; 45 | self.SetForeground(puzzle.foreground); 46 | self.SetBackground(puzzle.background); 47 | self.DrawImageString(self.x, self.baseline, self.label); 48 | 49 | int w = self.width - 1; 50 | int h = self.height - 1; 51 | self.SetForeground(puzzle.darkline); 52 | self.DrawLine(0, 0, w, 0); 53 | self.DrawLine(0, 0, 0, h); 54 | self.SetForeground(puzzle.brightline); 55 | self.DrawLine(1, 1, w - 1, 1); 56 | self.DrawLine(1, 1, 1, h - 1); 57 | self.SetForeground(puzzle.darkline); 58 | self.DrawLine(w - 1, 2, w - 1, h - 1); 59 | self.DrawLine(2, h - 1, w - 1, h - 1); 60 | self.SetForeground(puzzle.foreground); 61 | self.DrawLine(w, 1, w, h); 62 | self.DrawLine(1, h, w, h); 63 | } 64 | function onbuttonpress(event) 65 | { 66 | switch (event.button()) { 67 | case 1: 68 | self.puzzle.click(self.label); 69 | break; 70 | case 3: 71 | self.puzzle.childpress(event); 72 | break; 73 | } 74 | } 75 | } 76 | 77 | //************************************************************** 78 | 79 | class Puzzle : TopLevelWindow 80 | { 81 | const int HOR = 7; 82 | const int VER = 4; 83 | var foreground; 84 | var background; 85 | var brightline; 86 | var darkline; 87 | var menu; 88 | var x; 89 | var y; 90 | var width; 91 | var height; 92 | var ypbase; 93 | var wpiece; 94 | var hpiece; 95 | var pieces; 96 | var font; 97 | var grid; 98 | function Puzzle(controller) 99 | { 100 | int width = 764; 101 | int height = 440; 102 | int x = 0; 103 | int y = 0; 104 | self.x = x; 105 | self.y = y; 106 | self.TopLevelWindow(controller, "Puzzle", x, y, width, height); 107 | self.SetWMProtocols( [ "WM_DELETE_WINDOW" ] ); 108 | self.OnConfigure += function (event) { self.onconfigure(event); }; 109 | self.OnClientMessage += function (event) { self.quit(); }; 110 | self.OnDestroy += function (event) { controller.Quit(); }; 111 | 112 | var display = self.display; 113 | self.foreground = display.ParseColor("black"); 114 | self.background = display.ParseColor("RGB:FF/FF/00"); 115 | self.brightline = display.ParseColor("RGB:FF/FF/DD"); 116 | self.darkline = display.ParseColor("RGB:88/55/33"); 117 | var menufont = display.CreateFont("sans-12"); 118 | var menubar = new MenuBar(display, menufont); 119 | var menufile = new Menu(display, menufont); 120 | menufile.push("shuffle", function () { self.shuffle(); } ); 121 | menufile.push("quit", function () { self.quit(); } ); 122 | menubar.push("Game", menufile); 123 | var menuwin = menubar.activate(self, 0, 0, width); 124 | menuwin.Map(); 125 | int ypbase = menubar.getheight() + 2; 126 | self.ypbase = ypbase; 127 | self.setdims(width, height); 128 | 129 | var menu = new Menu(display, menufont); 130 | menu.push("shuffle", function () { self.shuffle(); } ); 131 | menu.push("quit", function () { self.quit(); } ); 132 | self.menu = menu; 133 | 134 | self.OnButtonPress += function (event) { self.onbuttonpress(event); }; 135 | self.OnKeyPress += function (event) { self.onkeypress(event); }; 136 | var grid = []; 137 | for (int i = 0; i < VER; ++i) { 138 | int row[HOR]; 139 | grid[i] = row; 140 | } 141 | self.grid = grid; 142 | self.createpieces(); 143 | self.shuffle(); 144 | for (var piece in self.pieces) 145 | piece.Map(); 146 | } 147 | function onconfigure(event) 148 | { 149 | int x = event.x(); 150 | int y = event.y(); 151 | self.x =: x; 152 | self.y =: y; 153 | } 154 | function onbuttonpress(event) 155 | { 156 | if (event.button() == 3) 157 | self.menu.activate_from(self, event); 158 | } 159 | function onkeypress(event) 160 | { 161 | var grid = self.grid; 162 | int x, y; 163 | for (y = 0; y < VER; ++y) { 164 | for (x = 0; x < HOR; ++x) { 165 | if (int(grid[y, x]) == 0) 166 | break; 167 | } 168 | if (x < HOR) 169 | break; 170 | } 171 | int x1 = x, y1 = y; 172 | string key = event.keyname(); 173 | switch (key) { 174 | case "Left": 175 | if (x < HOR - 1) 176 | x1 = x + 1; 177 | break; 178 | case "Right": 179 | if (x > 0) 180 | x1 = x - 1; 181 | break; 182 | case "Up": 183 | if (y < VER - 1) 184 | y1 = y + 1; 185 | break; 186 | case "Down": 187 | if (y > 0) 188 | y1 = y - 1; 189 | break; 190 | } 191 | if (x != x1 || y != y1) { 192 | int n = grid[y1, x1]; 193 | self.move(n, x, y); 194 | grid[y, x] = n; 195 | grid[y1, x1] = 0; 196 | } 197 | } 198 | function childpress(event) 199 | { 200 | int x = event.x_root() - self.x; 201 | int y = event.y_root() - self.y; 202 | int time = event.time(); 203 | self.menu.activate(self, x, y, time); 204 | } 205 | function quit() 206 | { 207 | self.Destroy(); 208 | } 209 | function setdims(int width, int height) 210 | { 211 | self.width = width; 212 | self.height = height; 213 | int wpiece = width / HOR; 214 | int hpiece = (height - self.ypbase) / VER; 215 | self.wpiece = wpiece; 216 | self.hpiece = hpiece; 217 | var display = self.display; 218 | // Calculate appropiate font size: 219 | var hs = display.Height(); 220 | var hsmm = display.HeightMM(); 221 | float h = float(hpiece); 222 | h = h * 3 / 5; 223 | // Convert pixesls to mm and then to points 224 | h = h * hsmm / hs; 225 | h = h / 0.3515; 226 | var font = display.CreateFont("sans-" + string(int(h))); 227 | self.font = font; 228 | } 229 | function createpieces() 230 | { 231 | int wpiece = self.wpiece; 232 | int hpiece = self.hpiece; 233 | var pieces = []; 234 | var grid = self.grid; 235 | for (int n = 1; n < VER * HOR; ++n) { 236 | var piece = new Piece(self, 0, 0, wpiece - 4, hpiece - 4, n); 237 | push(pieces, piece); 238 | } 239 | self.pieces = pieces; 240 | } 241 | function move(int n, int x, int y) 242 | { 243 | int ypbase = self.ypbase; 244 | int wpiece = self.wpiece; 245 | int hpiece = self.hpiece; 246 | self.pieces[n - 1].MoveWindow(x * wpiece + 2, y * hpiece + 2 + ypbase); 247 | } 248 | function shuffle() 249 | { 250 | int orig[]; 251 | int dest[]; 252 | var grid = self.grid; 253 | for (int i = 0; i < VER * HOR; ++i) 254 | orig[i] = i; 255 | for (int i = VER * HOR - 1; i > 0; --i) { 256 | int r; 257 | ${ rand r, i }; 258 | dest[i] = orig[r]; 259 | delete orig[r]; 260 | } 261 | dest[0] = orig[0]; 262 | 263 | // Check parity and swap two non-zero elements if wrong 264 | // to ensure teh puzzle is solvable. 265 | int p = 0; 266 | for (int i = 0; i < VER * HOR; ++i) 267 | for (int j = i + 1; j < VER * HOR; ++j) 268 | if (dest[i] > dest[j]) 269 | ++p; 270 | int i; 271 | for (i = 0; i < VER * HOR; ++i) 272 | if (dest[i] == 0) 273 | break; 274 | p += HOR - int (i / HOR) + VER - (i % HOR); 275 | if (!(p & 1)) { 276 | i = 0; 277 | if (dest[0] == 0 || dest[1] == 0) 278 | i = 2; 279 | p = dest[i]; 280 | dest[i] = dest[i + 1]; 281 | dest[i + 1] = p; 282 | } 283 | 284 | for (int i = VER * HOR - 1; i >= 0; --i) { 285 | int n = dest[i]; 286 | grid[int(i / HOR), i % HOR] = n; 287 | } 288 | 289 | var pieces = self.pieces; 290 | int ypbase = self.ypbase; 291 | int wpiece = self.wpiece; 292 | int hpiece = self.hpiece; 293 | for (int i = 0; i < VER; ++i) 294 | for (int j = 0; j < HOR; ++j) { 295 | int pos = grid[i, j] - 1; 296 | if (pos < 0) 297 | continue; 298 | pieces[pos].MoveWindow(j * wpiece + 2, i * hpiece + 2 + ypbase); 299 | } 300 | } 301 | function click(int n) 302 | { 303 | var grid = self.grid; 304 | // Get position 305 | int x, y; 306 | for (y = 0; y < VER; ++y) { 307 | for (x = 0; x < HOR; ++x) { 308 | if (int(grid[y, x]) == n) 309 | break; 310 | } 311 | if (x < HOR) 312 | break; 313 | } 314 | // Chek for vertical move 315 | int y1; 316 | for (y1 = 0; y1 < VER; ++y1) 317 | if (int(grid[y1, x]) == 0) 318 | break; 319 | if (y1 < VER) { 320 | if (y1 < y) { 321 | for (int y2 = y1 + 1; y2 <= y; ++y2) { 322 | int n = grid[y2, x]; 323 | self.move(n, x, y2 - 1); 324 | grid[y2 - 1, x] = n; 325 | } 326 | grid[y, x] = 0; 327 | } 328 | else { 329 | for (int y2 = y1 - 1; y2 >= y; --y2) { 330 | int n = grid[y2, x]; 331 | self.move(n, x, y2 + 1); 332 | grid[y2 + 1, x] = n; 333 | } 334 | grid[y, x] = 0; 335 | } 336 | } 337 | else { 338 | // Check for horizontal move. 339 | int x1; 340 | for (x1 = 0; x1 < HOR; ++x1) 341 | if (int(grid[y, x1]) == 0) 342 | break; 343 | if (x1 >= HOR) 344 | return; 345 | if (x1 < x) { 346 | for (int x2 = x1 + 1; x2 <= x; ++x2) { 347 | int n = grid[y, x2]; 348 | self.move(n, x2 - 1, y); 349 | grid[y, x2 - 1] = n; 350 | } 351 | } 352 | else { 353 | for (int x2 = x1 - 1; x2 >= x; --x2) { 354 | int n = grid[y, x2]; 355 | self.move(n, x2 + 1, y); 356 | grid[y, x2 + 1] = n; 357 | } 358 | } 359 | grid[y, x] = 0; 360 | } 361 | } 362 | } 363 | 364 | //************************************************************** 365 | 366 | function main[main](args) 367 | { 368 | var controller = new Controller(); 369 | var puzzle = new Puzzle(controller); 370 | puzzle.Map(); 371 | controller.MainLoop(); 372 | } 373 | 374 | // End 375 | -------------------------------------------------------------------------------- /examples/boxes.winxed: -------------------------------------------------------------------------------- 1 | #! winxed 2 | 3 | // boxes: put boxes with text 4 | 5 | $load "Guitor.pbc"; 6 | 7 | $include "Guitor.winxhead"; 8 | 9 | using namespace Guitor; 10 | using namespace Guitor.Events; 11 | 12 | //********************************************************************** 13 | 14 | class AboutBoxes : TopLevelWindow 15 | { 16 | const string msg = "Boxes - A Guitor example"; 17 | 18 | var font; 19 | var width; 20 | function AboutBoxes(controller, parent) 21 | { 22 | var display = controller.display; 23 | var font = display.CreateFont("courier-14"); 24 | self.font = font; 25 | int width = font.getTextWidth(display, msg); 26 | int height = font.getHeight(); 27 | width = width + width / 5; 28 | self.width = width; 29 | self.TopLevelWindow(controller, "About Boxes", 30 | 0, 0, width, height * 3); 31 | self.SetFont(font); 32 | self.OnClientMessage += function (event) { self.Destroy(); }; 33 | self.OnExpose += function (event) { self.onexpose(event); }; 34 | self.SetWMProtocols(['WM_DELETE_WINDOW']); 35 | self.SetTransientFor(parent); 36 | 37 | // Position of the button estimated 38 | var button = new TextButton(self, 39 | width / 2 - 40, height + height / 2, 0, 0, "close", font); 40 | button.OnClick += function () { self.Destroy(); }; 41 | button.Map(); 42 | } 43 | function onexpose(event) 44 | { 45 | int width = self.width; 46 | int x = (width - self.getTextWidth(msg)) / 2; 47 | self.DrawImageString(x, self.font.getAscent(), msg); 48 | } 49 | } 50 | 51 | const int STEP = 4; // pixels 52 | 53 | class Boxes : TopLevelWindow 54 | { 55 | var boxlist; 56 | var activebox; 57 | var width; 58 | var height; 59 | var x; 60 | var y; 61 | var x1; 62 | var y1; 63 | var pressed; 64 | var colors; 65 | var numcolor; 66 | function Boxes(controller) 67 | { 68 | var display = controller.display; 69 | self.boxlist = []; 70 | self.activebox = -1; 71 | self.x = 0; 72 | self.y = 0; 73 | self.x1 = 0; 74 | self.y1 = 0; 75 | self.pressed = false; 76 | self.numcolor = 0; 77 | int dwidth = display.Width(); 78 | int dheight = display.Height(); 79 | int width = dwidth - dwidth / 3; 80 | int height = dheight - dheight / 3; 81 | self.width = width; 82 | self.height = height; 83 | // The window manager will probably ignore the position, 84 | // but set it just in case. 85 | int x = (dwidth - width) / 2; 86 | int y = (dheight - height) / 2; 87 | self.TopLevelWindow(controller, "Boxes", x, y, width, height); 88 | self.colors = [ 89 | display.ParseColor("yellow"), 90 | display.ParseColor("red"), 91 | display.ParseColor("blue"), 92 | display.ParseColor("light steel blue"), 93 | display.ParseColor("orange"), 94 | display.ParseColor("green"), 95 | display.ParseColor("maroon"), 96 | display.ParseColor("aquamarine"), 97 | display.ParseColor("coral"), 98 | display.ParseColor("violet") 99 | ]; 100 | 101 | self.OnConfigure += function (event) { self.onConfigure(event); }; 102 | self.OnExpose += function (event) { self.onExpose(event); }; 103 | self.OnKeyPress += function (event) { self.onKeyPress(event); }; 104 | self.OnButtonPress += function (event) { self.onButtonPress(event); }; 105 | self.OnButtonRelease += function (event) { self.onButtonRelease(event); }; 106 | self.OnMotion += function (event) { self.onMotion(event); }; 107 | self.OnClientMessage += function (event) { self.onClientMessage(event); }; 108 | self.OnDestroy += function (event) 109 | { 110 | var controller = self.controller; 111 | controller.unregister(self); 112 | controller.Quit(); 113 | }; 114 | } 115 | function activate(box) 116 | { 117 | var boxlist = self.boxlist; 118 | for (int i = 0, n = elements(boxlist); i < n; ++i) 119 | if (boxlist[i] === box) { 120 | self.activebox =: i; 121 | box.RaiseWindow(); 122 | break; 123 | } 124 | } 125 | 126 | function onConfigure(event) 127 | { 128 | self.width =: int(event.width()); 129 | self.height =: int(event.height()); 130 | } 131 | function onExpose(event) 132 | { 133 | } 134 | function onKeyPress(event) 135 | { 136 | var display = self.display; 137 | var boxlist = self.boxlist; 138 | int active = self.activebox; 139 | int code = event.keycode(); 140 | 141 | string key = display.KeysymToString(display.KeycodeToKeysym(code)); 142 | switch (key) { 143 | case "Escape": 144 | self.Destroy(); 145 | break; 146 | case "F1": 147 | var about = new AboutBoxes(self.controller, self); 148 | about.Map(); 149 | break; 150 | case "BackSpace": 151 | if (active >= 0) 152 | { 153 | var boxlist = self.boxlist; 154 | var box = boxlist[active]; 155 | box.Destroy(); 156 | delete boxlist[active]; 157 | if (active >= elements(boxlist)) 158 | --active; 159 | self.activebox =: active; 160 | } 161 | break; 162 | case 'Up': 163 | if (active >= 0) { 164 | var box = boxlist[active]; 165 | box.MoveWindow(box.posx, box.posy - STEP); 166 | } 167 | break; 168 | case 'Down': 169 | if (active >= 0) { 170 | var box = boxlist[active]; 171 | box.MoveWindow(box.posx, box.posy + STEP); 172 | } 173 | break; 174 | case 'Left': 175 | if (active >= 0) { 176 | var box = boxlist[active]; 177 | box.MoveWindow(box.posx - STEP, box.posy); 178 | } 179 | break; 180 | case 'Right': 181 | if (active >= 0) { 182 | var box = boxlist[active]; 183 | box.MoveWindow(box.posx + STEP, box.posy); 184 | } 185 | break; 186 | case 'Home': 187 | if (active >= 0) { 188 | var box = boxlist[active]; 189 | box.MoveWindow(0, box.posy); 190 | } 191 | break; 192 | case 'End': 193 | if (active >= 0) { 194 | var box = boxlist[active]; 195 | box.MoveWindow(self.width - box.width, box.posy); 196 | } 197 | break; 198 | case 'Prior': 199 | if (active >= 0) { 200 | var box = boxlist[active]; 201 | box.MoveWindow(box.posx, 0); 202 | } 203 | break; 204 | case 'Next': 205 | if (active >= 0) { 206 | var box = boxlist[active]; 207 | box.MoveWindow(box.posx, self.height - box.height); 208 | } 209 | break; 210 | case '0': case '1': case '2': case '3': case '4': 211 | case '5': case '6': case '7': case '8': case '9': 212 | self.numcolor =: int(key); 213 | break; 214 | } 215 | } 216 | function onButtonPress(event) 217 | { 218 | self.pressed =: true; 219 | int x = event.x(); 220 | int y = event.y(); 221 | self.x =: x; 222 | self.y =: y; 223 | self.x1 =: x; 224 | self.y1 =: y; 225 | self.SetFunction(GXinvert); 226 | self.SetLineAttributes(0, LineOnOffDash, 0, 0); 227 | self.SetSubwindowMode(IncludeInferiors); 228 | } 229 | function onButtonRelease(event) 230 | { 231 | self.pressed =: false; 232 | int x = self.x; 233 | int y = self.y; 234 | int x1 = self.x1; 235 | int y1 = self.y1; 236 | self.rectangle(x, y, x1, y1); 237 | int x2 = event.x(); 238 | int y2 = event.y(); 239 | int width, height; 240 | if (x2 > x) 241 | width = x2 - x; 242 | else { 243 | width = x - x2; 244 | x = x2; 245 | } 246 | if (y2 > y) 247 | height = y2 - y; 248 | else { 249 | height = y - y2; 250 | y = y2; 251 | } 252 | if (width == 0 || height == 0) 253 | return; 254 | var boxlist = self.boxlist; 255 | var color = self.colors[self.numcolor]; 256 | var box = new Box(self, x, y, width, height, 257 | { "background-color" : color } ); 258 | 259 | box.Map(); 260 | int active = elements(boxlist); 261 | push(boxlist, box); 262 | self.activebox =: active; 263 | self.SetFunction(GXcopy); 264 | self.SetLineAttributes(0, LineSolid, 0, 0); 265 | self.SetSubwindowMode(ClipByChildren); 266 | } 267 | function onMotion(event) 268 | { 269 | if (self.pressed) { 270 | int x = self.x; 271 | int y = self.y; 272 | int x1 = self.x1; 273 | int y1 = self.y1; 274 | int x2 = event.x(); 275 | int y2 = event.y(); 276 | if (x != x1 && y != y1) 277 | self.rectangle(x, y, x1, y1); 278 | self.rectangle(x, y, x2, y2); 279 | self.x1 =: x2; 280 | self.y1 =: y2; 281 | } 282 | } 283 | function rectangle(int x1, int y1, int x2, int y2) 284 | { 285 | int x = x1; 286 | int y = y1; 287 | int width = x2 - x; 288 | int height = y2 - y; 289 | if (width && height) { 290 | if (x > x2) { 291 | x = x2; 292 | width = -width; 293 | } 294 | if (y > y2) { 295 | y = y2; 296 | height = -height; 297 | } 298 | self.DrawRectangle(x, y, width, height); 299 | } 300 | } 301 | function onClientMessage(event) 302 | { 303 | self.Destroy(); 304 | } 305 | } 306 | 307 | class Box : ChildWindow 308 | { 309 | var moving; 310 | var posx; 311 | var posy; 312 | var width; 313 | var height; 314 | var movex; 315 | var movey; 316 | function Box(parent, int x, int y, int width, int height, style [optional]) 317 | { 318 | self.ChildWindow(parent, x, y, width, height, style); 319 | self.moving = false; 320 | self.posx = x; 321 | self.posy = y; 322 | self.width = width; 323 | self.height = height; 324 | self.movex = 0; 325 | self.movey = 0; 326 | self.OnConfigure += function(event) 327 | { 328 | self.width =: int(event.width()); 329 | self.height =: int(event.height()); 330 | self.posx =: int(event.x()); 331 | self.posy =: int(event.y()); 332 | }; 333 | self.OnExpose += function (event) 334 | { 335 | int width = self.width - 1; 336 | int height = self.height - 1; 337 | self.DrawLine(0, 0, width, 0); 338 | self.DrawLine(0, height, width, height); 339 | self.DrawLine(0, 0, 0, height); 340 | self.DrawLine(width, 0, width, height); 341 | }; 342 | self.OnButtonPress += function (event) 343 | { 344 | self.moving =: true; 345 | self.movex =: int(event.x_root()); 346 | self.movey =: int(event.y_root()); 347 | parent.activate(self); 348 | }; 349 | self.OnButtonRelease += function (event) 350 | { 351 | self.moving =: false; 352 | }; 353 | self.OnMotion += function (event) 354 | { 355 | if (self.moving) { 356 | int evx = event.x_root(); 357 | int evy = event.y_root(); 358 | int x = evx - self.movex; 359 | int y = evy - self.movey; 360 | if (x != 0 || y != 0) { 361 | self.movex =: evx; 362 | self.movey =: evy; 363 | int childx = self.posx + x; 364 | int childy = self.posy + y; 365 | self.MoveWindow(childx, childy); 366 | self.posx =: childx; 367 | self.posy =: childy; 368 | } 369 | } 370 | }; 371 | } 372 | } 373 | 374 | //********************************************************************** 375 | 376 | function main(args) 377 | { 378 | var controller = new Controller(); 379 | controller.setDefaultFont("-*-liberation.mono-medium-r-*-*-*-120-*"); 380 | 381 | var boxes = new Boxes(controller); 382 | boxes.SetWMProtocols(['WM_DELETE_WINDOW']); 383 | boxes.Map(); 384 | 385 | controller.MainLoop(); 386 | 387 | say('End'); 388 | controller.Close(); 389 | } 390 | 391 | // End. 392 | -------------------------------------------------------------------------------- /examples/graph.winxed: -------------------------------------------------------------------------------- 1 | #! winxed 2 | 3 | // graph 4 | 5 | //************************************************************** 6 | 7 | $load "Guitor.pbc"; 8 | 9 | $include "Guitor.winxhead"; 10 | 11 | using namespace Guitor; 12 | using namespace Guitor.Events; 13 | 14 | //************************************************************** 15 | 16 | class Graph : TopLevelWindow 17 | { 18 | var funcs; 19 | var x0; 20 | var x1; 21 | var y0; 22 | var y1; 23 | var width; 24 | var height; 25 | var pressed; 26 | var xp0; 27 | var yp0; 28 | var xp1; 29 | var yp1; 30 | function Graph(controller, width, height, string expr, funcs, float x0, float x1, float y0, float y1) 31 | { 32 | self.pressed = false; 33 | self.funcs = funcs; 34 | self.x0 = x0; 35 | self.x1 = x1; 36 | self.y0 = y0; 37 | self.y1 = y1; 38 | self.width = width; 39 | self.height = height; 40 | 41 | self.TopLevelWindow(controller, "graph - " + expr, 0, 0, width, height); 42 | self.OnClientMessage += function (event) { self.onClientMessage(event); }; 43 | self.OnConfigure += function (event) { self.onConfigure(event); }; 44 | self.OnExpose += function (event) { self.onExpose(event); }; 45 | self.OnKeyPress += function (event) { self.onKeyPress(event); }; 46 | self.OnButtonPress += function (event) { self.onButtonPress(event); }; 47 | self.OnButtonRelease += function (event) { self.onButtonRelease(event); }; 48 | self.OnMotion += function (event) { self.onMotion(event); }; 49 | 50 | var font = self.display.CreateFont("Bitstream Vera Sans Mono,Free Mono-12"); 51 | if (font != null) 52 | self.SetFont(font); 53 | } 54 | function drawfun(fun) 55 | { 56 | float x0 = self.x0; 57 | float x1 = self.x1; 58 | float y0 = self.y0; 59 | float y1 = self.y1; 60 | int width = self.width; 61 | int height = self.height; 62 | int prev = false; 63 | int i0, j0; 64 | for (int i = 0; i < width; ++i) { 65 | try { 66 | float x = x0 + (float(i) / width) * (x1 - x0); 67 | float y = fun(x); 68 | int j = height - 1 - (y - y0) / (y1 - y0) * height; 69 | int current = true; 70 | if (j < 0 || j >= height) { 71 | current = false; 72 | if (prev) { 73 | j = j < 0 ? 0 : height - 1; 74 | self.DrawLine(i0, j0, i, j); 75 | } 76 | } 77 | else { 78 | if (prev) 79 | self.DrawLine(i0, j0, i, j); 80 | else 81 | self.DrawPoint(i, j); 82 | } 83 | prev = current; 84 | i0 = i; 85 | j0 = j; 86 | } 87 | catch () { 88 | prev = false; 89 | } 90 | } 91 | } 92 | function onClientMessage(event) 93 | { 94 | self.Destroy(); 95 | } 96 | function onConfigure(event) 97 | { 98 | self.width =: int(event.width()); 99 | self.height =: int(event.height()); 100 | } 101 | function onExpose(event) 102 | { 103 | float x0 = self.x0; 104 | float x1 = self.x1; 105 | float y0 = self.y0; 106 | float y1 = self.y1; 107 | int width = self.width; 108 | int height = self.height; 109 | try { 110 | int j = height + y0 * height / (y1 - y0); 111 | if (j > 0 && j < height) 112 | self.DrawLine(0, j, width, j); 113 | } 114 | catch () { } 115 | try { 116 | int i = -x0 * width / (x1 - x0); 117 | if (i > 0 && i < width) 118 | self.DrawLine(i, 0, i, height); 119 | } 120 | catch () { } 121 | 122 | var funcs = self.funcs; 123 | if (elements(funcs) == 1) 124 | self.drawfun(funcs[0]); 125 | else { 126 | string colors[] = [ "black", "red", "blue", "green" ]; 127 | int ncolors = elements(colors); 128 | int i = 0; 129 | for (var fun in self.funcs) { 130 | self.SetForeground(colors[i]); 131 | i = (i + 1) % ncolors; 132 | self.drawfun(fun); 133 | } 134 | self.SetForeground(colors[0]); 135 | } 136 | } 137 | function onKeyPress(event) 138 | { 139 | var display = self.display; 140 | float x0 = self.x0; 141 | float x1 = self.x1; 142 | float y0 = self.y0; 143 | float y1 = self.y1; 144 | float r; 145 | int code = event.keycode(); 146 | string key = display.KeysymToString(display.KeycodeToKeysym(code)); 147 | switch (key) { 148 | case "Escape": 149 | self.Destroy(); 150 | break; 151 | case "plus": 152 | r = (x1 - x0) / 4; 153 | x0 += r; 154 | x1 -= r; 155 | self.x0 =: x0; 156 | self.x1 =: x1; 157 | r = (y1 - y0) / 4; 158 | y0 += r; 159 | y1 -= r; 160 | self.y0 =: y0; 161 | self.y1 =: y1; 162 | self.ClearArea(0, 0, self.width, self.height, 1); 163 | break; 164 | case "minus": 165 | r = (x1 - x0) / 2; 166 | x0 -= r; 167 | x1 += r; 168 | self.x0 =: x0; 169 | self.x1 =: x1; 170 | r = (y1 - y0) / 2; 171 | y0 -= r; 172 | y1 += r; 173 | self.y0 =: y0; 174 | self.y1 =: y1; 175 | self.ClearArea(0, 0, self.width, self.height, 1); 176 | break; 177 | case "Left": 178 | self.movehor(-4); 179 | break; 180 | case "Right": 181 | self.movehor(4); 182 | break; 183 | case "Up": 184 | self.movever(4); 185 | break; 186 | case "Down": 187 | self.movever(-4); 188 | break; 189 | } 190 | } 191 | function onButtonPress(event) 192 | { 193 | int button = event.button(); 194 | switch (button) { 195 | case 1: 196 | case 3: 197 | break; 198 | case 4: 199 | self.movever(4); 200 | return; 201 | case 5: 202 | self.movever(-4); 203 | return; 204 | default: 205 | return; 206 | } 207 | self.pressed =: button; 208 | int x = event.x(); 209 | int y = event.y(); 210 | self.xp0 = x; 211 | self.yp0 = y; 212 | self.xp1 = x; 213 | self.yp1 = y; 214 | self.SetFunction(GXinvert); 215 | self.SetLineAttributes(0, LineOnOffDash, 0, 0); 216 | self.SetSubwindowMode(IncludeInferiors); 217 | } 218 | function onButtonRelease(event) 219 | { 220 | int button = self.pressed; 221 | if (! button) 222 | return; 223 | self.pressed =: false; 224 | int xp0 = self.xp0; 225 | int yp0 = self.yp0; 226 | int nxp1 = self.xp1; 227 | int nyp1 = self.yp1; 228 | self.rectangle(xp0, yp0, nxp1, nyp1); 229 | self.SetFunction(GXcopy); 230 | self.SetLineAttributes(0, LineSolid, 0, 0); 231 | self.SetSubwindowMode(ClipByChildren); 232 | int nxp0 = xp0; 233 | if (nxp0 > nxp1) { 234 | nxp0 = nxp1; 235 | nxp1 = xp0; 236 | } 237 | int nyp0 = yp0; 238 | if (nyp0 > nyp1) { 239 | nyp0 = nyp1; 240 | nyp1 = yp0; 241 | } 242 | float x0 = self.x0; 243 | float x1 = self.x1; 244 | float y0 = self.y0; 245 | float y1 = self.y1; 246 | int width = self.width; 247 | int height = self.height; 248 | if (nxp0 == nxp1 || nyp0 == nyp1) { 249 | int i = self.xp1; 250 | int j = self.yp1; 251 | float x = x0 + (float(i) / width) * (x1 - x0); 252 | float y = y0 + (float(height - j) / height) * (y1 - y0); 253 | self.SetForeground("white"); 254 | self.FillRectangle(4, 4, 280, 42); 255 | string sx = "x: " + string(x); 256 | string sy = "y: " + string(y); 257 | int lx = self.getTextWidth(sx); 258 | int ly = self.getTextWidth(sy); 259 | if (ly > lx) 260 | lx = ly; 261 | self.SetForeground("gray"); 262 | self.FillRectangle(4, 4, lx + 16, 41); 263 | self.SetForeground("black"); 264 | self.DrawString(12, 22, sx); 265 | self.DrawString(12, 38, sy); 266 | self.DrawRectangle(4, 4, lx + 16, 41); 267 | return; 268 | } 269 | float xx0, xx1, yy0, yy1; 270 | xx0 = x0 + (nxp0 / width) * (x1 - x0); 271 | xx1 = x0 + (nxp1 / width) * (x1 - x0); 272 | float yy = height - nyp0; 273 | yy1 = y0 + (yy / height) * (y1 - y0); 274 | yy = height - nyp1; 275 | yy0 = y0 + (yy / height) * (y1 - y0); 276 | switch (button) { 277 | case 1: 278 | break; 279 | case 3: 280 | var t0 = x0 + (x0 - xx0) * (x1 - x0) / (xx1 - xx0); 281 | var t1 = x0 + (x1 - xx0) * (x1 - x0) / (xx1 - xx0); 282 | xx0 = t0; 283 | xx1 = t1; 284 | t0 = y0 + (y0 - yy0) * (y1 - y0) / (yy1 - yy0); 285 | t1 = y0 + (y1 - yy0) * (y1 - y0) / (yy1 - yy0); 286 | yy0 = t0; 287 | yy1 = t1; 288 | break; 289 | default: 290 | return; 291 | } 292 | self.x0 =: xx0; 293 | self.x1 =: xx1; 294 | self.y0 =: yy0; 295 | self.y1 =: yy1; 296 | self.ClearArea(0, 0, width, height, 1); 297 | } 298 | function onMotion(event) 299 | { 300 | if (self.pressed) { 301 | int x = self.xp0; 302 | int y = self.yp0; 303 | int x0 = self.xp1; 304 | int y0 = self.yp1; 305 | int x1 = event.x(); 306 | int y1 = event.y(); 307 | if (x != x0 && y != y0) 308 | self.rectangle(x, y, x0, y0); 309 | self.rectangle(x, y, x1, y1); 310 | self.xp1 =: x1; 311 | self.yp1 =: y1; 312 | } 313 | } 314 | function movehor(int move) 315 | { 316 | int width = self.width; 317 | float despl = (self.x1 - self.x0) / width * move; 318 | self.x0 += despl; 319 | self.x1 += despl; 320 | self.ClearArea(0, 0, width, self.height, 1); 321 | } 322 | function movever(int move) 323 | { 324 | float despl = (self.y1 - self.y0) / self.width * move; 325 | self.y1 += despl; 326 | self.y0 += despl; 327 | self.ClearArea(0, 0, self.width, self.height, 1); 328 | } 329 | function rectangle(int x0, int y0, int x1, int y1) 330 | { 331 | int x = x0; 332 | int y = y0; 333 | int width = x1 - x; 334 | int height = y1 - y; 335 | if (width && height) { 336 | if (x > x1) { 337 | x = x1; 338 | width = -width; 339 | } 340 | if (y > y1) { 341 | y = y1; 342 | height = -height; 343 | } 344 | self.DrawRectangle(x, y, width, height); 345 | } 346 | } 347 | } 348 | 349 | //************************************************************** 350 | 351 | function rangey(fun, float x0, float x1) 352 | { 353 | float y0 = 1.e100; 354 | float y1 = -1.e100; 355 | float step = (x1 - x0) / 800; 356 | for (float x = x0; x <= x1; x += step) { 357 | try { 358 | float y = fun(x); 359 | if (y < y0) 360 | y0 = y; 361 | if (y > y1) 362 | y1 = y; 363 | } 364 | catch () 365 | { 366 | } 367 | } 368 | return y0, y1; 369 | } 370 | 371 | //************************************************************** 372 | 373 | function compile(string expr) 374 | { 375 | expr = "function evalexpr(float x) {\n return (" + expr + "); }\n"; 376 | load_language("winxed"); 377 | var compiler = compreg("winxed"); 378 | if (compiler == null) 379 | throw "Can't get winxed compiler"; 380 | var code = compiler.compile(expr); 381 | var fun = code[0]; 382 | return fun; 383 | } 384 | 385 | function main [main](args) 386 | { 387 | int nargs = elements(args); 388 | if (nargs < 2) { 389 | cry("usage: graph [ --range x0,x1[y0,y1] ] function [ more functions ]"); 390 | exit(1); 391 | } 392 | 393 | var display = new Display(); 394 | int swidth = display.Width(); 395 | int sheight = display.Height(); 396 | int width = swidth - swidth / 3; 397 | int height = sheight - sheight / 3; 398 | 399 | int iarg = 1; 400 | float x0 = -10, x1 = 10, y0, y1; 401 | if (args[iarg] == "--range") { 402 | ++iarg; 403 | var values = split(",", args[iarg]); 404 | switch (elements(values)) { 405 | case 4: 406 | y0 = values[2]; 407 | y1 = values[3]; 408 | case 2: 409 | x0 = values[0]; 410 | x1 = values[1]; 411 | break; 412 | default: 413 | cry("Invalid range"); 414 | exit(1); 415 | } 416 | ++iarg; 417 | } 418 | if (y0 == 0 || y1 == 0) { 419 | float p = float(x1 - x0) * height / width; 420 | if (y0 == 0) 421 | if (y1 == 0) { 422 | y1 = p / 2; 423 | y0 = -y1; 424 | } 425 | else 426 | y0 = y1 - p; 427 | else 428 | y1 = y0 + p; 429 | } 430 | 431 | string expr = ""; 432 | var funcs = []; 433 | for (; iarg < nargs; ++iarg) { 434 | string newexpr = args[iarg]; 435 | expr = expr + " | " + newexpr; 436 | try { 437 | var fun = compile(newexpr); 438 | push(funcs, fun); 439 | } 440 | catch (e) { 441 | cry("error compiling function: ", e["message"]); 442 | exit(1); 443 | } 444 | } 445 | if (elements(funcs) == 0) { 446 | cry("usage: graph [ --range x0,x1[y0,y1] ] function [ more functions ]"); 447 | exit(1); 448 | } 449 | 450 | var controller = new Controller(display); 451 | var graph = new Graph(controller, width, height, expr, funcs, x0, x1, y0, y1); 452 | int loop = true; 453 | display.SetWMProtocols(graph, ['WM_DELETE_WINDOW']); 454 | graph.OnDestroy += function (event) { 455 | loop = false; 456 | }; 457 | 458 | graph.Map(); 459 | var event = new Event(); 460 | while (loop) { 461 | display.NextEvent(event); 462 | controller.handleEvent(event); 463 | } 464 | display.Close(); 465 | } 466 | 467 | // End 468 | -------------------------------------------------------------------------------- /src/GuitorNci.winxed: -------------------------------------------------------------------------------- 1 | #! winxed 2 | 3 | // GuitorNci.winxed 4 | 5 | // Xlib NCI for Guitor 6 | 7 | namespace Guitor 8 | { 9 | 10 | //************************************************************** 11 | // Internal helper functions 12 | //************************************************************** 13 | 14 | 15 | namespace Xlib__nci 16 | { 17 | // Variable names 18 | const string 19 | XLIB = "xlib", 20 | XFTLIB = "xftlib", 21 | XPMLIB = "xpmlib", 22 | EVENTPAD = "eventpad", 23 | ANYVIEW = "anyview", 24 | BUTTONVIEW = "buttonview", 25 | KEYVIEW = "keyview", 26 | MOTIONVIEW = "motionview", 27 | STRUCTUREVIEW = "structureview", 28 | EXPOSEVIEW = "exposeview", 29 | FOCUSVIEW = "focusview", 30 | MAPVIEW = "mapview", 31 | CROSSINGVIEW = "crossingview", 32 | SELECTIONCLEARVIEW = "selectionclearview", 33 | SELECTIONVIEW = "selectionview", 34 | SELECTIONREQUESTVIEW = "selectionrequestview", 35 | CLIENTVIEW = "clientview", 36 | XTEXTPROPERTY = "xtextproperty", 37 | XAWMHINTSVIEW = "xawmhintsview", 38 | ATOMVIEW = "atomview", 39 | XCOLORVIEW = "xcolorview", 40 | XFTCOLORVIEW = "xftcolorview", 41 | XFONTVIEW = "xfontview", 42 | XFTFONTVIEW = "xftfontview", 43 | GLYPHINFOVIEW = "glyphinfoview"; 44 | 45 | function loadXlib() 46 | { 47 | string libs[] = [ 48 | "libX11", 49 | "libX11.so", 50 | "libX11.so.6", 51 | "/usr/lib/libX11.so", 52 | "/usr/lib/libX11.so.6", 53 | "cygX11-6" 54 | ]; 55 | var l; 56 | for (string lib in libs) { 57 | l= loadlib(lib); 58 | if (l) break; 59 | } 60 | return l; 61 | } 62 | 63 | function loadXftlib() 64 | { 65 | string libs[] = [ 66 | "libXft", 67 | "libXft.so", 68 | "libXft.so.2" 69 | ]; 70 | var l; 71 | for (string lib in libs) { 72 | l= loadlib(lib); 73 | if (l) break; 74 | } 75 | return l; 76 | } 77 | 78 | function loadXpmlib() 79 | { 80 | string libs[] = [ 81 | "libXpm", 82 | "libXpm.so", 83 | "libXpm.so.4" 84 | ]; 85 | var l; 86 | for (string lib in libs) { 87 | l= loadlib(lib); 88 | if (l) break; 89 | } 90 | return l; 91 | } 92 | 93 | function getlib() 94 | { 95 | var ns = namespace Xlib__nci; 96 | var l = ns[XLIB]; 97 | if (l == null) 98 | ns[XLIB] = l = loadXlib(); 99 | return l; 100 | } 101 | 102 | function getxftlib() 103 | { 104 | var ns = namespace Xlib__nci; 105 | var l = ns[XFTLIB]; 106 | if (l == null) 107 | ns[XFTLIB] = l = loadXftlib(); 108 | return l; 109 | } 110 | 111 | function getxpmlib() 112 | { 113 | var ns = namespace Xlib__nci; 114 | var l = ns[XPMLIB]; 115 | if (l == null) 116 | ns[XPMLIB] = l = loadXpmlib(); 117 | return l; 118 | } 119 | 120 | } 121 | 122 | namespace Xlib__private 123 | { 124 | 125 | $include_const "datatypes.pasm"; 126 | 127 | using namespace Xlib__nci; 128 | 129 | //************************************************************** 130 | /* 131 | Event structure definition. 132 | Values used for sizes and offsets are derived 133 | from Xlib docs and testing in several platforms. 134 | */ 135 | 136 | const int XLIB_Bool = DATATYPE_INT32; 137 | const int XLIB_Atom = DATATYPE_LONG; 138 | const int XLIB_time_t = DATATYPE_LONG; 139 | const int XLIB_Window = DATATYPE_LONG; 140 | 141 | //************************************************************** 142 | 143 | function geteventpad() 144 | { 145 | var ns = namespace Xlib__nci; 146 | var st = ns[EVENTPAD]; 147 | if (st == null) { 148 | const int PAD = 24; 149 | int viewdata [PAD + 2] = [ DATATYPE_STRUCT, PAD ]; 150 | for (int i = 0; i < PAD; ++i) 151 | viewdata[i + 2] = DATATYPE_LONG; 152 | ns[EVENTPAD] = st = new ["StructView"](viewdata); 153 | } 154 | return st; 155 | } 156 | 157 | function getanyview() 158 | { 159 | var ns = namespace Xlib__nci; 160 | var st = ns[ANYVIEW]; 161 | if (st == null) 162 | ns[ANYVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 5, 163 | DATATYPE_INT, // type 164 | DATATYPE_LONG, // serial 165 | XLIB_Bool, // send event 166 | DATATYPE_PTR, // display 167 | XLIB_Window // window 168 | ] ); 169 | return st; 170 | } 171 | 172 | function getbuttonview() 173 | { 174 | var ns = namespace Xlib__nci; 175 | var st = ns[BUTTONVIEW]; 176 | if (st == null) 177 | ns[BUTTONVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 14, 178 | DATATYPE_INT, // type 179 | DATATYPE_LONG, // serial 180 | XLIB_Bool, // send event 181 | DATATYPE_PTR, // display 182 | XLIB_Window, // window 183 | XLIB_Window, // root 184 | XLIB_Window, // subwindow 185 | XLIB_time_t, // time 186 | DATATYPE_INT, // x 187 | DATATYPE_INT, // y 188 | DATATYPE_INT, // x_root 189 | DATATYPE_INT, // y_root 190 | DATATYPE_INT, // state 191 | DATATYPE_INT, // button 192 | XLIB_Bool // same_screen 193 | ] ); 194 | return st; 195 | } 196 | 197 | function getkeyview() 198 | { 199 | var ns = namespace Xlib__nci; 200 | var st = ns[KEYVIEW]; 201 | if (st == null) 202 | ns[KEYVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 14, 203 | DATATYPE_INT, // type 204 | DATATYPE_LONG, // serial 205 | XLIB_Bool, // send event 206 | DATATYPE_PTR, // display 207 | XLIB_Window, // window 208 | XLIB_Window, // root 209 | XLIB_Window, // subwindow 210 | XLIB_time_t, // time 211 | DATATYPE_INT, // x 212 | DATATYPE_INT, // y 213 | DATATYPE_INT, // x_root 214 | DATATYPE_INT, // y_root 215 | DATATYPE_INT, // state 216 | DATATYPE_INT, // keycode 217 | XLIB_Bool // same_screen 218 | ] ); 219 | return st; 220 | } 221 | 222 | function getmotionview() 223 | { 224 | var ns = namespace Xlib__nci; 225 | var st = ns[MOTIONVIEW]; 226 | if (st == null) 227 | ns[MOTIONVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 14, 228 | DATATYPE_INT, // type 229 | DATATYPE_LONG, // serial 230 | XLIB_Bool, // send event 231 | DATATYPE_PTR, // display 232 | XLIB_Window, // window 233 | XLIB_Window, // root 234 | XLIB_Window, // subwindow 235 | XLIB_time_t, // time 236 | DATATYPE_INT, // x 237 | DATATYPE_INT, // y 238 | DATATYPE_INT, // x_root 239 | DATATYPE_INT, // y_root 240 | DATATYPE_INT, // state 241 | DATATYPE_INT // keycode 242 | ] ); 243 | return st; 244 | } 245 | 246 | function getstructureview() 247 | { 248 | var ns = namespace Xlib__nci; 249 | var st = ns[STRUCTUREVIEW]; 250 | if (st == null) 251 | ns[STRUCTUREVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 13, 252 | DATATYPE_INT, // type 253 | DATATYPE_LONG, // serial 254 | XLIB_Bool, // send event 255 | DATATYPE_PTR, // display 256 | XLIB_Window, // event window 257 | XLIB_Window, // window 258 | DATATYPE_INT, // x 259 | DATATYPE_INT, // y 260 | DATATYPE_INT, // width 261 | DATATYPE_INT, // height 262 | DATATYPE_INT, // border_width 263 | XLIB_Window, // above 264 | XLIB_Bool // override_redirect 265 | ] ); 266 | return st; 267 | } 268 | 269 | function getexposeview() 270 | { 271 | var ns = namespace Xlib__nci; 272 | var st = ns[EXPOSEVIEW]; 273 | if (st == null) 274 | ns[EXPOSEVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 10, 275 | DATATYPE_INT, // type 276 | DATATYPE_LONG, // serial 277 | XLIB_Bool, // send event 278 | DATATYPE_PTR, // display 279 | XLIB_Window, // window 280 | DATATYPE_INT, // x 281 | DATATYPE_INT, // y 282 | DATATYPE_INT, // width 283 | DATATYPE_INT, // height 284 | DATATYPE_INT // count 285 | ] ); 286 | return st; 287 | } 288 | 289 | function getfocusview() 290 | { 291 | var ns = namespace Xlib__nci; 292 | var st = ns[FOCUSVIEW]; 293 | if (st == null) 294 | ns[FOCUSVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 7, 295 | DATATYPE_INT, // type 296 | DATATYPE_LONG, // serial 297 | XLIB_Bool, // send event 298 | DATATYPE_PTR, // display 299 | XLIB_Window, // window 300 | DATATYPE_INT, // mode 301 | DATATYPE_INT // detail 302 | ] ); 303 | return st; 304 | } 305 | 306 | function getmapview() 307 | { 308 | // Used for Map and Unmap Notify 309 | var ns = namespace Xlib__nci; 310 | var st = ns[MAPVIEW]; 311 | if (st == null) 312 | ns[FOCUSVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 7, 313 | DATATYPE_INT, // type 314 | DATATYPE_LONG, // serial 315 | XLIB_Bool, // send event 316 | DATATYPE_PTR, // display 317 | XLIB_Window, // event window 318 | XLIB_Window, // window mapped 319 | XLIB_Bool // dverride_redirect or from_configure 320 | ] ); 321 | return st; 322 | } 323 | 324 | function getcrossingview() 325 | { 326 | var ns = namespace Xlib__nci; 327 | var st = ns[CROSSINGVIEW]; 328 | if (st == null) 329 | ns[CROSSINGVIEW] = st = new ["StructView"] ( [ DATATYPE_STRUCT, 17, 330 | DATATYPE_INT, // type 331 | DATATYPE_LONG, // serial 332 | XLIB_Bool, // send event 333 | DATATYPE_PTR, // display 334 | XLIB_Window, // window 335 | XLIB_Window, // root 336 | XLIB_Window, // subwindow 337 | XLIB_time_t, // time 338 | DATATYPE_INT, // x 339 | DATATYPE_INT, // y 340 | DATATYPE_INT, // x_root 341 | DATATYPE_INT, // y_root 342 | DATATYPE_INT, // mode 343 | DATATYPE_INT, // detail 344 | XLIB_Bool, // same_screen 345 | XLIB_Bool, // focus 346 | DATATYPE_INT // state 347 | ] ); 348 | return st; 349 | } 350 | 351 | function getselectionclearview() 352 | { 353 | var ns = namespace Xlib__nci; 354 | var st = ns[SELECTIONCLEARVIEW]; 355 | if (st == null) 356 | ns[SELECTIONCLEARVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 7, 357 | DATATYPE_INT, // type 358 | DATATYPE_LONG, // serial 359 | XLIB_Bool, // send event 360 | DATATYPE_PTR, // display 361 | XLIB_Window, // window 362 | XLIB_Atom, // selection 363 | XLIB_time_t // time 364 | ] ); 365 | return st; 366 | } 367 | 368 | function getselectionrequestview() 369 | { 370 | var ns = namespace Xlib__nci; 371 | var st = ns[SELECTIONREQUESTVIEW]; 372 | if (st == null) 373 | ns[SELECTIONREQUESTVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 10, 374 | DATATYPE_INT, // type 375 | DATATYPE_LONG, // serial 376 | XLIB_Bool, // send event 377 | DATATYPE_PTR, // display 378 | XLIB_Window, // owner 379 | XLIB_Window, // requestor 380 | XLIB_Atom, // selection 381 | XLIB_Atom, // target 382 | XLIB_Atom, // property 383 | XLIB_time_t // time 384 | ] ); 385 | return st; 386 | } 387 | 388 | function getselectionview() 389 | { 390 | var ns = namespace Xlib__nci; 391 | var st = ns[SELECTIONVIEW]; 392 | if (st == null) 393 | ns[SELECTIONVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 9, 394 | DATATYPE_INT, // type 395 | DATATYPE_LONG, // serial 396 | XLIB_Bool, // send event 397 | DATATYPE_PTR, // display 398 | XLIB_Window, // requestor 399 | XLIB_Atom, // selection 400 | XLIB_Atom, // target 401 | XLIB_Atom, // property 402 | XLIB_time_t // time 403 | ] ); 404 | return st; 405 | } 406 | 407 | function getclientview() 408 | { 409 | var ns = namespace Xlib__nci; 410 | var st = ns[CLIENTVIEW]; 411 | if (st == null) 412 | ns[CLIENTVIEW] = st = new ["StructView"] ( [ DATATYPE_STRUCT, 10, 413 | DATATYPE_INT, // type 414 | DATATYPE_LONG, // serial 415 | XLIB_Bool, // send event 416 | DATATYPE_PTR, // display 417 | DATATYPE_INT, // window 418 | XLIB_Atom, // message_type 419 | DATATYPE_INT, // format 420 | DATATYPE_LONG, // data l 0 421 | DATATYPE_LONG, // data l 1 422 | DATATYPE_LONG // data l 2 423 | ] ); 424 | return st; 425 | } 426 | 427 | //************************************************************** 428 | 429 | // Other structures 430 | 431 | function getatomview(int n) 432 | { 433 | int init[2 + n] = [ DATATYPE_STRUCT, n ]; 434 | for (int i = 0; i < n; ++i) 435 | init[i + 2] = XLIB_Atom; 436 | return new ["StructView"] (init); 437 | } 438 | 439 | function gettextpropertyview() 440 | { 441 | var ns = namespace Xlib__nci; 442 | var st = ns[XTEXTPROPERTY]; 443 | if (st == null) 444 | ns[XTEXTPROPERTY] = st = new ["StructView"]( [ DATATYPE_STRUCT, 4, 445 | DATATYPE_PTR, // value 446 | XLIB_Atom, // encoding 447 | DATATYPE_INT, // format 448 | DATATYPE_LONG // nitems 449 | ] ); 450 | return st; 451 | } 452 | 453 | function textpropertyfromstring(string str, int encoding) 454 | { 455 | var view = gettextpropertyview(); 456 | var prop = view.alloc(); 457 | var pstr = str_to_achar_utf8(str); 458 | int l = elements(pstr); 459 | view[prop, 0] = pstr; 460 | view[prop, 1] = encoding; 461 | view[prop, 2] = 8; 462 | view[prop, 3] = l; 463 | return prop; 464 | } 465 | 466 | function getxawmhints() 467 | { 468 | var ns = namespace Xlib__nci; 469 | var st = ns[XAWMHINTSVIEW]; 470 | if (st == null) 471 | ns[XAWMHINTSVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 9, 472 | DATATYPE_LONG, // flags 473 | XLIB_Bool, // input 474 | DATATYPE_INT, // initial_state 475 | DATATYPE_PTR, // icon_pixmap 476 | DATATYPE_PTR, // icon_window 477 | DATATYPE_INT, // icon_x 478 | DATATYPE_INT, // icon_y 479 | DATATYPE_PTR, // icon_mask 480 | DATATYPE_PTR // window_group 481 | ] ); 482 | return st; 483 | } 484 | 485 | function getxcolorview() 486 | { 487 | var ns = namespace Xlib__nci; 488 | var st = ns[XCOLORVIEW]; 489 | if (st == null) 490 | ns[XCOLORVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 6, 491 | DATATYPE_LONG, // pixel 492 | DATATYPE_SHORT, // red 493 | DATATYPE_SHORT, // green 494 | DATATYPE_SHORT, // blue 495 | DATATYPE_CHAR, // flags 496 | DATATYPE_CHAR // pad 497 | ] ); 498 | return st; 499 | } 500 | 501 | function getxftcolorview() 502 | { 503 | var ns = namespace Xlib__nci; 504 | var st = ns[XFTCOLORVIEW]; 505 | if (st == null) 506 | ns[XFTCOLORVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 5, 507 | DATATYPE_LONG, // pixel 508 | DATATYPE_SHORT, // red 509 | DATATYPE_SHORT, // green 510 | DATATYPE_SHORT, // blue 511 | DATATYPE_SHORT // alpha 512 | ] ); 513 | return st; 514 | } 515 | 516 | function getglyphinfoview() 517 | { 518 | var ns = namespace Xlib__nci; 519 | var st = ns[GLYPHINFOVIEW]; 520 | if (st == null) 521 | ns[GLYPHINFOVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 6, 522 | DATATYPE_SHORT, // width 523 | DATATYPE_SHORT, // height 524 | DATATYPE_SHORT, // x 525 | DATATYPE_SHORT, // y 526 | DATATYPE_SHORT, // xOff 527 | DATATYPE_SHORT // yOff 528 | ] ); 529 | return st; 530 | } 531 | 532 | function getxfontview() 533 | { 534 | var ns = namespace Xlib__nci; 535 | var st = ns[XFONTVIEW]; 536 | if (st == null) 537 | ns[XFONTVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 24, 538 | DATATYPE_PTR, // ext_data 539 | DATATYPE_INT, // fid 540 | DATATYPE_INT, // direction 541 | DATATYPE_INT, // min_char_or_byte2 542 | DATATYPE_INT, // max_char_or_byte2 543 | DATATYPE_INT, // min_byte1 544 | DATATYPE_INT, // max_byte1 545 | XLIB_Bool, // all_chars_exists 546 | DATATYPE_INT, // default_char 547 | DATATYPE_INT, // n_properties 548 | DATATYPE_PTR, // properties 549 | // min_bounds 550 | DATATYPE_SHORT, // lbearing 551 | DATATYPE_SHORT, // rbearing 552 | DATATYPE_SHORT, // width 553 | DATATYPE_SHORT, // ascent 554 | DATATYPE_SHORT, // descent 555 | // max_bounds 556 | DATATYPE_SHORT, // lbearing 557 | DATATYPE_SHORT, // rbearing 558 | DATATYPE_SHORT, // width 559 | DATATYPE_SHORT, // ascent 560 | DATATYPE_SHORT, // descent 561 | DATATYPE_PTR, // per_char 562 | DATATYPE_INT, // ascent 563 | DATATYPE_INT // descent 564 | ] ); 565 | return st; 566 | } 567 | 568 | function getxftfontview() 569 | { 570 | var ns = namespace Xlib__nci; 571 | var st = ns[XFTFONTVIEW]; 572 | if (st == null) 573 | ns[XFTFONTVIEW] = st = new ["StructView"]( [ DATATYPE_STRUCT, 5, 574 | DATATYPE_INT, // ascent 575 | DATATYPE_INT, // descent 576 | DATATYPE_INT, // height 577 | DATATYPE_INT, // max_advance_width 578 | DATATYPE_PTR, // charset 579 | DATATYPE_PTR // pattern 580 | ] ); 581 | return st; 582 | } 583 | 584 | //************************************************************** 585 | 586 | function create_function(string funcname) 587 | { 588 | string sig; 589 | switch (funcname) { 590 | case "XFree": 591 | case "XFlush": 592 | sig = "vp"; 593 | break; 594 | case "XSync": 595 | case "XFreePixmap": 596 | case "XRaiseWindow": 597 | sig = "vpi"; 598 | break; 599 | case "XDisplayName": 600 | case "XOpenDisplay": 601 | sig = "pp"; 602 | break; 603 | case "XCloseDisplay": 604 | case "XDefaultScreen": 605 | case "XStringToKeysym": 606 | case "XSetLocaleModifiers": 607 | case "XPending": 608 | sig = "ip"; 609 | break; 610 | case "setlocale": 611 | sig = "pip"; 612 | break; 613 | case "XDefaultGC": 614 | case "XDefaultVisual": 615 | case "XDefaultColormap": 616 | sig = "ppi"; 617 | break; 618 | case "XRootWindow": 619 | case "XDefaultDepth": 620 | case "XBlackPixel": 621 | case "XWhitePixel": 622 | case "XDisplayWidth": 623 | case "XDisplayWidthMM": 624 | case "XDisplayHeight": 625 | case "XDisplayHeightMM": 626 | case "XMapWindow": 627 | case "XUnmapWindow": 628 | case "XDestroyWindow": 629 | case "XFilterEvent": 630 | case "XKeysymToKeycode": 631 | sig = "ipi"; 632 | break; 633 | case "XCreateGC": 634 | sig = "ppipi"; 635 | break; 636 | case "XSetForeground": 637 | case "XSetBackground": 638 | case "XSetFunction": 639 | case "XSetSubwindowMode": 640 | case "XSetClipMask": 641 | sig = "vppi"; 642 | break; 643 | case "XCreatePixmap": 644 | sig = "ipiiii"; 645 | break; 646 | case "XSetInputFocus": 647 | sig = "vpiil"; 648 | break; 649 | case "XSelectInput": 650 | case "XSetTransientForHint": 651 | sig = "vpii"; 652 | break; 653 | case "XNextEvent": 654 | sig = "vpp"; 655 | break; 656 | case "XSendEvent": 657 | sig = "ipiilp"; 658 | break; 659 | case "XKeycodeToKeysym": 660 | sig = "ipii"; 661 | break; 662 | case "XKeysymToString": 663 | sig = "pi"; 664 | break; 665 | case "XLookupString": 666 | sig = "ippipp"; 667 | break; 668 | case "XmbLookupString": 669 | case "Xutf8LookupString": 670 | sig = "ipppipp"; 671 | break; 672 | case "XOpenIM": 673 | sig = "ppppp"; 674 | break; 675 | case "XCreateIC": 676 | sig = "ppplplplp"; 677 | break; 678 | case "XInternAtom": 679 | sig = "ippi"; 680 | break; 681 | case "XGetAtomName": 682 | sig = "ppl"; 683 | break; 684 | case "XStoreName": 685 | sig = "ipip"; 686 | break; 687 | case "XSetWMName": 688 | sig = "vpip"; 689 | break; 690 | case "XDrawPoint": 691 | sig = "ipipii"; 692 | break; 693 | case "XDrawLine": 694 | case "XDrawRectangle": 695 | case "XFillRectangle": 696 | sig = "ipipiiii"; 697 | break; 698 | case "XDrawLines": 699 | sig = "vpippii"; 700 | break; 701 | case "XFillPolygon": 702 | sig = "vpippiii"; 703 | break; 704 | case "XClearArea": 705 | sig = "ipiiiiii"; 706 | break; 707 | case "XCreateSimpleWindow": 708 | sig = "ipiiiiiiii"; 709 | break; 710 | case "XSetWMProtocols": 711 | sig = "ipipi"; 712 | break; 713 | case "XMoveWindow": 714 | case "XResizeWindow": 715 | sig = "ipiii"; 716 | break; 717 | case "XMoveResizeWindow": 718 | sig = "ipiiiii"; 719 | break; 720 | case "XParseColor": 721 | sig = "ipppp"; 722 | break; 723 | case "XAllocColor": 724 | sig = "ippp"; 725 | break; 726 | case "XTextWidth": 727 | case "XmbTextEscapement": 728 | sig = "ippi"; 729 | break; 730 | case "XDrawString": 731 | case "XDrawImageString": 732 | sig = "vpipiipi"; 733 | break; 734 | case "XmbDrawString": 735 | case "XmbDrawImageString": 736 | case "Xutf8DrawString": 737 | sig = "vpippiipi"; 738 | break; 739 | case "XCreateFontSet": 740 | sig = "pppppp"; 741 | break; 742 | case "XSetLineAttributes": 743 | sig = "vppiiii"; 744 | break; 745 | case "XListProperties": 746 | sig = "ppip"; 747 | break; 748 | case "XQueryPointer": 749 | sig = "ipippppppp"; 750 | break; 751 | case "XWarpPointer": 752 | sig = "vpiiiiiiii"; 753 | break; 754 | case "XGrabPointer": 755 | sig = "ipiiiiiiil"; 756 | break; 757 | case "XUngrabPointer": 758 | sig = "vpl"; 759 | break; 760 | case "XGetWindowProperty": 761 | sig = "ipiilliippppp"; 762 | break; 763 | case "XChangeProperty": 764 | sig = "vpiiiiipi"; 765 | break; 766 | case "XSetSelectionOwner": 767 | sig = "vpiil"; 768 | break; 769 | case "XGetSelectionOwner": 770 | sig = "ipi"; 771 | break; 772 | case "XConvertSelection": 773 | sig = "vpiiiil"; 774 | break; 775 | case "XCopyArea": 776 | sig = "vpiipiiiiii"; 777 | break; 778 | default: 779 | throw "Function " + funcname + " unknown"; 780 | } 781 | var func = dlfunc(getlib(), funcname, sig); 782 | return func; 783 | } 784 | 785 | function create_xft_function(string funcname) 786 | { 787 | string sig; 788 | switch (funcname) { 789 | case "XftDrawCreate": 790 | sig = "ppipp"; 791 | break; 792 | case "XftDrawDestroy": 793 | sig = "vp"; 794 | break; 795 | case "XftDrawRect": 796 | sig = "vppiiii"; 797 | break; 798 | case "XftColorAllocName": 799 | sig = "ippppp"; 800 | break; 801 | case "XftFontOpenXlfd": 802 | case "XftFontOpenName": 803 | sig = "ppip"; 804 | break; 805 | case "XftTextExtentsUtf8": 806 | sig = "vpppip"; 807 | break; 808 | case "XftDrawStringUtf8": 809 | sig = "vpppiipi"; 810 | break; 811 | default: 812 | throw "Function " + funcname + " unknown"; 813 | } 814 | var func = dlfunc(getxftlib(), funcname, sig); 815 | return func; 816 | } 817 | 818 | function create_xpm_function(string funcname) 819 | { 820 | string sig; 821 | switch (funcname) { 822 | case "XpmCreatePixmapFromBuffer": 823 | sig = "ipipppp"; 824 | break; 825 | default: 826 | throw "Function " + funcname + " unknown"; 827 | } 828 | var func = dlfunc(getxpmlib(), funcname, sig); 829 | return func; 830 | } 831 | 832 | //************************************************************** 833 | 834 | function str_to_achar(string s) 835 | { 836 | var cstring = new ["ByteBuffer"]; 837 | cstring =: s; 838 | return cstring; 839 | } 840 | 841 | function str_to_achar_utf8(string s) 842 | { 843 | var cstring = new ["ByteBuffer"]; 844 | cstring =: trans_encoding(s, "utf8"); 845 | return cstring; 846 | } 847 | 848 | function str_to_cstring(string s) 849 | { 850 | var cstring = new ["ByteBuffer"]; 851 | cstring =: trans_encoding(s, "utf8"); 852 | push(cstring, 0); 853 | return cstring; 854 | } 855 | 856 | function string_from_nci(p) 857 | { 858 | string s; 859 | if (p != null) 860 | s = p.as_string("utf8"); 861 | return s; 862 | } 863 | 864 | function newAtomlist(int n) 865 | { 866 | var view = getatomview(n); 867 | var data = view.alloc(); 868 | return data; 869 | } 870 | 871 | function getfun(string funcname) 872 | { 873 | var ns = namespace Xlib__nci; 874 | var fun = ns[funcname]; 875 | if (fun == null) 876 | ns[funcname] = fun = create_function(funcname); 877 | return fun; 878 | } 879 | 880 | function getxftfun(string funcname) 881 | { 882 | var ns = namespace Xlib__nci; 883 | var fun = ns[funcname]; 884 | if (fun == null) 885 | ns[funcname] = fun = create_xft_function(funcname); 886 | return fun; 887 | } 888 | 889 | function getxpmfun(string funcname) 890 | { 891 | var ns = namespace Xlib__nci; 892 | var fun = ns[funcname]; 893 | if (fun == null) 894 | ns[funcname] = fun = create_xpm_function(funcname); 895 | return fun; 896 | } 897 | 898 | } // namespace Xlib__private 899 | 900 | } // namespace Guitor 901 | 902 | // End 903 | -------------------------------------------------------------------------------- /examples/pizarra.winxed: -------------------------------------------------------------------------------- 1 | #! winxed 2 | 3 | // pizarra: a simple drawing tool using WinxedXlib module 4 | 5 | 6 | $load "Guitor.pbc"; 7 | 8 | $include "Guitor.winxhead"; 9 | 10 | using namespace Guitor; 11 | using namespace Guitor.Events; 12 | 13 | //********************************************************************** 14 | 15 | function evhandler(object, string methodname) 16 | { 17 | var method = find_method(object, methodname); 18 | return function (event) { object.*method(event); }; 19 | } 20 | 21 | function method_fun(obj, string methodname) 22 | { 23 | var method = find_method(obj, methodname); 24 | return function (args[slurpy]) 25 | { 26 | return obj.*method(args:[flat]); 27 | }; 28 | } 29 | 30 | //********************************************************************** 31 | 32 | // Size in mm 33 | const int BOXWIDTH = 5; 34 | const int BOXHEIGHT = 5; 35 | // Min size in pixels 36 | const int MINBOXWIDTH = 16; 37 | const int MINBOXHEIGHT = 16; 38 | 39 | function boxsize(display) 40 | { 41 | // Convert box size to pixels 42 | int wp = display.Width(); 43 | int wm = display.WidthMM(); 44 | int boxwidth = BOXWIDTH * wp / wm; 45 | int hp = display.Height(); 46 | int hm = display.HeightMM(); 47 | int boxheight = BOXHEIGHT * hp / hm; 48 | if (boxwidth < MINBOXWIDTH) 49 | boxwidth = MINBOXWIDTH; 50 | if (boxheight < MINBOXHEIGHT) 51 | boxheight = MINBOXHEIGHT; 52 | return boxwidth, boxheight; 53 | } 54 | 55 | class BoxedSelector 56 | { 57 | var boxwidth; 58 | var boxheight; 59 | var width; 60 | var height; 61 | function BoxedSelector(display, int xitems, int yitems) 62 | { 63 | :(int boxwidth, int boxheight) = boxsize(display); 64 | self.boxwidth = boxwidth; 65 | self.boxheight = boxheight; 66 | int width = (boxwidth + 2) * xitems + 4; 67 | int height = (boxheight + 2) * yitems + 4; 68 | self.width = width; 69 | self.height = height; 70 | } 71 | function getwidth() 72 | { 73 | return int(self.width); 74 | } 75 | function getheight() 76 | { 77 | return int(self.height); 78 | } 79 | } 80 | 81 | //********************************************************************** 82 | 83 | class ColorSelector : ChildWindow, BoxedSelector 84 | { 85 | 86 | var pizarra; 87 | var colors; 88 | function ColorSelector(pizarra, int x, int y) 89 | { 90 | self.BoxedSelector(pizarra.display, 3, 5); 91 | self.pizarra = pizarra; 92 | string colors[] = [ 93 | "black", "white", "grey", 94 | "red", "green", "blue", 95 | "yellow", "pink", "orange", 96 | "violet", "maroon", "aquamarine", 97 | "coral", "lime green", "light steel blue" 98 | ]; 99 | self.colors = colors; 100 | self.ChildWindow(pizarra, x, y, self.width, self.height); 101 | self.OnExpose += evhandler(self, "onexpose"); 102 | self.OnButtonPress += evhandler(self, "onbuttonpress"); 103 | self.Map(); 104 | } 105 | function onexpose(event) 106 | { 107 | int width = self.width; 108 | int height = self.height; 109 | self.SetForeground("black"); 110 | self.DrawRectangle(0, 0, width - 1, height - 1); 111 | int boxwidth = self.boxwidth; 112 | int boxheight = self.boxheight; 113 | var colors = self.colors; 114 | for (int i = 0; i < 5; ++i) 115 | for (int j = 0; j < 3; ++j) { 116 | self.SetForeground("black"); 117 | int x = 3 + j * (boxwidth + 2); 118 | int y = 3 + i * (boxheight + 2); 119 | self.DrawRectangle(x, y, 120 | boxwidth - 1, boxheight - 1); 121 | string color = colors[i * 3 + j]; 122 | self.SetForeground(color); 123 | self.FillRectangle(x + 1, y + 1, 124 | boxwidth - 2, boxheight - 2); 125 | } 126 | } 127 | function onbuttonpress(event) 128 | { 129 | int boxwidth = self.boxwidth; 130 | int boxheight = self.boxheight; 131 | int x = event.x(); 132 | int y = event.y(); 133 | x = (x - 3) / (boxwidth + 2); 134 | y = (y - 3) / (boxheight + 2); 135 | if (x >= 0 || x < 3 || y >= 0 || y < 5) { 136 | var colors = self.colors; 137 | string color = colors[y * 3 + x]; 138 | self.pizarra.setcolor(color); 139 | } 140 | } 141 | } 142 | 143 | //********************************************************************** 144 | 145 | class ToolSelector : ChildWindow, BoxedSelector 146 | { 147 | var pizarra; 148 | var pmline; 149 | var pmpoly; 150 | var pmfillpoly; 151 | function ToolSelector(pizarra, int x, int y) 152 | { 153 | self.BoxedSelector(pizarra.display, 2, 3); 154 | self.pizarra = pizarra; 155 | self.ChildWindow(pizarra, x, y, self.width, self.height); 156 | self.OnDestroy += evhandler(self, "ondestroy"); 157 | self.OnExpose += evhandler(self, "onexpose"); 158 | self.OnButtonPress += evhandler(self, "onbuttonpress"); 159 | self.Map(); 160 | // Ugly icon for hand drawn lines 161 | self.pmline = self.CreatePixmapFromBuffer(<<: 162 | /* XPM */ 163 | static char *line[] = { 164 | "16 16 2 1", 165 | " c #FFFFFF", 166 | "+ c #000000", 167 | " ", 168 | " ++++ ", 169 | " + ", 170 | " + ", 171 | " ++++ ", 172 | " + ", 173 | " + ", 174 | " + ", 175 | " + ", 176 | " + ", 177 | " ++ ", 178 | " + ", 179 | " + ", 180 | " + ", 181 | " ++++ ", 182 | " ", 183 | }; 184 | :>> 185 | ); 186 | self.pmpoly = self.CreatePixmapFromBuffer(<<: 187 | /* XPM */ 188 | static char *poly[] = { 189 | "16 16 2 1", 190 | " c #FFFFFF", 191 | "+ c #000000", 192 | " ", 193 | " + ", 194 | " ++ ", 195 | " + + ", 196 | " + + ", 197 | " + + ", 198 | " + + ", 199 | " + + ", 200 | " + + ", 201 | " + + ", 202 | " + ++ ", 203 | " + ++ ", 204 | " + ++ ", 205 | " + ++ ", 206 | " ++ ", 207 | " ", 208 | }; 209 | :>> 210 | ); 211 | self.pmfillpoly = self.CreatePixmapFromBuffer(<<: 212 | /* XPM */ 213 | static char *fillpoly[] = { 214 | "16 16 2 1", 215 | " c #FFFFFF", 216 | "+ c #000000", 217 | " ", 218 | " + ", 219 | " ++ ", 220 | " +++ ", 221 | " ++++ ", 222 | " +++++ ", 223 | " ++++++ ", 224 | " ++++++++ ", 225 | " ++++++++++ ", 226 | " ++++++++++++ ", 227 | " ++++++++++++ ", 228 | " +++++++++++ ", 229 | " ++++++++ ", 230 | " +++++ ", 231 | " ++ ", 232 | " ", 233 | }; 234 | :>> 235 | ); 236 | } 237 | function ondestroy(event) 238 | { 239 | for (var pixmap in 240 | [ self.pmline, self.pmpoly, self.pmfillpoly ] ) 241 | if (pixmap != null) 242 | pixmap.Free(); 243 | self.pmline = null; 244 | self.pmpoly = null; 245 | self.pmfillpoly = null; 246 | } 247 | function onexpose(event) 248 | { 249 | int width = self.width; 250 | int height = self.height; 251 | int boxwidth = self.boxwidth; 252 | int boxheight = self.boxheight; 253 | self.SetForeground("black"); 254 | self.DrawRectangle(0, 0, width - 1, height - 1); 255 | for (int i = 0; i < 3; ++i) 256 | for (int j = 0; j < 2; ++j) { 257 | int x = 3 + j * (boxwidth + 2); 258 | int y = 3 + i * (boxheight + 2); 259 | self.DrawRectangle(x, y, boxwidth - 1, boxheight - 1); 260 | switch (i * 2 + j) { 261 | case 0: 262 | self.CopyArea(self.pmline, 0, 0, 16, 16, x + 1, y + 1); 263 | break; 264 | case 1: 265 | self.DrawLine(x + 2, y + 3, x + 10, y + 14); 266 | break; 267 | case 2: 268 | self.DrawRectangle(x + 3, y + 3, boxwidth - 7, boxheight - 7); 269 | break; 270 | case 3: 271 | self.FillRectangle(x + 3, y + 3, boxwidth - 6, boxheight - 6); 272 | break; 273 | case 4: 274 | self.CopyArea(self.pmpoly, 0, 0, 16, 16, x + 1, y + 1); 275 | break; 276 | case 5: 277 | self.CopyArea(self.pmfillpoly, 0, 0, 16, 16, x + 1, y + 1); 278 | break; 279 | } 280 | } 281 | } 282 | function onbuttonpress(event) 283 | { 284 | int boxwidth = self.boxwidth; 285 | int boxheight = self.boxheight; 286 | int x = event.x(); 287 | int y = event.y(); 288 | x = (x - 3) / (boxwidth + 2); 289 | y = (y - 3) / (boxheight + 2); 290 | if (x >= 0 || x < 2 || y >= 0 || y < 2) { 291 | self.pizarra.setmode(y * 2 + x); 292 | } 293 | } 294 | } 295 | 296 | //********************************************************************** 297 | 298 | class Thing 299 | { 300 | var colorspec; 301 | var _color; 302 | function Thing(string colorspec) 303 | { 304 | self.colorspec = colorspec; 305 | } 306 | function _getcolor(drawable) 307 | { 308 | var color = self._color; 309 | if (color == null) 310 | self._color = color = drawable.display.ParseColor(self.colorspec); 311 | return color; 312 | } 313 | function setforeground(drawable) 314 | { 315 | drawable.SetForeground(self._getcolor(drawable)); 316 | } 317 | function setbackground(drawable) 318 | { 319 | drawable.SetBackground(self._getcolor(drawable)); 320 | } 321 | } 322 | 323 | class Line : Thing 324 | { 325 | var x; 326 | var y; 327 | var closed; 328 | function Line(string colorspec, int x0, int y0, int x1, int y1) 329 | { 330 | self.Thing(colorspec); 331 | int x[] = [ x0, x1 - x0 ]; 332 | int y[] = [ y0, y1 - y0 ]; 333 | self.x = x; 334 | self.y = y; 335 | self.closed = false; 336 | } 337 | function draw(drawable) 338 | { 339 | self.setforeground(drawable); 340 | var x = self.x; 341 | var y = self.y; 342 | int x0 = x[0]; 343 | int y0 = y[0]; 344 | for (int i = 1, n = elements(x); i < n; ++i) { 345 | int x1 = x0 + x[i]; 346 | int y1 = y0 + y[i]; 347 | drawable.DrawLine(x0, y0, x1, y1); 348 | x0 = x1; 349 | y0 = y1; 350 | } 351 | if (self.closed) 352 | drawable.DrawLine(x0, y0, x[0], y[0]); 353 | } 354 | function addsegment(int x1, int y1) 355 | { 356 | push(self.x, x1); 357 | push(self.y, y1); 358 | } 359 | function close() 360 | { 361 | self.closed =: true; 362 | } 363 | } 364 | 365 | class Poly : Line 366 | { 367 | function Poly(string colorspec, int x0, int y0, int x1, int y1) 368 | { 369 | self.Line(colorspec, x0, y0, x1, y1); 370 | } 371 | } 372 | 373 | class FillPoly : Poly 374 | { 375 | function FillPoly(string colorspec, int x0, int y0, int x1, int y1) 376 | { 377 | self.Poly(colorspec, x0, y0, x1, y1); 378 | } 379 | function draw(drawable) 380 | { 381 | self.setforeground(drawable); 382 | self.setbackground(drawable); 383 | drawable.FillPolygon(self.x, self.y); 384 | } 385 | function hint(drawable) 386 | { 387 | self.setforeground(drawable); 388 | drawable.SetFunction(GXinvert); 389 | drawable.DrawLines(self.x, self.y); 390 | drawable.SetFunction(GXcopy); 391 | } 392 | } 393 | 394 | class HandLine : Thing 395 | { 396 | var xcoord; 397 | var ycoord; 398 | function HandLine(string colorspec) 399 | { 400 | self.Thing(colorspec); 401 | int x[]; 402 | int y[]; 403 | self.xcoord = x; 404 | self.ycoord = y; 405 | } 406 | function push(int x, int y) 407 | { 408 | push(self.xcoord, x); 409 | push(self.ycoord, y); 410 | } 411 | function draw(drawable) 412 | { 413 | var x = self.xcoord; 414 | var y = self.ycoord; 415 | int n = elements(x) - 1; 416 | self.setforeground(drawable); 417 | if (n == 0) 418 | drawable.DrawPoint(x[0], y[0]); 419 | else { 420 | int x0 = x[0], y0 = y[0]; 421 | for (int i = 1; i < n; ++i) { 422 | int x1 = x0 + x[i], y1 = y0 + y[i]; 423 | drawable.DrawLine(x0, y0, x1, y1); 424 | x0 = x1; y0 = y1; 425 | } 426 | } 427 | } 428 | } 429 | 430 | class BaseRectangle : Thing 431 | { 432 | var x0; 433 | var y0; 434 | var x1; 435 | var y1; 436 | function BaseRectangle(string colorspec, int x0, int y0, int x1, int y1) 437 | { 438 | self.Thing(colorspec); 439 | if (x0 < x1) { 440 | self.x0 = x0; 441 | self.x1 = x1; 442 | } 443 | else { 444 | self.x0 = x1; 445 | self.x1 = x0; 446 | } 447 | if (y0 < y1) { 448 | self.y0 = y0; 449 | self.y1 = y1; 450 | } 451 | else { 452 | self.y0 = y1; 453 | self.y1 = y0; 454 | } 455 | } 456 | } 457 | 458 | class Rectangle : BaseRectangle 459 | { 460 | function Rectangle(string colorspec, int x0, int y0, int x1, int y1) 461 | { 462 | self.BaseRectangle(colorspec, x0, y0, x1, y1); 463 | } 464 | function draw(drawable) 465 | { 466 | self.setforeground(drawable); 467 | int x0 = self.x0; 468 | int x1 = self.x1; 469 | int y0 = self.y0; 470 | int y1 = self.y1; 471 | drawable.DrawRectangle(x0, y0, x1 - x0, y1 - y0); 472 | } 473 | } 474 | 475 | class FillRectangle : BaseRectangle 476 | { 477 | function FillRectangle(string colorspec, int x0, int y0, int x1, int y1) 478 | { 479 | self.BaseRectangle(colorspec, x0, y0, x1, y1); 480 | } 481 | function draw(drawable) 482 | { 483 | self.setforeground(drawable); 484 | int x0 = self.x0; 485 | int x1 = self.x1; 486 | int y0 = self.y0; 487 | int y1 = self.y1; 488 | drawable.FillRectangle(x0, y0, x1 - x0, y1 - y0); 489 | } 490 | } 491 | 492 | //********************************************************************** 493 | 494 | class Pizarra : TopLevelWindow 495 | { 496 | var width; 497 | var height; 498 | var yboard; 499 | var board; 500 | function Pizarra(controller) 501 | { 502 | var display = controller.display; 503 | string title = "pizarra"; 504 | int width = 600; 505 | int height = 400; 506 | self.width = width; 507 | self.height = height; 508 | self.TopLevelWindow(controller, title, 0, 0, width, height, 509 | { "background-color" : display.ParseColor("grey") } ); 510 | controller.created(self); 511 | self.SetWMProtocols(['WM_DELETE_WINDOW']); 512 | self.OnDestroy += function (event) 513 | { 514 | self.controller.destroyed(self); 515 | }; 516 | self.OnConfigure += evhandler(self, "onconfigure"); 517 | self.OnClientMessage += evhandler(self, "onclientmessage"); 518 | 519 | var colorsel = new ColorSelector(self, 4, 2); 520 | int yboard = colorsel.getwidth(); 521 | int ytoolset = colorsel.getheight() + 4; 522 | var toolsel = new ToolSelector(self, 4, ytoolset); 523 | int ybutton = ytoolset + toolsel.getheight() + 2; 524 | int ybaux = toolsel.getwidth(); 525 | if (yboard < ybaux) 526 | yboard = ybaux; 527 | var buttonclose = new TextButton(self, 4, ybutton, 0, 0, 528 | "close", null); 529 | ybaux = buttonclose.getwidth(); 530 | if (yboard < ybaux) 531 | yboard = ybaux; 532 | yboard += 4; 533 | self.yboard = yboard; 534 | 535 | self.board = new Board(self, yboard, 2, width - yboard - 2, height - 4); 536 | self.board.Map(); 537 | 538 | colorsel.MoveWindow((yboard - colorsel.getwidth()) / 2 , 2); 539 | toolsel.MoveWindow((yboard - toolsel.getwidth()) / 2 , ytoolset); 540 | buttonclose.MoveWindow((yboard - buttonclose.getwidth()) / 2, ybutton); 541 | 542 | buttonclose.OnClick += evhandler(self, "onclickclose"); 543 | buttonclose.Map(); 544 | } 545 | function onconfigure(event) 546 | { 547 | int nwidth = event.width(); 548 | int nheight = event.height(); 549 | var width = self.width; 550 | var height = self.height; 551 | if (width != nwidth || height != nheight) { 552 | if (self.board != null) 553 | self.board.ResizeWindow(nwidth - self.yboard - 2, nheight - 4); 554 | self.width = nwidth; 555 | self.height = nheight; 556 | } 557 | } 558 | function onclientmessage(event) 559 | { 560 | self.close(); 561 | } 562 | function onclickclose(event) 563 | { 564 | self.close(); 565 | } 566 | 567 | function newwindow() 568 | { 569 | self.controller.pushaction(function () 570 | { 571 | var np = new Pizarra(self.controller); 572 | np.Map(); 573 | } ); 574 | } 575 | function close() 576 | { 577 | self.controller.pushaction(method_fun(self, "Destroy")); 578 | } 579 | function setcolor(string spec) 580 | { 581 | self.board.setcolor(spec); 582 | } 583 | function setmode(int mode) 584 | { 585 | self.board.setmode(mode); 586 | } 587 | } 588 | 589 | //********************************************************************** 590 | 591 | class Board : ChildWindow 592 | { 593 | const int 594 | HANDLINE = 0, LINE = 1, 595 | RECTANGLE = 2, FILLRECT = 3, 596 | POLY = 4, FILLPOLY = 5; 597 | 598 | var parent; 599 | var mode; 600 | var listline; 601 | var line; 602 | var pressed; 603 | var initx; 604 | var inity; 605 | var oldx; 606 | var oldy; 607 | var colorspec; 608 | var hintcolor; 609 | var menu; 610 | var grid; 611 | function Board(parent, int x, int y, int width, int height) 612 | { 613 | self.parent = parent; 614 | self.mode = HANDLINE; 615 | self.listline = []; 616 | self.ChildWindow(parent, x, y, width, height); 617 | self.pressed = false; 618 | self.initx = 0; 619 | self.inity = 0; 620 | self.oldx = 0; 621 | self.oldy = 0; 622 | self.colorspec = "black"; 623 | self.hintcolor = self.display.ParseColor("black"); 624 | self.grid = 0; 625 | 626 | self.OnExpose += evhandler(self, "onexpose"); 627 | self.OnKeyPress += evhandler(self, "onkeypress"); 628 | self.OnButtonPress += evhandler(self, "onbuttonpress"); 629 | self.OnButtonRelease += evhandler(self, "onbuttonrelease"); 630 | self.OnMotion += evhandler(self, "onmotion"); 631 | 632 | var menu = new Menu(self.display, self.display.CreateFont("courier-12")); 633 | menu.push("new window", method_fun(self.parent, "newwindow")); 634 | menu.push("grid off", function () { self.setgrid(0); }); 635 | menu.push("grid 4", function () { self.setgrid(4); }); 636 | menu.push("grid 8", function () { self.setgrid(8); }); 637 | menu.push("grid 16", function () { self.setgrid(16); }); 638 | menu.push("close", method_fun(self.parent, "close")); 639 | self.menu = menu; 640 | } 641 | 642 | function onexpose(event) 643 | { 644 | for (var l in self.listline) 645 | l.draw(self); 646 | } 647 | function onkeypress(event) 648 | { 649 | int code = event.keycode(); 650 | var display = self.display; 651 | string key = display.KeysymToString(display.KeycodeToKeysym(code)); 652 | switch (key) { 653 | case "Escape": 654 | self.parent.close(); 655 | break; 656 | case "l": 657 | self.mode =: HANDLINE; 658 | break; 659 | case "r": 660 | self.mode =: RECTANGLE; 661 | break; 662 | case "f": 663 | self.mode =: FILLRECT; 664 | break; 665 | case "BackSpace": 666 | self.pressed =: false; 667 | if (self.line != null) 668 | self.line = null; 669 | if (elements(self.listline) > 0) 670 | self.listline.pop(); 671 | //TODO else beep, or something. 672 | self.ClearArea(0, 0, 0, 0, 1); 673 | break; 674 | case "Shift_L": 675 | case "Shift_R": 676 | int mode = self.mode; 677 | if (self.pressed && (mode == LINE || mode == POLY || mode == FILLPOLY)) { 678 | int initx = self.initx; 679 | int inity = self.inity; 680 | int oldx = self.oldx; 681 | int oldy = self.oldy; 682 | self.hintline(initx, inity, oldx, oldy); 683 | var l = self.line; 684 | if (l == null) { 685 | switch (mode) { 686 | case LINE: 687 | l = new Line(self.colorspec, initx, inity, oldx, oldy); 688 | break; 689 | case POLY: 690 | l = new Poly(self.colorspec, initx, inity, oldx, oldy); 691 | break; 692 | case FILLPOLY: 693 | l = new FillPoly(self.colorspec, initx, inity, oldx, oldy); 694 | break; 695 | } 696 | self.line = l; 697 | self.listline.push(l); 698 | } 699 | else { 700 | if (mode == FILLPOLY) 701 | l.hint(self); 702 | l.addsegment(oldx - initx, oldy - inity); 703 | } 704 | switch (mode) { 705 | case LINE: 706 | l.draw(self); 707 | break; 708 | case POLY: 709 | self.SetForeground(self.hintcolor); 710 | self.DrawLine(initx, inity, oldx, oldy); 711 | break; 712 | case FILLPOLY: 713 | l.hint(self); 714 | break; 715 | } 716 | self.initx =: oldx; 717 | self.inity =: oldy; 718 | self.oldx =: oldx; 719 | self.oldy =: oldy; 720 | } 721 | break; 722 | default: 723 | int sym = self.display.KeycodeToKeysym(code); 724 | say('Key name: ', self.display.KeysymToString(sym)); 725 | } 726 | } 727 | function onbuttonpress(event) 728 | { 729 | int button = event.button(); 730 | if (button == 3) { 731 | self.menu.activate_from(self, event); 732 | return; 733 | } 734 | self.pressed = button; 735 | int x = event.x(); 736 | int y = event.y(); 737 | int grid = self.grid; 738 | if (grid) { 739 | x += grid; 740 | x -= x % grid; 741 | y += grid; 742 | y -= y % grid; 743 | } 744 | self.initx =: x; 745 | self.inity =: y; 746 | self.oldx =: x; 747 | self.oldy =: y; 748 | } 749 | function onbuttonrelease(event) 750 | { 751 | if (! self.pressed) 752 | return; 753 | self.pressed = false; 754 | int initx = self.initx; 755 | int inity = self.inity; 756 | int oldx = self.oldx; 757 | int oldy = self.oldy; 758 | string colorspec = self.colorspec; 759 | switch (self.mode) { 760 | case RECTANGLE: 761 | case FILLRECT: 762 | self.hintrectangle(initx, inity, oldx, oldy); 763 | var r = self.mode == RECTANGLE ? 764 | new Rectangle(colorspec, initx, inity, oldx, oldy) : 765 | new FillRectangle(colorspec, initx, inity, oldx, oldy); 766 | self.listline.push(r); 767 | r.draw(self); 768 | break; 769 | case LINE: 770 | self.hintline(initx, inity, oldx, oldy); 771 | var l = self.line; 772 | if (l == null) { 773 | l = new Line(colorspec, initx, inity, oldx, oldy); 774 | self.listline.push(l); 775 | } 776 | else { 777 | if (event.state() & ShiftMask) 778 | l.close(); 779 | else 780 | l.addsegment(oldx - initx, oldy - inity); 781 | } 782 | l.draw(self); 783 | break; 784 | case POLY: 785 | self.hintline(initx, inity, oldx, oldy); 786 | var p = self.line; 787 | if (p == null) { 788 | p = new Poly(colorspec, initx, inity, oldx, oldy); 789 | self.listline.push(p); 790 | } 791 | else { 792 | p.addsegment(oldx - initx, oldy - inity); 793 | p.close(); 794 | } 795 | p.draw(self); 796 | break; 797 | case FILLPOLY: 798 | self.hintline(initx, inity, oldx, oldy); 799 | var fp = self.line; 800 | if (fp != null) { 801 | fp.hint(self); 802 | fp.addsegment(oldx - initx, oldy - inity); 803 | fp.close(); 804 | fp.draw(self); 805 | } 806 | break; 807 | } 808 | self.line = null; 809 | } 810 | function onmotion(event) 811 | { 812 | if (self.pressed) { 813 | int x = event.x(); 814 | int y = event.y(); 815 | int grid = self.grid; 816 | if (grid) { 817 | x += grid; 818 | x -= x % grid; 819 | y += grid; 820 | y -= y % grid; 821 | } 822 | int oldx = self.oldx; 823 | int oldy = self.oldy; 824 | if (x != oldx || y != oldy) { 825 | switch (self.mode) { 826 | case HANDLINE: 827 | var line = self.line; 828 | if (line == null) { 829 | string colorspec = self.colorspec; 830 | self.line = line = new HandLine(colorspec); 831 | self.listline.push(line); 832 | line.push(oldx, oldy); 833 | self.SetForeground(self.display.ParseColor(colorspec)); 834 | } 835 | line.push(x - oldx, y - oldy); 836 | self.DrawLine(oldx, oldy, x, y); 837 | break; 838 | case LINE: 839 | case POLY: 840 | case FILLPOLY: 841 | self.hintline(self.initx, self.inity, oldx, oldy); 842 | self.hintline(self.initx, self.inity, x, y); 843 | break; 844 | case RECTANGLE: 845 | case FILLRECT: 846 | self.hintrectangle(self.initx, self.inity, oldx, oldy); 847 | self.hintrectangle(self.initx, self.inity, x, y); 848 | break; 849 | } 850 | } 851 | self.oldx =: x; 852 | self.oldy =: y; 853 | } 854 | } 855 | 856 | function setgrid(int n) 857 | { 858 | self.grid =: n; 859 | } 860 | function hinton() 861 | { 862 | self.SetFunction(GXinvert); 863 | self.SetLineAttributes(0, LineOnOffDash, 0, 0); 864 | self.SetSubwindowMode(IncludeInferiors); 865 | } 866 | function hintoff() 867 | { 868 | self.SetFunction(GXcopy); 869 | self.SetLineAttributes(0, LineSolid, 0, 0); 870 | self.SetSubwindowMode(ClipByChildren); 871 | } 872 | function hintline(int x0, int y0, int x1, int y1) 873 | { 874 | self.hinton(); 875 | self.DrawLine(x0, y0, x1, y1); 876 | self.hintoff(); 877 | } 878 | function hintrectangle(int x0, int y0, int x1, int y1) 879 | { 880 | int x = x0; 881 | int y = y0; 882 | int width = x1 - x; 883 | int height = y1 - y; 884 | if (width && height) { 885 | if (x > x1) { 886 | x = x1; 887 | width = -width; 888 | } 889 | if (y > y1) { 890 | y = y1; 891 | height = -height; 892 | } 893 | self.hinton(); 894 | self.DrawRectangle(x, y, width, height); 895 | self.hintoff(); 896 | } 897 | } 898 | function opencolorsel(int x, int y) 899 | { 900 | var colorsel = new ColorSelector(self, x, y); 901 | } 902 | function setcolor(string spec) 903 | { 904 | self.colorspec = spec; 905 | } 906 | function setmode(int mode) 907 | { 908 | self.mode =: mode; 909 | } 910 | } 911 | 912 | //********************************************************************** 913 | 914 | class MyController : Controller 915 | { 916 | var counter; 917 | function MyController() 918 | { 919 | self.Controller(); 920 | self.counter = 0; 921 | } 922 | function created(pizarra) 923 | { 924 | self.counter++; 925 | } 926 | function destroyed(pizarra) 927 | { 928 | var counter = self.counter; 929 | if (--counter == 0) 930 | self.Quit(); 931 | } 932 | } 933 | 934 | //********************************************************************** 935 | 936 | function main(args) 937 | { 938 | int nargs = elements(args); 939 | var controller = new MyController(); 940 | 941 | int n = (nargs < 2) ? 1 : nargs - 1; 942 | for (int i = 0; i < n; ++i) { 943 | var pizarra = new Pizarra(controller); 944 | pizarra.Map(); 945 | } 946 | 947 | controller.MainLoop(); 948 | 949 | say('End'); 950 | controller.Close(); 951 | } 952 | 953 | // End. 954 | -------------------------------------------------------------------------------- /examples/pokedit.winxed: -------------------------------------------------------------------------------- 1 | #! winxed 2 | 3 | // pokedit - A text editor 4 | // (C) 2011 Julián Albo "NotFound" 5 | 6 | $include "Guitor.winxhead"; 7 | 8 | $include_const "hash_key_type.pasm"; 9 | 10 | $load "Guitor.pbc"; 11 | 12 | using namespace Guitor; 13 | using namespace Guitor.Events; 14 | 15 | //************************************************************** 16 | 17 | // Convenience functions 18 | 19 | // Build a event handler function from object and method name. 20 | // The method is assumed to take a event argument 21 | 22 | function eventhandler(object, string methodname) 23 | { 24 | var method = find_method(object, methodname); 25 | return function (event) 26 | { 27 | object.*method(event); 28 | }; 29 | } 30 | 31 | // Bind a object and a method given by name into a invokable 32 | 33 | function method_fun(object, string methodname) 34 | { 35 | var method = find_method(object, methodname); 36 | return function (args[slurpy]) 37 | { 38 | return object.*method(args:[flat]); 39 | }; 40 | } 41 | 42 | // Some common use atoms 43 | 44 | const string 45 | WM_PROTOCOLS_s = "WM_PROTOCOLS", 46 | WM_DELETE_WINDOW_s = "WM_DELETE_WINDOW", 47 | WM_TAKE_FOCUS_s = "WM_TAKE_FOCUS", 48 | NET_WM_WINDOW_TYPE_s = "_NET_WM_WINDOW_TYPE", 49 | NET_WM_WINDOW_TYPE_DIALOG_s = "_NET_WM_WINDOW_TYPE_DIALOG", 50 | UTF8_STRING_s = "UTF8_STRING", 51 | CLIPBOARD_s = "CLIPBOARD"; 52 | 53 | // Special keys 54 | const string 55 | CTRL_A = "\x{1}", 56 | CTRL_C = "\x{3}", 57 | CTRL_F = "\x{6}", 58 | CTRL_N = "\x{E}", 59 | CTRL_Q = "\x{11}", 60 | CTRL_S = "\x{13}", 61 | CTRL_V = "\x{16}", 62 | CTRL_X = "\x{18}"; 63 | 64 | //************************************************************** 65 | 66 | class SelectedText 67 | { 68 | var startline; 69 | var startpos; 70 | var endline; 71 | var endpos; 72 | var checked; 73 | function SelectedText(int line, int pos) 74 | { 75 | self.startline = line; 76 | self.endline = line; 77 | self.startpos = pos; 78 | self.endpos = pos; 79 | self.checked = 0; 80 | } 81 | function get() 82 | { 83 | return self.startline, self.startpos, self.endline, self.endpos; 84 | } 85 | function getordered() 86 | { 87 | int stline = self.startline; 88 | int endline = self.endline; 89 | int stpos = self.startpos; 90 | int endpos = self.endpos; 91 | if (stline < endline || (stline == endline && stpos <= endpos)) 92 | return stline, stpos, endline, endpos; 93 | else 94 | return endline, endpos, stline, stpos; 95 | } 96 | function isempty() 97 | { 98 | return self.startline == self.endline && self.startpos == self.endpos; 99 | } 100 | function check(line, pos) 101 | { 102 | int checked = 0; 103 | if (line == self.startline && pos == self.startpos) 104 | checked = 1; 105 | else if (line == self.endline && pos == self.endpos) 106 | checked = 2; 107 | self.checked =: checked; 108 | } 109 | function moveend(int line, int pos) 110 | { 111 | self.endline =: line; 112 | self.endpos =: pos; 113 | } 114 | function move(int line, int pos) 115 | { 116 | :(int stline, int stpos, int endline, int endpos) = self.get(); 117 | int checked; 118 | if (self.isempty()) { 119 | int stline = self.startline; 120 | if (line < stline || (line == stline && pos < stpos)) 121 | checked = 1; 122 | else 123 | checked = 2; 124 | } 125 | else 126 | checked = self.checked; 127 | switch (checked) { 128 | case 1: 129 | stline = line; 130 | stpos = pos; 131 | break; 132 | case 2: 133 | endline = line; 134 | endpos = pos; 135 | break; 136 | default: 137 | cry("WARNING: something wrong with selected text"); 138 | } 139 | if (checked != 0 && 140 | (stline > endline || (stline == endline && stpos > endpos))) { 141 | self.startline =: endline; 142 | self.endline =: stline; 143 | self.startpos =: endpos; 144 | self.endpos =: stpos; 145 | } 146 | else { 147 | self.startline =: stline; 148 | self.endline =: endline; 149 | self.startpos =: stpos; 150 | self.endpos =: endpos; 151 | } 152 | } 153 | } 154 | 155 | //************************************************************** 156 | 157 | class AlertWindow : DialogWindow 158 | { 159 | var text; 160 | var ascent; 161 | var lineheight; 162 | var height; 163 | var marginleft; 164 | function AlertWindow(parent, string message) 165 | { 166 | var controller = parent.controller; 167 | var display = controller.display; 168 | var text = split("\n", message); 169 | self.text = text; 170 | var font = parent.getdialogfont(); 171 | int ascent = font.getAscent(); 172 | int lineheight = ascent + font.getDescent(); 173 | int height = lineheight * elements(text); 174 | int width = 0; 175 | for (int i = 0, n = elements(text); i < n; ++i) { 176 | int w = font.getTextxOff(display, text[i]); 177 | if (w > width) 178 | width = w; 179 | } 180 | width += font.getTextxOff(display, "MMMM"); 181 | self.marginleft = int(font.getTextxOff(display, "MM")); 182 | self.ascent = ascent; 183 | self.lineheight = lineheight; 184 | self.height = height; 185 | self.DialogWindow(parent, "Pokedit alert", 186 | 0, 0, width, height + lineheight * 3); 187 | var fgcolor = parent.display.ParseColor("black"); 188 | self.SetForeground(fgcolor); 189 | var bgcolor = parent.display.ParseColor("white"); 190 | self.SetBackground(bgcolor); 191 | var button = new TextButton(self, 0, 0, 0, 0, "Ok", font); 192 | int bwidth = button.getwidth(); 193 | button.OnClick += function () { self.Destroy(); }; 194 | button.MoveWindow((width - bwidth) / 2, height + lineheight); 195 | button.Map(); 196 | 197 | self.SetFont(font); 198 | self.SetWMProtocols([ WM_DELETE_WINDOW_s ]); 199 | self.OnClientMessage += eventhandler(self, "onclientmessage"); 200 | self.OnExpose += eventhandler(self, "onexpose"); 201 | self.OnKeyPress += eventhandler(self, "onkeypress"); 202 | } 203 | function setfocus(int revert) 204 | { 205 | self.SetInputFocus(revert); 206 | } 207 | function onclientmessage(event) 208 | { 209 | self.Destroy(); 210 | } 211 | function onexpose(event) 212 | { 213 | var text = self.text; 214 | int ascent = self.ascent; 215 | int lineheight = self.lineheight; 216 | int marginleft = self.marginleft; 217 | for (int i = 0, n = elements(text); i < n; ++i) 218 | self.DrawImageString(marginleft, i * lineheight + ascent, text[i]); 219 | } 220 | function onkeypress(event) 221 | { 222 | string key = self.LookupString(event); 223 | switch (key) { 224 | case "\r": 225 | case "\n": 226 | case "\e": 227 | self.Destroy(); 228 | default: 229 | ; // Nothing 230 | } 231 | } 232 | } 233 | 234 | //************************************************************** 235 | 236 | class FindTool : DialogWindow 237 | { 238 | var parent; 239 | var ascent; 240 | var lineheight; 241 | var margin; 242 | var edit; 243 | var buttonfind; 244 | var buttonclose; 245 | function FindTool(parent) 246 | { 247 | self.parent = parent; 248 | var font = parent.getdialogfont(); 249 | int ascent = font.getAscent(); 250 | int lineheight = ascent + font.getDescent(); 251 | self.ascent = ascent; 252 | self.lineheight = lineheight; 253 | int width = 400; 254 | int height = lineheight * 4; 255 | self.DialogWindow(parent, "Find - Pokedit", 256 | 0, 0, width, height); 257 | self.SetFont(font); 258 | int margin = self.getTextxOff("M"); 259 | self.margin = margin; 260 | 261 | var edit = new EditBox(self, margin, lineheight + 2, width - margin * 2, 0, font); 262 | self.edit = edit; 263 | 264 | var buttonfind = new TextButton(self, margin, lineheight * 2 + 8, 265 | 0, 0, "Find", font); 266 | int bwidth = buttonfind.getwidth(); 267 | buttonfind.OnClick += method_fun(self, "find"); 268 | self.buttonfind = buttonfind; 269 | 270 | var buttonclose = new TextButton(self, 271 | margin * 2 + bwidth, lineheight * 2 + 8, 272 | 0, 0, "Close", font); 273 | buttonclose.OnClick += method_fun(self, "close"); 274 | self.buttonclose = buttonclose; 275 | 276 | edit.Map(); 277 | buttonfind.Map(); 278 | buttonclose.Map(); 279 | 280 | self.SetWMProtocols([ WM_DELETE_WINDOW_s ]); 281 | self.OnClientMessage += function (event) { self.close(); }; 282 | self.OnExpose += eventhandler(self, "onexpose"); 283 | self.OnFocusIn += eventhandler(self, "onfocusin"); 284 | 285 | edit.OnKeyPress += eventhandler(self, "onkeypress"); 286 | } 287 | function onexpose(event) 288 | { 289 | int ascent = self.ascent; 290 | self.DrawImageString(self.margin, ascent, "Find text"); 291 | } 292 | function onkeypress(event) 293 | { 294 | string key = self.LookupString(event); 295 | switch (key) { 296 | case "\r": 297 | case "\n": 298 | self.find(event); 299 | break; 300 | case "\e": 301 | self.close(event); 302 | break; 303 | default: 304 | ; // Nothing 305 | } 306 | } 307 | function onfocusin(event) 308 | { 309 | self.setfocus(self.parent.getDID()); 310 | } 311 | function setfocus(int revert) 312 | { 313 | if (self.edit != null) 314 | self.edit.SetInputFocus(revert); 315 | } 316 | function find(event) 317 | { 318 | string text = self.edit.getValue(); 319 | int r = self.parent.findtext(text); 320 | } 321 | function close(event[optional]) 322 | { 323 | if (self.edit != null) { 324 | self.edit.Destroy(); 325 | self.edit = null; 326 | } 327 | if (self.buttonfind != null) { 328 | self.buttonfind.Destroy(); 329 | self.buttonfind = null; 330 | } 331 | if (self.buttonclose != null) { 332 | self.buttonclose.Destroy(); 333 | self.buttonclose = null; 334 | } 335 | self.Destroy(); 336 | } 337 | } 338 | 339 | //************************************************************** 340 | 341 | class SaveasWindow : ChildWindow 342 | { 343 | var parent; 344 | var font; 345 | var height; 346 | var edit; 347 | var bok; 348 | var bcancel; 349 | function SaveasWindow(parent, int width) 350 | { 351 | var font = parent.getstatusfont(); 352 | self.parent = parent; 353 | self.font = font; 354 | int height = 24; 355 | self.height = height; 356 | var bgcolor = parent.display.ParseColor("RGB:A/A/A"); 357 | self.ChildWindow(parent, 0, 0, parent.width, height, 358 | { "background-color" : bgcolor } ); 359 | self.SetBackground(bgcolor); 360 | int editxpos = font.getTextxOff(self.display, "Save as "); 361 | 362 | var bok = new TextButton(self, 0, 0, 0, 0, "Ok", font); 363 | int bokwidth = bok.getwidth(); 364 | int bheight = bok.getheight(); 365 | bok.MoveResizeWindow(width - bokwidth - 2, (height - bheight) / 2 + 1, 366 | bokwidth, bheight); 367 | self.bok = bok; 368 | var bcancel = new TextButton(self, 0, 0, 0, 0, "cancel", font); 369 | int bcancelwidth = bcancel.getwidth(); 370 | bcancel.MoveResizeWindow(width - bcancelwidth - bokwidth - 4, 371 | (height - bheight) / 2 + 1, 372 | bcancelwidth, bheight); 373 | self.bcancel = bcancel; 374 | 375 | int editwidth = width - editxpos - bokwidth - bcancelwidth - 6; 376 | var edit = new EditBox(self, editxpos, 2, editwidth, 0, font); 377 | self.edit = edit; 378 | int eheight = edit.getheight(); 379 | edit.MoveWindow(editxpos, (height - eheight) / 2 + 1); 380 | 381 | self.height = 4 + eheight; 382 | 383 | self.OnExpose += eventhandler(self, "onexpose"); 384 | edit.OnKeyPress += eventhandler(self, "oneditkeypress"); 385 | bok.OnClick += eventhandler(self, "doit"); 386 | bcancel.OnClick += eventhandler(self, "cancel"); 387 | 388 | edit.Map(); 389 | bok.Map(); 390 | bcancel.Map(); 391 | } 392 | function close() 393 | { 394 | var bok = self.bok; 395 | if (bok != null) { 396 | self.bok = null; 397 | bok.Destroy(); 398 | } 399 | var bcancel = self.bcancel; 400 | if (bcancel != null) { 401 | self.bcancel = null; 402 | bcancel.Destroy(); 403 | } 404 | var edit = self.edit; 405 | if (edit != null) { 406 | self.edit = null; 407 | edit.Destroy(); 408 | } 409 | self.Destroy(); 410 | } 411 | function getheight() 412 | { 413 | return int(self.height); 414 | } 415 | function setfocus(int revert) 416 | { 417 | var edit = self.edit; 418 | if (edit != null) 419 | self.edit.SetInputFocus(revert); 420 | } 421 | function doit(event [optional]) 422 | { 423 | self.parent.savetofile(self.edit.getValue()); 424 | self.parent.closedialog(); 425 | } 426 | function cancel(event [optional]) 427 | { 428 | self.parent.closedialog(); 429 | } 430 | function onexpose(event) 431 | { 432 | self.SetFont(self.font); 433 | self.DrawImageString(2, 18, "Save as"); 434 | } 435 | function oneditkeypress(event) 436 | { 437 | switch (event.keyname()) { 438 | case "Escape": 439 | self.cancel(); 440 | break; 441 | case "Return": 442 | self.doit(); 443 | break; 444 | } 445 | } 446 | } 447 | 448 | //************************************************************** 449 | 450 | class StatusWindow : ChildWindow 451 | { 452 | var parent; 453 | var ascent; 454 | var descent; 455 | var fgcolor; 456 | var bgcolor; 457 | var height; 458 | var nwidth; 459 | function StatusWindow(parent, int x, int y, int width, int height) 460 | { 461 | var font = parent.getstatusfont(); 462 | self.parent = parent; 463 | self.fgcolor = parent.display.ParseColor("grey50"); 464 | self.bgcolor = parent.display.ParseColor("grey95"); 465 | int ascent = font.getAscent(); 466 | int descent = font.getDescent(); 467 | height = ascent + descent; 468 | self.ascent = ascent; 469 | self.descent = descent; 470 | self.height = height; 471 | self.ChildWindow(parent, x, y, width, height, 472 | { "background-color": self.bgcolor } ); 473 | self.SetForeground(self.fgcolor); 474 | self.SetBackground(self.bgcolor); 475 | self.SetFont(font); 476 | self.nwidth = int(self.getTextxOff("MMMM")); 477 | self.OnExpose += eventhandler(self, "onexpose"); 478 | } 479 | function getheight() 480 | { 481 | return int(self.height); 482 | } 483 | function onexpose(event) 484 | { 485 | self.updatepos(); 486 | } 487 | function updatepos() 488 | { 489 | var tw = self.parent.textwindow; 490 | int curpos = tw.curpos + 1; 491 | int curline = tw.curline + 1; 492 | int nwidth = self.nwidth; 493 | int ascent = self.ascent; 494 | int descent = self.descent; 495 | self.SetForeground(self.bgcolor); 496 | self.FillRectangle(0, 0, nwidth * 3, ascent + descent); 497 | self.SetForeground(self.fgcolor); 498 | self.DrawString(0, ascent, curpos); 499 | self.DrawString(nwidth * 2, ascent, curline); 500 | } 501 | } 502 | 503 | //************************************************************** 504 | 505 | class TextWindow : ChildWindow 506 | { 507 | const int MARGINSUP = 4; 508 | const int MARGINLEFT = 2; 509 | var parent; 510 | var textfont; 511 | var fgcolor; 512 | var bgcolor; 513 | var width; 514 | var height; 515 | var lineheight; 516 | var ascent; 517 | var text; 518 | var headline; 519 | var maxlines; 520 | var xoff; 521 | var curline; 522 | var curpos; 523 | var has_focus; 524 | var selected; 525 | var copybuffer; 526 | var pressed; 527 | 528 | function TextWindow(parent, int x, int y, int width, int height) 529 | { 530 | self.parent = parent; 531 | string text[]; 532 | self.text = text; 533 | var font = parent.gettextfont(); 534 | self.textfont = font; 535 | self.width = width; 536 | self.height = height; 537 | int ascent = font.getAscent(); 538 | int descent = font.getDescent(); 539 | int lineheight = ascent + descent; 540 | self.lineheight = lineheight; 541 | self.ascent = ascent; 542 | self.headline = 0; 543 | self.maxlines = int((height - MARGINSUP) / lineheight); 544 | self.xoff = MARGINLEFT; 545 | self.curline = 0; 546 | self.curpos = 0; 547 | self.has_focus = false; 548 | self.pressed = false; 549 | self.ChildWindow(parent, x, y, width, height); 550 | self.SetFont(font); 551 | self.fgcolor = self.display.ParseColor("black"); 552 | self.bgcolor = self.display.ParseColor("white"); 553 | self.SetForeground(self.fgcolor); 554 | self.SetBackground(self.bgcolor); 555 | 556 | self.OnDestroy += eventhandler(self, "ondestroy"); 557 | self.OnConfigure += eventhandler(self, "onconfigure"); 558 | self.OnExpose += eventhandler(self, "onexpose"); 559 | self.OnFocusIn += eventhandler(self, "onfocusin"); 560 | self.OnFocusOut += eventhandler(self, "onfocusout"); 561 | self.OnKeyPress += eventhandler(self, "onkeypress"); 562 | self.OnButtonPress += eventhandler(self, "onbuttonpress"); 563 | self.OnButtonRelease += eventhandler(self, "onbuttonrelease"); 564 | self.OnMotion += eventhandler(self, "onmotion"); 565 | self.OnSelectionClear += eventhandler(self, "onselectionclear"); 566 | self.OnSelectionRequest += eventhandler(self, "onselectionrequest"); 567 | self.OnSelectionNotify += eventhandler(self, "onselectionnotify"); 568 | } 569 | function ondestroy(event) 570 | { 571 | self.text = null; 572 | self.parent.close(); 573 | } 574 | function onconfigure(event) 575 | { 576 | int width = event.width(); 577 | int height = event.height(); 578 | self.width =: width; 579 | self.height =: height; 580 | int lineheight = self.lineheight; 581 | self.maxlines =: int((height - MARGINSUP) / lineheight); 582 | if (self.text != null) { 583 | self.adjust(); 584 | self.checkxoff(); 585 | } 586 | } 587 | function onexpose(event) 588 | { 589 | if (self.text != null) { 590 | self.drawall(); 591 | self.invertselection(); 592 | self.cursor(); 593 | } 594 | } 595 | function onfocusin(event) 596 | { 597 | if (self.text == null) 598 | return; 599 | int detail = event.detail(); 600 | self.has_focus =: true; 601 | self.cursor(); 602 | } 603 | function onfocusout(event) 604 | { 605 | if (self.text == null) 606 | return; 607 | int detail = event.detail(); 608 | self.cursor(); 609 | self.has_focus =: false; 610 | } 611 | function onkeypress(event) 612 | { 613 | var text = self.text; 614 | int headline = self.headline; 615 | int curline = self.curline; 616 | int curpos = self.curpos; 617 | int l; 618 | string key = event.keyname(); 619 | self.cursor(); 620 | 621 | int drawall = false; 622 | int shifted = (event.state() & ShiftMask) != 0; 623 | if (shifted) 624 | self.checkselected(curline, curpos); 625 | switch (key) { 626 | case "Prior": 627 | if (! shifted) 628 | self.cancelselected(); 629 | if (curline > 0) { 630 | l = self.maxlines - 1; 631 | curline -= l; 632 | if (curline < 0) 633 | curline = 0; 634 | self.curline =: curline; 635 | if (headline > 0) { 636 | headline -= l; 637 | if (headline < 0) 638 | headline = 0; 639 | self.headline =: headline; 640 | drawall = true; 641 | } 642 | } 643 | break; 644 | case "Next": 645 | if (! shifted) 646 | self.cancelselected(); 647 | int nlines = elements(text); 648 | if (curline < nlines) { 649 | l = self.maxlines - 1; 650 | curline += l; 651 | if (curline > nlines) 652 | curline = nlines; 653 | self.curline =: curline; 654 | if (headline < nlines) { 655 | headline += l; 656 | if (headline > nlines) 657 | headline = nlines; 658 | self.headline =: headline; 659 | drawall = true; 660 | } 661 | } 662 | break; 663 | case "Up": 664 | if (! shifted) 665 | self.cancelselected(); 666 | if (curline > 0) 667 | if (self.moveup()) 668 | drawall = true; 669 | if (self.checkxoff()) 670 | drawall = true; 671 | break; 672 | case "Down": 673 | if (! shifted) 674 | self.cancelselected(); 675 | if (curline < elements(text)) 676 | if (self.movedown()) 677 | drawall = true; 678 | if (self.checkxoff()) 679 | drawall = true; 680 | break; 681 | case "Home": 682 | if (! shifted) 683 | self.cancelselected(); 684 | curpos = 0; 685 | self.curpos =: curpos; 686 | if (event.state() & ControlMask) { 687 | self.curline =: 0; 688 | self.headline =: 0; 689 | drawall = true; 690 | } 691 | if (self.checkxoff()) 692 | drawall = true; 693 | break; 694 | case "End": 695 | if (! shifted) 696 | self.cancelselected(); 697 | if (event.state() & ControlMask) { 698 | self.curpos =: 0; 699 | l = elements(text); 700 | self.curline =: l; 701 | l = l - self.maxlines + 1; 702 | if (l < 0) 703 | l = 0; 704 | if (l > headline) { 705 | self.headline =: l; 706 | drawall = true; 707 | } 708 | } 709 | else { 710 | curpos = length(text[curline]); 711 | self.curpos =: curpos; 712 | } 713 | if (self.checkxoff()) 714 | drawall = true; 715 | break; 716 | case "Left": 717 | if (! shifted) 718 | self.cancelselected(); 719 | l = length(text[curline]); 720 | if (curpos > l) 721 | self.curpos =: curpos = l; 722 | if (curpos == 0) { 723 | if (curline == 0) 724 | break; 725 | if (self.moveup()) 726 | drawall = true; 727 | curline = self.curline; 728 | curpos = length(text[curline]); 729 | } 730 | else { 731 | --curpos; 732 | } 733 | self.curpos =: curpos; 734 | if (self.checkxoff()) 735 | drawall = true; 736 | break; 737 | case "Right": 738 | if (! shifted) 739 | self.cancelselected(); 740 | int maxpos = length(text[curline]); 741 | if (++curpos > maxpos) { 742 | if (curline >= elements(text)) 743 | break; 744 | if (self.movedown()) 745 | drawall = true; 746 | curpos = 0; 747 | } 748 | self.curpos =: curpos; 749 | if (self.checkxoff()) 750 | drawall = true; 751 | break; 752 | case "BackSpace": 753 | if (self.someselected()) { 754 | self.deleteselected(); 755 | drawall = true; 756 | break; 757 | } 758 | l = length(text[curline]); 759 | if (curpos > l) 760 | self.curpos =: curpos = l; 761 | if (curpos > 0) { 762 | string line = text[curline]; 763 | if (substr(line, 0, curpos) == " " * curpos) { 764 | if (curpos < 4) { 765 | } 766 | else { 767 | line = substr(line, 4); 768 | curpos -= 4; 769 | } 770 | } 771 | else { 772 | --curpos; 773 | line = substr(line, 0, curpos) + substr(line, curpos + 1); 774 | } 775 | self.curpos =: curpos; 776 | text[curline] = line; 777 | self.drawline(curline); 778 | } 779 | else if (curline > 0) { 780 | if (curline < elements(text)) { 781 | string line = text[curline]; 782 | delete text[curline]; 783 | string prevline = text[curline - 1]; 784 | curpos = length(prevline); 785 | line = prevline + line; 786 | text[curline - 1] = line; 787 | } 788 | else 789 | curpos = length(text[curline - 1]); 790 | --curline; 791 | self.curline =: curline; 792 | self.curpos =: curpos; 793 | drawall = true; 794 | } 795 | break; 796 | case "Delete": 797 | if (self.someselected()) { 798 | self.deleteselected(); 799 | drawall = true; 800 | break; 801 | } 802 | l = length(text[curline]); 803 | if (curpos > l) 804 | self.curpos =: curpos = l; 805 | if (curpos < l) { 806 | string line = text[curline]; 807 | line = substr(line, 0, curpos) + substr(line, curpos + 1); 808 | text[curline] = line; 809 | self.drawline(curline); 810 | } 811 | else if (curline < elements(text)) { 812 | string line = text[curline + 1]; 813 | delete text[curline + 1]; 814 | string prevline = text[curline]; 815 | curpos = length(prevline); 816 | line = prevline + line; 817 | text[curline] = line; 818 | self.curpos =: curpos; 819 | drawall = true; 820 | } 821 | break; 822 | default: 823 | key = self.LookupString(event); 824 | if (key == null || length(key) == 0) 825 | break; 826 | string line = text[curline]; 827 | l = length(line); 828 | switch (key) { 829 | case "\r": 830 | self.cancelselected(); 831 | if (curpos > l) 832 | curpos = l; 833 | string newline = substr(line, curpos); 834 | int ind; 835 | for (ind = 0; ind < curpos && line[ind] == ' '; ++ind) 836 | ; 837 | line = substr(line, 0, curpos); 838 | for (int i = elements(text); i > curline; --i) 839 | text[i] = text[i - 1]; 840 | text[curline] = line; 841 | if (ind) 842 | newline = " " * ind + newline; 843 | text[curline + 1] = newline; 844 | self.curpos =: ind; 845 | if (! self.movedown()) 846 | self.drawlines(curline, 0); 847 | break; 848 | case CTRL_A: 849 | self.selectall(event.time()); 850 | return; 851 | case CTRL_N: 852 | self.parent.new(); 853 | return; 854 | case CTRL_Q: 855 | self.parent.close(); 856 | return; 857 | case CTRL_S: 858 | self.parent.save(); 859 | return; 860 | case CTRL_C: 861 | self.copyselected(event.time()); 862 | break; 863 | case CTRL_F: 864 | self.parent.find(); 865 | break; 866 | case CTRL_X: 867 | self.cutselected(event.time()); 868 | return; 869 | case CTRL_V: 870 | if (self.someselected()) 871 | self.cancelselected(); 872 | self.paste(event.time()); 873 | break; 874 | case "\t": 875 | // Cheap trick 876 | if (curpos > l) 877 | curpos = l; 878 | key = " " * (4 - (curpos % 4)); 879 | default: 880 | self.cancelselected(); 881 | if (ord(key) < ord(" ")) 882 | break; 883 | if (self.someselected()) 884 | self.cancelselected(); 885 | if (curpos > l) 886 | curpos = l; 887 | line = substr(line, 0, curpos) + key + substr(line, curpos); 888 | curpos += length(key); 889 | text[curline] = line; 890 | self.curpos =: curpos; 891 | self.drawline(curline); 892 | } 893 | } 894 | if (drawall) 895 | self.drawall(); 896 | if (shifted) 897 | self.moveselected(); 898 | self.parent.updatepos(); 899 | self.cursor(); 900 | } 901 | function onbuttonpress(event) 902 | { 903 | if (self.parent.waiting()) 904 | return; 905 | int curpos, curline; 906 | switch (event.button()) { 907 | case 1: 908 | self.cursor(); 909 | :(curpos, curline) = self.gettextpos(event.x(), event.y()); 910 | self.cancelselected(); 911 | self.selected = new SelectedText(curline, curpos); 912 | self.pressed =: 1; 913 | self.curpos =: curpos; 914 | self.curline =: curline; 915 | self.parent.updatepos(); 916 | self.cursor(); 917 | break; 918 | case 2: 919 | // Paste primary selection 920 | self.cursor(); 921 | :(curpos, curline) = self.gettextpos(event.x(), event.y()); 922 | self.curpos =: curpos; 923 | self.curline =: curline; 924 | self.parent.updatepos(); 925 | self.cursor(); 926 | self.paste_selection(XA_PRIMARY, event.time()); 927 | break; 928 | case 4: 929 | if (self.up()) { 930 | self.cursor(); 931 | self.invertselection(); 932 | self.drawall(); 933 | self.invertselection(); 934 | self.cursor(); 935 | } 936 | break; 937 | case 5: 938 | if (self.down()) { 939 | self.cursor(); 940 | self.invertselection(); 941 | self.drawall(); 942 | self.invertselection(); 943 | self.cursor(); 944 | } 945 | break; 946 | } 947 | } 948 | function onbuttonrelease(event) 949 | { 950 | int pressed = self.pressed; 951 | self.pressed =: 0; 952 | var selected = self.selected; 953 | switch (pressed) { 954 | case 1: 955 | if (selected != null) { 956 | if (selected.isempty()) 957 | self.selected = null; 958 | else 959 | self.SetSelectionOwner(XA_PRIMARY, event.time()); 960 | } 961 | break; 962 | } 963 | } 964 | function onmotion(event) 965 | { 966 | if (self.text == null) 967 | return; 968 | if (self.pressed == 1) 969 | { 970 | self.cursor(); 971 | int x = event.x(); 972 | int y = event.y(); 973 | :(int pos, int l) = self.gettextpos(x, y); 974 | self.invertselection(); 975 | self.selected.moveend(l, pos); 976 | int headline = self.headline; 977 | int lineheight = self.lineheight; 978 | int maxlines = self.maxlines; 979 | if (l >= headline + maxlines) { 980 | int desp = l - headline - maxlines + 1; 981 | int ny = y - desp * lineheight; 982 | self.display.WarpPointer(self.getDID(), x, ny); 983 | self.headline = headline + desp; 984 | self.drawall(); 985 | } 986 | else if (l < headline) { 987 | int desp = headline - l; 988 | int ny = y + desp * lineheight; 989 | self.display.WarpPointer(self.getDID(), x, ny); 990 | self.headline = headline - desp; 991 | self.drawall(); 992 | } 993 | self.curpos =: pos; 994 | self.curline =: l; 995 | self.invertselection(); 996 | self.parent.updatepos(); 997 | self.cursor(); 998 | } 999 | } 1000 | function getline(int y) 1001 | { 1002 | // Get the text line at the y coordninate 1003 | var text = self.text; 1004 | int nlines = elements(text); 1005 | int headline = self.headline; 1006 | int lineheight = self.lineheight; 1007 | int l = (y - MARGINSUP) / lineheight + headline; 1008 | if (l < 0) 1009 | l = 0; 1010 | if (l > nlines) 1011 | l = nlines; 1012 | return l; 1013 | } 1014 | function getpos(int x, int nline) 1015 | { 1016 | // Get the chcaracet position at the x coordinate 1017 | x -= self.xoff; 1018 | if (x < 0) 1019 | return 0; 1020 | var text = self.text; 1021 | string line = text[nline]; 1022 | int rp = length(line); 1023 | if (rp == 0) 1024 | return 0; 1025 | if (x > self.getTextxOff(line)) 1026 | return rp; 1027 | int lp = 0; 1028 | int mp; 1029 | while ((mp = (lp + rp) / 2) != lp) { 1030 | if (x < self.getTextxOff(substr(line, 0, mp))) 1031 | rp = mp; 1032 | else 1033 | lp = mp; 1034 | } 1035 | return x < ((self.getTextxOff(substr(line, 0, mp)) + 1036 | self.getTextxOff(substr(line, 0, mp + 1))) / 2) ? 1037 | mp : mp + 1; 1038 | } 1039 | function gettextpos(int x, int y) 1040 | { 1041 | int l = self.getline(y); 1042 | int pos = l < elements(self.text) ? self.getpos(x, l) : 0; 1043 | return pos, l; 1044 | } 1045 | function insert(string newtext) 1046 | { 1047 | if (newtext == null || length(newtext) == 0) 1048 | return; 1049 | self.cursor(); 1050 | self.invertselection(); 1051 | int curline = self.curline; 1052 | int curpos = self.curpos; 1053 | var text = self.text; 1054 | string line = text[curline]; 1055 | int l = length(line); 1056 | if (curpos > l) 1057 | curpos = l; 1058 | int pos = indexof(newtext, "\n"); 1059 | if (pos < 0) { 1060 | line = substr(line, 0, curpos) + newtext + substr(line, curpos); 1061 | curpos += length(newtext); 1062 | text[curline] = line; 1063 | self.curpos =: curpos; 1064 | if (self.checkxoff()) 1065 | self.drawall(); 1066 | else 1067 | self.drawline(curline); 1068 | } 1069 | else { 1070 | int fpos = pos; 1071 | string plines[]; 1072 | int npos; 1073 | while ((npos = indexof(newtext, "\n", pos + 1)) >= 0) { 1074 | string l = substr(newtext, pos + 1, npos - pos - 1); 1075 | push(plines, l); 1076 | pos = npos; 1077 | } 1078 | int nplines = elements(plines); 1079 | string firstline = substr(line, 0, curpos) + 1080 | substr(newtext, 0, fpos); 1081 | string lastline = substr(newtext, pos + 1); 1082 | self.curpos =: length(lastline); 1083 | lastline += substr(line, curpos); 1084 | for (int i = elements(text); i > curline; --i) 1085 | text[i + nplines + 1] = text[i]; 1086 | for (int i = 0; i < nplines; ++i) 1087 | text[curline + i + 1] = plines[i]; 1088 | text[curline] = firstline; 1089 | text[curline + nplines + 1] = lastline; 1090 | int oldcurline = curline; 1091 | self.curline =: curline + nplines + 1; 1092 | if (self.adjust() || self.checkxoff()) 1093 | self.drawall(); 1094 | else 1095 | self.drawlines(oldcurline, 0); 1096 | } 1097 | self.parent.updatepos(); 1098 | self.invertselection(); 1099 | self.cursor(); 1100 | } 1101 | function onselectionclear(event) 1102 | { 1103 | int selection = event.selection(); 1104 | if (selection != XA_PRIMARY) 1105 | return; 1106 | self.cancelselected(); 1107 | } 1108 | function onselectionrequest(event) 1109 | { 1110 | int requestor = event.requestor(); 1111 | int selection = event.selection(); 1112 | int target = event.target(); 1113 | int property = event.property(); 1114 | var display = self.display; 1115 | 1116 | string targetname = self.GetAtomName(target); 1117 | int typeutf8 = self.InternAtom(UTF8_STRING_s); 1118 | // Request for supported types: answer only utf8 text. 1119 | if (targetname == "TARGETS") { 1120 | display.ChangePropertyInt32(requestor, 1121 | property, target, PropModeReplace, typeutf8); 1122 | } 1123 | else if (target == typeutf8 || target == XA_STRING) { 1124 | // Request for text: fine, do it. 1125 | string textsel; 1126 | if (selection == XA_PRIMARY) 1127 | textsel = self.getselectedtext(); 1128 | else { 1129 | // Assume CLIPBOARD 1130 | var copybuffer = self.copybuffer; 1131 | textsel = copybuffer == null ? "" : copybuffer; 1132 | } 1133 | // Some clients can request STRING without checking. 1134 | // Try to transcode in that case. 1135 | if (target == XA_STRING) { 1136 | try { 1137 | textsel = trans_encoding(textsel, "iso-8859-1"); 1138 | display.ChangePropertyStringIso(requestor, 1139 | property, target, PropModeReplace, textsel); 1140 | } 1141 | catch () { } 1142 | } 1143 | else 1144 | display.ChangePropertyString(requestor, 1145 | property, target, PropModeReplace, textsel); 1146 | } 1147 | else 1148 | return; 1149 | 1150 | var notify = new Event(SelectionNotify); 1151 | // No much support for creating events yet, use the 1152 | // raw StructView for a now. 1153 | var data = notify.eventdata; 1154 | var view = notify.getview(); 1155 | view[data, 4] = requestor; 1156 | view[data, 5] = selection; 1157 | view[data, 6] = target; 1158 | view[data, 7] = property; 1159 | view[data, 8] = event.time(); 1160 | display.SendEvent(requestor, false, 0, notify); 1161 | } 1162 | function onselectionnotify(event) 1163 | { 1164 | int selection = event.selection(); 1165 | int target = event.target(); 1166 | int property = event.property(); 1167 | if (property == None) { 1168 | if (target == self.InternAtom(UTF8_STRING_s)) { 1169 | // Retry with plain string type 1170 | self.ConvertSelection(selection, XA_STRING, 1171 | selection, event.time()); 1172 | } 1173 | return; 1174 | } 1175 | string pasted; 1176 | if (target == XA_STRING) 1177 | pasted = self.GetPropertyString(property); 1178 | else 1179 | pasted = self.GetPropertyUtf8String(property); 1180 | if (pasted == null) 1181 | return; 1182 | self.insert(pasted); 1183 | } 1184 | function getselectedtext() 1185 | { 1186 | var selected = self.selected; 1187 | if (selected == null || selected.isempty()) 1188 | return ""; 1189 | :(int stline, int stpos, int endline, int endpos) = 1190 | selected.getordered(); 1191 | var text = self.text; 1192 | string firstline = text[stline]; 1193 | string result; 1194 | if (stline == endline) 1195 | result = substr(firstline, stpos, endpos - stpos); 1196 | else { 1197 | result = substr(firstline, stpos); 1198 | for (int l = stline + 1; l < endline; ++l) { 1199 | result += "\n"; 1200 | result += string(text[l]); 1201 | } 1202 | result += "\n"; 1203 | result += substr(text[endline], 0, endpos); 1204 | } 1205 | return result; 1206 | } 1207 | function someselected() 1208 | { 1209 | var selected = self.selected; 1210 | return selected != null && ! selected.isempty(); 1211 | } 1212 | function deleteselected() 1213 | { 1214 | var selected = self.selected; 1215 | if (selected == null || selected.isempty()) 1216 | return; 1217 | :(int stline, int stpos, int endline, int endpos) = 1218 | selected.getordered(); 1219 | var text = self.text; 1220 | string firstline = text[stline]; 1221 | string lastline = text[endline]; 1222 | string line = substr(firstline, 0, stpos) + substr(lastline, endpos); 1223 | text[stline] = line; 1224 | for (int i = 0; i < endline - stline; ++i) 1225 | delete text[stline + 1]; 1226 | self.selected = null; 1227 | self.curline =: stline; 1228 | self.curpos =: stpos; 1229 | self.adjust(); 1230 | } 1231 | function cancelselected() 1232 | { 1233 | var selected = self.selected; 1234 | if (selected != null) { 1235 | self.invertselection(); 1236 | self.selected = null; 1237 | } 1238 | } 1239 | function checkselected(int line, int pos) 1240 | { 1241 | var selected = self.selected; 1242 | if (selected == null) 1243 | self.selected = selected = new SelectedText(line, pos); 1244 | else 1245 | self.invertselection(); 1246 | selected.check(line, pos); 1247 | } 1248 | function invertselection() 1249 | { 1250 | if (self.text == null) 1251 | return; 1252 | var selected = self.selected; 1253 | if (selected == null || selected.isempty()) 1254 | return; 1255 | :(int stline, int stpos, int endline, int endpos) = 1256 | selected.getordered(); 1257 | var text = self.text; 1258 | int headline = self.headline; 1259 | int lineheight = self.lineheight; 1260 | int maxlines = self.maxlines; 1261 | int firstline = stline; 1262 | int lastline = headline + maxlines - 1; 1263 | 1264 | if (firstline < headline) 1265 | firstline = headline; 1266 | if (lastline > endline) 1267 | lastline = endline; 1268 | self.SetFunction(GXinvert); 1269 | int xoff = self.xoff; 1270 | for (int nline = firstline; nline <= lastline; ++nline) { 1271 | string line = nline >= elements(text) ? "" : self.text[nline]; 1272 | int ascent = self.ascent; 1273 | int ypos = MARGINSUP + lineheight * (nline - headline); 1274 | int pos0 = nline == stline ? stpos : 0; 1275 | int pos1 = nline == endline ? endpos : length(line); 1276 | int x0 = pos0 == 0 ? 0 : self.getTextxOff(substr(line, 0, pos0)); 1277 | int x1 = pos1 == 0 ? 0 : self.getTextxOff(substr(line, 0, pos1)); 1278 | 1279 | self.FillRectangle(x0 + xoff, ypos, x1 - x0, lineheight); 1280 | } 1281 | self.SetFunction(GXcopy); 1282 | } 1283 | function moveselected() 1284 | { 1285 | var selected = self.selected; 1286 | if (selected != null) { 1287 | selected.move(self.curline, self.curpos); 1288 | self.invertselection(); 1289 | self.SetSelectionOwner(XA_PRIMARY, CurrentTime); 1290 | } 1291 | } 1292 | function paste_selection(int atomsel, int time) 1293 | { 1294 | self.ConvertSelection(atomsel, self.InternAtom(UTF8_STRING_s), 1295 | atomsel, time); 1296 | } 1297 | function paste(int time) 1298 | { 1299 | int clipboard = self.InternAtom(CLIPBOARD_s); 1300 | self.paste_selection(clipboard, time); 1301 | } 1302 | function selectall(int time) 1303 | { 1304 | self.cursor(); 1305 | self.cancelselected(); 1306 | self.selected = new SelectedText(0, 0); 1307 | self.selected.move(elements(self.text), 0); 1308 | self.SetSelectionOwner(XA_PRIMARY, time); 1309 | self.drawall(); 1310 | self.invertselection(); 1311 | self.cursor(); 1312 | } 1313 | function cutselected(int time) 1314 | { 1315 | if (self.selected == null) 1316 | self.parent.alert("Nothing to cut"); 1317 | else { 1318 | self.cursor(); 1319 | self.invertselection(); 1320 | string text = self.getselectedtext(); 1321 | self.copybuffer = text; 1322 | self.deleteselected(); 1323 | self.drawall(); 1324 | self.parent.updatepos(); 1325 | self.cursor(); 1326 | self.SetSelectionOwner(self.InternAtom(CLIPBOARD_s), time); 1327 | } 1328 | } 1329 | function copyselected(int time) 1330 | { 1331 | if (self.selected == null) 1332 | self.parent.alert("Nothing to copy"); 1333 | else { 1334 | string text = self.getselectedtext(); 1335 | self.copybuffer = text; 1336 | self.SetSelectionOwner(self.InternAtom(CLIPBOARD_s), time); 1337 | } 1338 | } 1339 | function checkxoff() 1340 | { 1341 | var text = self.text; 1342 | if (text == null) 1343 | return; 1344 | int curline = self.curline; 1345 | int curpos = self.curpos; 1346 | int width = self.width; 1347 | int xoff = self.xoff; 1348 | string line = text[curline]; 1349 | int xpos = self.getTextxOff(substr(line, 0, curpos)); 1350 | if (xpos >= width - xoff) { 1351 | int chunk = (width - MARGINLEFT) / 3; 1352 | xoff = MARGINLEFT - (int(xpos/ chunk) - 1) * chunk; 1353 | self.xoff =: xoff; 1354 | return true; 1355 | } 1356 | if (xpos + xoff < 0) { 1357 | int chunk = (width - MARGINLEFT) / 3; 1358 | xoff = MARGINLEFT - int(xpos/ chunk) * chunk; 1359 | self.xoff =: xoff; 1360 | return true; 1361 | } 1362 | return false; 1363 | } 1364 | function adjust() 1365 | { 1366 | int headline = self.headline; 1367 | int maxlines = self.maxlines; 1368 | int lastline = headline + maxlines; 1369 | int curline = self.curline; 1370 | if (curline >= lastline) { 1371 | self.headline =: curline - maxlines + 1; 1372 | return true; 1373 | } 1374 | else if (curline < headline) { 1375 | self.headline =: curline; 1376 | return true; 1377 | } 1378 | else 1379 | return false; 1380 | } 1381 | function up() 1382 | { 1383 | int headline = self.headline; 1384 | if (headline > 0) { 1385 | self.scrollup(); 1386 | return true; 1387 | } 1388 | else 1389 | return false; 1390 | } 1391 | function down() 1392 | { 1393 | int headline = self.headline; 1394 | if (headline < elements(self.text)) { 1395 | self.scrolldown(); 1396 | return true; 1397 | } 1398 | else 1399 | return false; 1400 | } 1401 | function moveup() 1402 | { 1403 | int curline = self.curline; 1404 | --curline; 1405 | self.curline =: curline; 1406 | int headline = self.headline; 1407 | if (headline > curline) { 1408 | self.scrollup(); 1409 | return true; 1410 | } 1411 | else 1412 | return false; 1413 | } 1414 | function movedown() 1415 | { 1416 | int curline = self.curline; 1417 | ++curline; 1418 | self.curline = curline; 1419 | int headline = self.headline; 1420 | int maxlines = self.maxlines; 1421 | if (curline >= headline + maxlines) { 1422 | self.scrolldown(); 1423 | return true; 1424 | } 1425 | else 1426 | return false; 1427 | } 1428 | function scrollup() 1429 | { 1430 | int headline = self.headline; 1431 | --headline; 1432 | self.headline =: headline; 1433 | //self.drawall(); 1434 | } 1435 | function scrolldown() 1436 | { 1437 | int headline = self.headline; 1438 | ++headline; 1439 | self.headline =: headline; 1440 | //self.drawall(); 1441 | } 1442 | function cursor() 1443 | { 1444 | if (! self.has_focus) 1445 | return; 1446 | var text = self.text; 1447 | if (text == null) 1448 | return; 1449 | int curline = self.curline; 1450 | int headline = self.headline; 1451 | int maxlines = self.maxlines; 1452 | if (curline < headline || curline >= headline + maxlines) 1453 | return; 1454 | 1455 | int lineheight = self.lineheight; 1456 | int ypos = (curline - headline) * lineheight + MARGINSUP; 1457 | string line = text[curline]; 1458 | int curpos = self.curpos; 1459 | int xpos = self.getTextxOff(substr(line, 0, curpos)) + self.xoff; 1460 | self.SetFunction(GXinvert); 1461 | self.FillRectangle(xpos, ypos, 2, lineheight); 1462 | self.SetFunction(GXcopy); 1463 | } 1464 | function drawall() 1465 | { 1466 | int headline = self.headline; 1467 | int maxlines = self.maxlines; 1468 | int maxline = headline + maxlines - 1; 1469 | self.drawlines(headline, maxline); 1470 | } 1471 | function drawlines(int from, int to) 1472 | { 1473 | int headline = self.headline; 1474 | int maxlines = self.maxlines; 1475 | int maxline = headline + maxlines - 1; 1476 | if (from < headline) 1477 | from = headline; 1478 | if (to == 0) 1479 | to = maxline; 1480 | else if (to > maxline) 1481 | to = maxline; 1482 | for (int line = from; line <= to; ++line) 1483 | self.drawline(line); 1484 | } 1485 | function drawline(int nline) 1486 | { 1487 | var text = self.text; 1488 | string line; 1489 | if (nline < elements(text)) 1490 | line = self.text[nline]; 1491 | int headline = self.headline; 1492 | int lineheight = self.lineheight; 1493 | int ascent = self.ascent; 1494 | int ypos = MARGINSUP + lineheight * (nline - headline); 1495 | self.SetForeground(self.bgcolor); 1496 | self.FillRectangle(0, ypos, self.width, lineheight); 1497 | self.SetForeground(self.fgcolor); 1498 | if (line != null) 1499 | self.DrawString(self.xoff, ypos + ascent, line); 1500 | } 1501 | function set(text) 1502 | { 1503 | self.text = text; 1504 | } 1505 | function indent() 1506 | { 1507 | var selected = self.selected; 1508 | if (selected == null || selected.isempty()) 1509 | return ""; 1510 | self.cursor(); 1511 | self.invertselection(); 1512 | :(int stline, int stpos, int endline, int endpos) = 1513 | selected.getordered(); 1514 | var text = self.text; 1515 | for (int l = stline; l <= endline; ++l) { 1516 | string line = text[l]; 1517 | if (length(line) > 0) { 1518 | line = " " + line; 1519 | text[l] = line; 1520 | } 1521 | } 1522 | self.drawlines(stline, endline); 1523 | self.invertselection(); 1524 | self.cursor(); 1525 | } 1526 | function unindent() 1527 | { 1528 | var selected = self.selected; 1529 | if (selected == null || selected.isempty()) 1530 | return ""; 1531 | self.cursor(); 1532 | self.invertselection(); 1533 | :(int stline, int stpos, int endline, int endpos) = 1534 | selected.getordered(); 1535 | var text = self.text; 1536 | for (int l = stline; l <= endline; ++l) { 1537 | string line = text[l]; 1538 | if (substr(line, 0, 4) == " ") { 1539 | line = substr(line, 4); 1540 | text[l] = line; 1541 | } 1542 | } 1543 | self.drawlines(stline, endline); 1544 | self.invertselection(); 1545 | self.cursor(); 1546 | } 1547 | function close() 1548 | { 1549 | self.text = null; 1550 | self.Destroy(); 1551 | } 1552 | function findtext(string find) 1553 | { 1554 | var text = self.text; 1555 | int nlines = elements(text); 1556 | int stline = 0; 1557 | int stpos = 0; 1558 | var selected = self.selected; 1559 | if (selected != null && ! selected.isempty()) { 1560 | :(stline, stpos, int endline, int endpos) = 1561 | selected.getordered(); 1562 | ++stpos; 1563 | } 1564 | for (int l = stline; l < nlines; ++l) { 1565 | int p = indexof(text[l], find, stpos); 1566 | if (p >= 0) { 1567 | int pend = p + length(find); 1568 | self.cancelselected(); 1569 | self.selected = selected = new SelectedText(l, p); 1570 | selected.move(l, pend); 1571 | self.curpos = pend; 1572 | self.curline = l; 1573 | self.adjust(); 1574 | self.drawall(); 1575 | self.invertselection(); 1576 | return true; 1577 | } 1578 | stpos = 0; 1579 | } 1580 | return false; 1581 | } 1582 | } 1583 | 1584 | //************************************************************** 1585 | 1586 | class PokeditWindow : TopLevelWindow 1587 | { 1588 | var id; 1589 | var width; 1590 | var height; 1591 | var menubarh; 1592 | var menubarw; 1593 | var textfont; 1594 | var menufont; 1595 | var textwindow; 1596 | var statuswindow; 1597 | var dialogwindow; 1598 | var dialogactive; 1599 | var filename; 1600 | function PokeditWindow(controller) 1601 | { 1602 | self.id = controller.genuid(); 1603 | int width = 800; 1604 | int height = 600; 1605 | self.width = width; 1606 | self.height = height; 1607 | var bgcolor = controller.display.ParseColor("grey70"); 1608 | self.TopLevelWindow(controller, "Pokedit", 0, 0, width, height, 1609 | { "background-color" : bgcolor } ); 1610 | var display = self.display; 1611 | 1612 | self.SetWMProtocols( [ WM_DELETE_WINDOW_s, WM_TAKE_FOCUS_s ] ); 1613 | 1614 | self.OnConfigure += eventhandler(self, "onconfigure"); 1615 | self.OnMap += eventhandler(self, "onmap"); 1616 | self.OnClientMessage += eventhandler(self, "onclientmessage"); 1617 | 1618 | var menufont = self.getmenufont(); 1619 | var menubar = new MenuBar(display, menufont); 1620 | var filemenu = new Menu(display, menufont); 1621 | filemenu.push("new", method_fun(self, "new") ); 1622 | filemenu.push("save", method_fun(self, "save") ); 1623 | filemenu.push("save as", method_fun(self, "saveas") ); 1624 | filemenu.push("close", method_fun(self, "close") ); 1625 | var editmenu = new Menu(display, menufont); 1626 | editmenu.push("cut", method_fun(self, "cut") ); 1627 | editmenu.push("copy", method_fun(self, "copy") ); 1628 | editmenu.push("paste", method_fun(self, "paste") ); 1629 | editmenu.push("select all", method_fun(self, "selectall") ); 1630 | editmenu.push("find", method_fun(self, "find") ); 1631 | var viewmenu = new Menu(display, menufont); 1632 | viewmenu.push("status", method_fun(self, "togglestatus") ); 1633 | var toolsmenu = new Menu(display, menufont); 1634 | toolsmenu.push("indent", method_fun(self, "indent") ); 1635 | toolsmenu.push("unindent", method_fun(self, "unindent") ); 1636 | 1637 | menubar.push("File", filemenu); 1638 | menubar.push("Edit", editmenu); 1639 | menubar.push("View", viewmenu); 1640 | menubar.push("Tool", toolsmenu); 1641 | int menubarh = menubar.getheight(); 1642 | self.menubarh = menubarh; 1643 | var menubarw = menubar.activate(self, 0, 0, width); 1644 | self.menubarw = menubarw; 1645 | 1646 | var statuswindow = new StatusWindow(self, 1, height - 24 - 1, 1647 | width - 2, 24); 1648 | self.statuswindow = statuswindow; 1649 | 1650 | var textwindow = new TextWindow(self, 1, menubarh + 1, 1651 | width - 2, height - menubarh - 2 - 24 - 1); 1652 | self.textwindow = textwindow; 1653 | self.configuresubwindows(); 1654 | menubarw.Map(); 1655 | } 1656 | function getid() 1657 | { 1658 | return int(self.id); 1659 | } 1660 | function waiting() 1661 | { 1662 | return self.dialogactive != null; 1663 | } 1664 | function configuresubwindows() 1665 | { 1666 | int width = self.width; 1667 | int height = self.height; 1668 | int menubarh = self.menubarh; 1669 | self.menubarw.ResizeWindow(width, menubarh); 1670 | int nextypos = menubarh + 1; 1671 | int textheight = height - menubarh - 2; 1672 | 1673 | var dialogwindow = self.dialogwindow; 1674 | if (dialogwindow != null) { 1675 | int dheight = dialogwindow.getheight(); 1676 | dialogwindow.MoveResizeWindow(1, nextypos, width - 2, dheight); 1677 | nextypos += dheight + 2; 1678 | textheight -= dheight + 2; 1679 | } 1680 | 1681 | var statuswindow = self.statuswindow; 1682 | if (statuswindow != null) { 1683 | int stheight = statuswindow.getheight(); 1684 | textheight -= stheight + 1; 1685 | statuswindow.MoveResizeWindow(1, textheight + nextypos + 1, 1686 | width - 2, stheight); 1687 | } 1688 | var textwindow = self.textwindow; 1689 | if (textwindow != null) 1690 | textwindow.MoveResizeWindow(1, nextypos, width - 2, textheight); 1691 | } 1692 | function onconfigure(event) 1693 | { 1694 | int width = event.width(); 1695 | int height = event.height(); 1696 | self.width = width; 1697 | self.height = height; 1698 | self.configuresubwindows(); 1699 | } 1700 | function onmap(event) 1701 | { 1702 | if (self.textwindow != null) 1703 | self.textwindow.Map(); 1704 | if (self.statuswindow != null) 1705 | self.statuswindow.Map(); 1706 | } 1707 | function onclientmessage(event) 1708 | { 1709 | string type = self.GetAtomName(event.message_type()); 1710 | switch (type) { 1711 | case WM_PROTOCOLS_s: 1712 | string protocol = self.GetAtomName(event.message_data(0)); 1713 | switch (protocol) { 1714 | case WM_DELETE_WINDOW_s: 1715 | self.controller.pushaction(method_fun(self, "close")); 1716 | break; 1717 | case WM_TAKE_FOCUS_s: 1718 | var dialogactive = self.dialogactive; 1719 | if (dialogactive != null) { 1720 | dialogactive.setfocus(self.getDID()); 1721 | break; 1722 | } 1723 | var dialogwindow = self.dialogwindow; 1724 | if (dialogwindow != null) { 1725 | dialogwindow.setfocus(self.getDID()); 1726 | break; 1727 | } 1728 | var textwindow = self.textwindow; 1729 | if (textwindow != null) 1730 | textwindow.SetInputFocus(RevertToParent); 1731 | else 1732 | self.SetInputFocus(RevertToParent); 1733 | break; 1734 | default: 1735 | cry("Warning: unknown WM Protocol: ", protocol); 1736 | } 1737 | break; 1738 | default: 1739 | cry("Warning: unknown ClientMessage type: ", type); 1740 | } 1741 | } 1742 | 1743 | function openfile(string filename) 1744 | { 1745 | var file = open(filename, "r"); 1746 | file.encoding("utf8"); 1747 | string lines[]; 1748 | string line; 1749 | for (;;) { 1750 | line = file.readline(); 1751 | if (file.eof()) 1752 | break; 1753 | line = chomp(line); 1754 | push(lines, line); 1755 | } 1756 | if (line != "") { 1757 | push(lines, line); 1758 | cry("Warning: no newline at end of file"); 1759 | } 1760 | file.close(); 1761 | self.filename = filename; 1762 | self.textwindow.set(lines); 1763 | self.SetWMName("pokedit - " + filename); 1764 | } 1765 | function closedialog() 1766 | { 1767 | var dialogwindow = self.dialogwindow; 1768 | if (dialogwindow != null) { 1769 | self.dialogwindow = null; 1770 | dialogwindow.close(); 1771 | self.controller.pushaction(method_fun(self, 1772 | "configuresubwindows")); 1773 | } 1774 | } 1775 | function savetofile(string sfile) 1776 | { 1777 | var text = self.textwindow.text; 1778 | try { 1779 | var handle = open(sfile, "w"); 1780 | handle.encoding("utf8"); 1781 | handle.print(join("\n", text)); 1782 | // Check for newline at end of file: 1783 | // avoid adding spurious newllines or leaving non terminated 1784 | // lines at end. 1785 | string last = text[-1]; 1786 | if (length(last) != 0) 1787 | handle.print("\n"); 1788 | handle.close(); 1789 | self.filename = sfile; 1790 | self.SetWMName("pokedit - " + sfile); 1791 | } 1792 | catch (e) { 1793 | self.alert("Error saving file '" + sfile + "':\n" + 1794 | string(e["message"])); 1795 | } 1796 | } 1797 | function saveas() 1798 | { 1799 | self.dialogwindow = new SaveasWindow(self, self.width - 2); 1800 | self.configuresubwindows(); 1801 | self.dialogwindow.Map(); 1802 | self.dialogwindow.setfocus(self.getDID()); 1803 | } 1804 | function new() 1805 | { 1806 | self.controller.pokeditnew(); 1807 | } 1808 | function save() 1809 | { 1810 | var filename = self.filename; 1811 | if (filename == null) 1812 | self.saveas(); 1813 | else 1814 | self.savetofile(filename); 1815 | } 1816 | function close() 1817 | { 1818 | var dialogactive = self.dialogactive; 1819 | if (dialogactive != null) { 1820 | self.dialogactive = null; 1821 | dialogactive.close(); 1822 | self.controller.pushaction(method_fun(self, "close")); 1823 | return; 1824 | } 1825 | var dialogwindow = self.dialogwindow; 1826 | if (dialogwindow != null) { 1827 | self.dialogwindow = null; 1828 | dialogwindow.close(); 1829 | self.controller.pushaction(method_fun(self, "close")); 1830 | return; 1831 | } 1832 | var menubarw = self.menubarw; 1833 | if (menubarw != null) { 1834 | self.menubarw = null; 1835 | menubarw.Destroy(); 1836 | } 1837 | // If the text window is still here, destroy it. 1838 | // Its OnDentroy handler will call this method again. 1839 | // In the following call, destroy self. 1840 | var textwindow = self.textwindow; 1841 | if (textwindow != null) { 1842 | self.textwindow = null; 1843 | self.controller.pushaction(method_fun(textwindow, "close")); 1844 | } 1845 | else 1846 | self.Destroy(); 1847 | } 1848 | function togglestatus() 1849 | { 1850 | var statuswindow = self.statuswindow; 1851 | if (statuswindow == null) { 1852 | statuswindow = new StatusWindow(self, 1, 1, 1, 1); 1853 | self.statuswindow = statuswindow; 1854 | } 1855 | else { 1856 | self.statuswindow = null; 1857 | statuswindow.Destroy(); 1858 | statuswindow = null; 1859 | } 1860 | self.configuresubwindows(); 1861 | if (statuswindow != null) 1862 | statuswindow.Map(); 1863 | } 1864 | function updatepos() 1865 | { 1866 | var statuswindow = self.statuswindow; 1867 | if (statuswindow != null) 1868 | statuswindow.updatepos(); 1869 | } 1870 | function cut() 1871 | { 1872 | var textwindow = self.textwindow; 1873 | if (textwindow != null) 1874 | textwindow.cutselected(CurrentTime); 1875 | } 1876 | function copy() 1877 | { 1878 | var textwindow = self.textwindow; 1879 | if (textwindow != null) 1880 | textwindow.copyselected(CurrentTime); 1881 | } 1882 | function paste() 1883 | { 1884 | var textwindow = self.textwindow; 1885 | if (textwindow != null) 1886 | textwindow.paste(CurrentTime); 1887 | } 1888 | function selectall() 1889 | { 1890 | var textwindow = self.textwindow; 1891 | if (textwindow != null) 1892 | textwindow.selectall(CurrentTime); 1893 | } 1894 | function find() 1895 | { 1896 | var findtool = new FindTool(self); 1897 | self.dialogactive = findtool; 1898 | findtool.OnDestroy += function (event) { self.dialogactive = null; }; 1899 | findtool.Map(); 1900 | } 1901 | function findtext(string text) 1902 | { 1903 | return self.textwindow.findtext(text); 1904 | } 1905 | function indent() 1906 | { 1907 | var textwindow = self.textwindow; 1908 | if (textwindow != null) 1909 | textwindow.indent(); 1910 | } 1911 | function unindent() 1912 | { 1913 | var textwindow = self.textwindow; 1914 | if (textwindow != null) 1915 | textwindow.unindent(); 1916 | } 1917 | function alert(string message) 1918 | { 1919 | var alertw = new AlertWindow(self, message); 1920 | self.dialogactive = alertw; 1921 | alertw.OnDestroy += function (event) { self.dialogactive = null; }; 1922 | alertw.Map(); 1923 | } 1924 | 1925 | // Fonts 1926 | 1927 | const string DEFAULT_TEXT_FONT = "mono-10"; 1928 | const string DEFAULT_MENU_FONT = "sans-12"; 1929 | 1930 | function gettextfont() 1931 | { 1932 | var font = self.textfont; 1933 | if (font == null) 1934 | self.textfont = font = self.display.CreateFont(DEFAULT_TEXT_FONT); 1935 | return font; 1936 | } 1937 | function getmenufont() 1938 | { 1939 | var font = self.menufont; 1940 | if (font == null) 1941 | self.menufont = font = self.display.CreateFont(DEFAULT_MENU_FONT); 1942 | return font; 1943 | } 1944 | function getstatusfont() 1945 | { 1946 | return self.gettextfont(); 1947 | } 1948 | function getdialogfont() 1949 | { 1950 | return self.getmenufont(); 1951 | } 1952 | } 1953 | 1954 | //************************************************************** 1955 | 1956 | class PokeditController : Controller 1957 | { 1958 | var nextuid; 1959 | var pkwin; 1960 | function PokeditController() 1961 | { 1962 | self.Controller(); 1963 | self.nextuid = 0; 1964 | self.pkwin = new ["Hash"](Hash_key_type_int); 1965 | } 1966 | function genuid() 1967 | { 1968 | int uid = ++self.nextuid; 1969 | return uid; 1970 | } 1971 | function pokeditnew() 1972 | { 1973 | var pokedit = new PokeditWindow(self); 1974 | self.pkwin[pokedit.getid()] = pokedit; 1975 | pokedit.OnDestroy += function (event) { self.pokeditclosed(pokedit); }; 1976 | pokedit.Map(); 1977 | } 1978 | function pokeditopen(string filename) 1979 | { 1980 | var pokedit = new PokeditWindow(self); 1981 | self.pkwin[pokedit.getid()] = pokedit; 1982 | pokedit.OnDestroy += function (event) { self.pokeditclosed(pokedit); }; 1983 | pokedit.openfile(filename); 1984 | pokedit.Map(); 1985 | } 1986 | function pokeditclosed(window) 1987 | { 1988 | var pkwin = self.pkwin; 1989 | delete pkwin[window.getid()]; 1990 | if (elements(pkwin) == 0) 1991 | self.pushaction(method_fun(self, "Quit")); 1992 | } 1993 | } 1994 | 1995 | //************************************************************** 1996 | 1997 | function main [main] (args) 1998 | { 1999 | var controller = new PokeditController(); 2000 | if (elements(args) > 1) 2001 | controller.pokeditopen(args[1]); 2002 | else 2003 | controller.pokeditnew(); 2004 | controller.MainLoop(); 2005 | controller.Close(); 2006 | } 2007 | 2008 | // End 2009 | --------------------------------------------------------------------------------