Changeset 201
- Timestamp:
- 07/26/10 00:52:41 (2 years ago)
- Files:
-
- trunk/src/demo1/main.d (modified) (4 diffs)
- trunk/src/demo2/main.d (modified) (6 diffs)
- trunk/src/yage/core/math/vector.d (modified) (2 diffs)
- trunk/src/yage/gui/surface.d (modified) (17 diffs)
- trunk/src/yage/gui/textblock.d (modified) (20 diffs)
- trunk/src/yage/system/graphics/render.d (modified) (1 diff)
- trunk/src/yage/system/input.d (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/src/demo1/main.d
r198 r201 167 167 }; 168 168 169 view.onMouseDown = (Surface self, byte buttons, Vec2i coordinates){169 view.onMouseDown = (Surface self, Input.MouseButton button, Vec2i coordinates){ 170 170 scene.ship.acceptInput = !scene.ship.acceptInput; 171 171 self.grabMouse(scene.ship.acceptInput); 172 172 return false; 173 173 }; 174 view.onMouseMove = (Surface self, byte buttons,Vec2i rel){174 view.onMouseMove = (Surface self, Vec2i rel){ 175 175 if(scene.ship.acceptInput) 176 176 scene.ship.input.mouseDelta += rel; … … 180 180 // Make a draggable window to show some useful info. 181 181 auto info = view.addChild(new Surface()); 182 info.style.set("top: 5px; right: 12px; width: 11 0px; height: 100px; color: white; padding: -6px; " ~182 info.style.set("top: 5px; right: 12px; width: 115px; height: 100px; color: white; " ~ 183 183 "border-width: 12px; border-image: url('gui/skin/panel1.png'); font-size: 12px"); 184 184 185 185 //window.style.backgroundImage = scene.camera.getTexture(); 186 info.onMouseDown = delegate bool(Surface self, byte buttons, Vec2i coordinates) { 187 self.raise(); 188 self.focus(); 186 bool dragging; 187 info.onMouseDown = delegate bool(Surface self, Input.MouseButton button, Vec2i coordinates) { 188 if (button == Input.MouseButton.LEFT) 189 dragging = true; 189 190 return false; // don't propagate upward 190 191 }; 191 info.onMouseMove = delegate bool(Surface self, byte buttons, Vec2i amount) { 192 if(buttons == 1) 193 self.move(cast(Vec2f)amount, true); 194 return false; 195 }; 196 info.onMouseUp = delegate bool(Surface self, byte buttons, Vec2i coordinates) { 197 self.blur(); 198 return false; 199 }; 200 info.onMouseOver = delegate bool(Surface self, byte buttons, Vec2i coordinates) { 192 info.onMouseMove = delegate bool(Surface self, Vec2i amount) { 193 if (dragging) 194 self.move(amount.toFloat(), true); 195 return false; 196 }; 197 info.onMouseUp = delegate bool(Surface self, Input.MouseButton button, Vec2i coordinates) { 198 if (button == Input.MouseButton.LEFT) 199 dragging = false; 200 return false; 201 }; 202 info.onMouseOver = delegate bool(Surface self) { 201 203 self.style.set("border-image: url('gui/skin/panel2.png')"); 202 204 return false; 203 205 }; 204 info.onMouseOut = delegate bool(Surface self , byte buttons, Vec2i coordinates) {206 info.onMouseOut = delegate bool(Surface self) { 205 207 self.style.set("border-image: url('gui/skin/panel1.png')"); 206 208 return false; … … 229 231 { float framerate = fps/frame.tell(); 230 232 window.setCaption(format("Yage Demo | %.2f fps\0", framerate)); 231 info. innerHtml =format(233 info.setHtml(format( 232 234 `%.2f <b>fps</span><br/>` 233 235 `%d <b>objects</b><br/>` … … 235 237 `%d <b>vertices</b><br/>` 236 238 `%d <b>lights</b><br/><br/> wasd to move<br/> +q for hyperdrive<br/>space to shoot`, 237 framerate, stats.nodeCount, stats.triangleCount, stats.vertexCount, stats.lightCount) ~ Profile.getTimesAndClear() ;239 framerate, stats.nodeCount, stats.triangleCount, stats.vertexCount, stats.lightCount) ~ Profile.getTimesAndClear()); 238 240 frame.seek(0); 239 241 fps = 0; trunk/src/demo2/main.d
r198 r201 18 18 import derelict.opengl.gl; 19 19 import derelict.opengl.glext; 20 21 bool dragging; 20 22 21 23 // program entry point. … … 53 55 return true; 54 56 }; 55 view.onMouseDown = delegate bool(Surface self, byte buttons, Vec2i coordinates) {56 self.grabMouse(!self.getGrabbedMouse());57 return true;58 };59 57 60 58 // Lights … … 62 60 l1.setPosition(Vec3f(0, 200, -30)); 63 61 64 // For Testing62 // A window with text in it 65 63 auto info = view.addChild(new Surface()); 66 64 info.style.set("top: 40px; left: 40px; width: 500px; height: 260px; padding: 3px; color: #ff8800; " ~ … … 70 68 info.style.overflowY = Style.Overflow.HIDDEN; 71 69 72 info.onMouseDown = delegate bool(Surface self, byte buttons, Vec2i coordinates){ 73 self.raise(); 74 self.focus(); 70 bool dragging; 71 info.onMouseDown = delegate bool(Surface self, Input.MouseButton button, Vec2i coordinates) { 72 if (button == Input.MouseButton.LEFT) 73 dragging = true; 75 74 return false; 76 75 }; 77 info.onMouseMove = delegate bool(Surface self, byte buttons, Vec2i amount) {78 if (buttons == 1)79 self.move( cast(Vec2f)amount, true);76 info.onMouseMove = delegate bool(Surface self, Vec2i amount) { 77 if (dragging) 78 self.move(amount.toFloat(), true); 80 79 return false; 81 80 }; 82 info.onMouseUp = delegate bool(Surface self, byte buttons, Vec2i coordinates) { 83 self.blur(); 81 info.onMouseUp = delegate bool(Surface self, Input.MouseButton button, Vec2i coordinates) { 82 if (button == Input.MouseButton.LEFT) 83 dragging = false; 84 84 return false; 85 85 }; 86 info.onMouseOver = delegate bool(Surface self , byte buttons, Vec2i coordinates) {87 //self.style.set("border-image: url('gui/skin/panel2.png')");86 info.onMouseOver = delegate bool(Surface self) { 87 self.style.set("border-image: url('gui/skin/panel2.png')"); 88 88 return false; 89 89 }; 90 info.onMouseOut = delegate bool(Surface self , byte buttons, Vec2i coordinates) {91 //self.style.set("border-image: url('gui/skin/panel1.png')");90 info.onMouseOut = delegate bool(Surface self) { 91 self.style.set("border-image: url('gui/skin/panel1.png')"); 92 92 return false; 93 93 }; 94 94 info.editable = view.editable = true; 95 / /info.style.transform = Matrix().scale(Vec3f(.5, .5, .5));96 95 /* 96 // Test overflow clipping 97 97 auto clip = info.addChild(new Surface()); 98 98 clip.style.set("width: 60px; height: 60px; background-color: black; top: -30px; left: -30px; overflow: hidden"); … … 103 103 auto clip3 = info.addChild(new Surface()); 104 104 clip3.style.set("width: 60px; height: 60px; background-color: orange; top: -30px; right: -30px"); 105 105 */ 106 106 107 107 … … 115 115 auto stats = Render.scene(camera, window); 116 116 Render.surface(view, window); 117 118 117 Render.complete(); // swap buffers 119 118 120 // Print framerate121 f ps++;119 // Rotate the info box 120 float amount = total.tell(); 122 121 info.style.transform = Matrix(); 123 122 info.style.transform = info.style.transform.move(Vec3f(-300, -20, 0)); 124 info.style.transform *= Matrix().rotate(Vec3f(0, sin(total.tell()/2)/2, sin(total.tell()/2)/5));123 info.style.transform *= Matrix().rotate(Vec3f(0, /*sin(amount/2)/2*/0, sin(amount/2)/5)); 125 124 info.style.transform = info.style.transform.move(Vec3f(300, 20, 0)); 126 125 127 126 127 fps++; 128 128 if (frame.tell()>=.25f && !(Surface.getFocusSurface() is info)) 129 { 130 info.innerHtml = `In a <s>traditional</s> <span style="color: green; text-decoration: overline; font-size:40px">`~ 131 `<u>M</u>a<s>nua</s>l <u style="font-size: 18px">printing</u></span> (letterpress) `~ 132 `<span style="text-decoration: overline">house</span> the font would refer to a complete set of metal `~ 133 `type that <b>would be used</b> to type-set an entire page. Unlike a digital typeface it would not `~ 134 `include a single definition of each character, but commonly used characters (such as vowels and periods) `~ 135 `would have more <i>physical type-pieces included. A <b>font <i style="font-style: normal">when</i> bought</b> new would often be sold as `~ 136 `(for example in a roman alphabet) 12pt 14A 34a, meaning that it would be a <span style="font-size: 30px">size</span> 12pt fount containing `~ 137 `14 upper-case 'A's, and 34 lower-case 'A's.</i> The rest of the characters would be provided in quantities `~ 138 `appropriate for the language it was required for in order to set a complete page in that language. `~ 139 `Some metal type required in type-setting, such as varying sizes of inter-word spacing pieces and `~ 140 `line-width spacers, were not part of a specific font in pre-digital usage, but were separate, `~ 141 `generic pieces.[1] `~ Format.convert(` {} fps<br/>`, fps/frame.tell()); 129 { info.setHtml(`Click <s>here</s> <span style="color: green; text-decoration: overline; font-size:40px">`~ 130 `<u>To</u><s> type and</s> <u style="font-size: 18px">edit</u></span> this `~ 131 `<span style="text-decoration: overline">block</span> of <b>text. <i style="font-style: normal">No,</i> really</b> it `~ 132 `works,<br/><br/>Another line of text.<br/><br/><br/> `~ Format.convert(` {} fps<br/>`, fps/frame.tell())); 142 133 143 134 frame.seek(0); trunk/src/yage/core/math/vector.d
r187 r201 159 159 assert(Vec2f(0, 0).inside(polygon)); 160 160 assert(!Vec2f(0, 2).inside(polygon)); 161 assert(Vec2f(0, .999999).inside(polygon)); 162 assert(!Vec2f(0, 1.00001).inside(polygon)); 161 163 } 162 164 … … 290 292 291 293 /// Allow casting to float where appropriate 292 static if (is(T : float)) // if T can be implicitly cast to float 293 { Vec!(S, float) opCast() 294 { Vec!(S, float) result; 295 for (int i=0; i<v.length; i++) 296 result.v[i] = v[i]; 297 return result; 298 } } 294 Vec!(S, float) toFloat() 295 { Vec!(S, float) result; 296 for (int i=0; i<v.length; i++) 297 result.v[i] = v[i]; 298 return result; 299 } 300 301 Vec!(S, int) toInt() 302 { Vec!(S, int) result; 303 for (int i=0; i<v.length; i++) 304 result.v[i] = cast(int)v[i]; 305 return result; 306 } 299 307 300 308 /// Get the element at i trunk/src/yage/gui/surface.d
r200 r201 7 7 module yage.gui.surface; 8 8 9 public import derelict.sdl.sdl; 10 9 11 import tango.math.IEEE; 10 12 import tango.math.Math; 11 13 import tango.text.convert.Utf; 12 14 import yage.core.all; 13 import yage.system.system;14 import yage.system.input;15 15 import yage.system.log; 16 import yage.system.graphics.render;17 16 import yage.system.window; 18 17 import yage.resource.manager; … … 20 19 import yage.resource.image; 21 20 import yage.resource.material; 21 import yage.system.input; 22 22 import yage.gui.style; 23 23 import yage.gui.textblock; … … 33 33 { 34 34 Style style; 35 36 //protected char[] text; /// This html text will be rendered inside the surface. 35 37 36 bool editable = false; /// The text of this surface is editable. 38 37 bool mouseChildren = true; /// Allow the mouse to interact with this Surface's children. 38 int mouseX, mouseY; /// Current position of the mouse cursor. (Read-only for now) 39 39 TextCursor textCursor; /// 40 40 … … 42 42 bool delegate(Surface self) onBlur; /// 43 43 bool delegate(Surface self) onFocus; /// 44 bool delegate(Surface self, byte buttons, Vec2i coordinates) onClick; /// When a mouse button is pressed and released without moving the mouse.45 bool delegate(Surface self, byte buttons, Vec2i coordinates) onDblCick; ///unfinished44 bool delegate(Surface self, Input.MouseButton button, Vec2i coordinates) onClick; /// When a mouse button is pressed and released without moving the mouse. 45 bool delegate(Surface self, Input.MouseButton button, Vec2i coordinates) onDblCick; /// TODO unfinished 46 46 bool delegate(Surface self, int key, int modifier) onKeyDown; /// Triggered once when a key is pressed down 47 47 bool delegate(Surface self, int key, int modifier) onKeyUp; /// Triggered once when a key is released … … 51 51 * Unlike onKeyDown and onKeyUp, key is the unicode value of the key press, instead of the sdl key code. */ 52 52 bool delegate(Surface self, dchar key, int modifier) onKeyPress; 53 bool delegate(Surface self, byte buttons, Vec2i coordinates) onMouseDown; ///54 bool delegate(Surface self, byte buttons, Vec2i coordinates) onMouseUp; ///55 bool delegate(Surface self, byte buttons,Vec2i amount) onMouseMove; ///56 bool delegate(Surface self , byte buttons, Vec2i coordinates) onMouseOver; ///57 bool delegate(Surface self , byte buttons, Vec2i coordinates) onMouseOut; ///53 bool delegate(Surface self, Input.MouseButton button, Vec2i coordinates) onMouseDown; /// 54 bool delegate(Surface self, Input.MouseButton button, Vec2i coordinates) onMouseUp; /// 55 bool delegate(Surface self, Vec2i amount) onMouseMove; /// 56 bool delegate(Surface self) onMouseOver; /// 57 bool delegate(Surface self) onMouseOut; /// 58 58 void delegate(Surface self, Vec2f amount) onResize; /// 59 59 60 /// This is a mirror of SDLMod (SDL's modifier key struct)61 enum ModifierKey62 { NONE = 0x0000, /// Allowed values.63 LSHIFT= 0x0001, /// ditto64 RSHIFT= 0x0002, /// ditto65 LCTRL = 0x0040, /// ditto66 RCTRL = 0x0080, /// ditto67 LALT = 0x0100, /// ditto68 RALT = 0x0200, /// ditto69 LMETA = 0x0400, /// ditto70 RMETA = 0x0800, /// ditto71 NUM = 0x1000, /// ditto72 CAPS = 0x2000, /// ditto73 MODE = 0x4000, /// ditto74 RESERVED = 0x8000, /// ditto75 CTRL = LCTRL | RCTRL, /// ditto76 SHIFT = LSHIFT | RSHIFT, /// ditto77 ALT = LALT | RALT, /// ditto78 META = LMETA | RMETA /// ditto79 };80 81 60 protected Texture textTexture; // texture that constains rendered text image. 82 61 … … 88 67 protected bool mouseIn; // used to track mouseover/mouseout 89 68 protected bool mouseMoved; // used for click() event. 69 90 70 protected bool resizeDirty = true; 91 71 protected bool textDirty = true; … … 155 135 } 156 136 137 138 139 157 140 /** 158 141 * Find the surface at the given coordinates. … … 166 149 * the children will not be searched. 167 150 * Returns: The surface at the coordinates (may be self), or null if coordinates are outside of this surface. */ 168 Surface findSurface( float x, floaty, bool useMouseChildren=true)151 Surface findSurface(Vec2i xy, bool useMouseChildren=true) 169 152 { 170 // Search children171 if (useMouseChildren && mouseChildren)172 { // Sort if necessary173 if (!children.sorted(false, (Surface s){return s.style.zIndex;}))174 children.radixSort(false, (Surface s){return s.style.zIndex;});175 176 foreach(surf; children)177 { Surface result = surf.findSurface(x, y);178 if (result)179 return result;180 }181 }182 183 153 // Search self 184 154 Vec2f[4] polygon; 185 155 getPolygon(polygon); 186 if (Vec2f(x, y).inside(polygon)) 156 if (xy.toFloat().inside(polygon)) // TODO: This doesn't take clipping into account. 157 { 158 // Search children 159 if (useMouseChildren && mouseChildren) 160 { // Sort if necessary 161 if (!children.sorted(false, (Surface s){return s.style.zIndex;})) 162 children.radixSort(false, (Surface s){return s.style.zIndex;}); 163 164 foreach(surf; children) 165 { Surface result = surf.findSurface(xy); 166 if (result) 167 return result; 168 } } 169 187 170 return this; 171 } 188 172 189 173 return null; … … 238 222 SurfaceGeometry getGeometry() 239 223 { return geometry; 224 } 225 226 /** 227 * Get a 4-sided polygon of the outline of this surface, after all styles and the transformation are applied. 228 * Coordinates are relative to the parent Surface. 229 * Params: 230 * polygon = A pointer to a Vec2f[4] where the result will be stored and returned. 231 * If null, new memory will be allocated. */ 232 public Vec2f[] getPolygon(in Vec2f[] polygon=null) 233 { if (polygon.length < 4) 234 polygon = new Vec2f[4]; 235 polygon[0] = localToParent(Vec2f(0)); // top left 236 polygon[1] = localToParent(Vec2f(size.x, 0)); // top right 237 polygon[2] = localToParent(size); // bottom right 238 polygon[3] = localToParent(Vec2f(0, size.y)); // bottom left 239 return polygon; 240 240 } 241 241 … … 255 255 { SDL_WM_GrabInput(SDL_GRAB_OFF); 256 256 grabbedSurface = null; 257 SDL_WarpMouse(mouseX+cast(int)offsetAbsolute.x, mouseY+cast(int)offsetAbsolute.y); 257 258 } 258 259 } … … 261 262 } 262 263 263 /// 264 public char[] innerHtml() 264 /** 265 * Get and set the html text displayed inside this Surface. */ 266 public char[] getHtml() 265 267 { return textBlock.getHtml(); 266 268 } 267 269 /// ditto 268 public void innerHtml(char[] html) 269 { //this.text = html; 270 textDirty = true; 271 Style cs = getComputedStyle(); 272 textBlock.update(html, cs, cast(int)width(), cast(int)height()); 270 public void setHtml(char[] html) 271 { textDirty = true; 272 textBlock.setHtml(html); 273 } 274 275 /** 276 * Convert between global, parent, and local coordinate systems. 277 * style.transform is taken into account. 278 * Params: 279 * xy = Coordinates relative to the left side of the function name. 280 * Returns: Coordinates relative to the right side of the function name. */ 281 Vec2f localToParent(Vec2f xy) 282 { if (parent) /// TODO: innerXy 283 return xy.vec3f.transform(style.transform).vec2f + offset; 284 return xy; 285 } 286 Vec2f localToGlobal(Vec2f xy) /// ditto 287 { if (parent) 288 return localToGlobal(localToParent(xy)); // untested 289 return xy; 290 } 291 Vec2f parentToLocal(Vec2f xy) /// ditto 292 { Vec2f parentSize = Vec2f(parentWidth(), parentHeight()); 293 Vec2f extra = Vec2f( 294 style.borderLeftWidth.toPx(parentSize.x, false) + style.paddingLeft.toPx(parentSize.x, false), 295 style.borderTopWidth.toPx(parentSize.y, false) + style.paddingTop.toPx(parentSize.y, false)); 296 Vec2f innerXy = xy - offset - extra; 297 298 if (parent) 299 { if (style.transform == Matrix.IDENTITY) 300 return innerXy; // simple common case 301 return innerXy.vec3f.transform(style.transform.inverse()).vec2f; // TODO: this fails if there's non-z rotation 302 } 303 return innerXy; 304 } 305 Vec2f globalToLocal(Vec2f xy) /// ditto 306 { if (parent) 307 return parentToLocal(parent.globalToLocal(xy)); // untested 308 return xy; 273 309 } 274 310 … … 360 396 * Update all of this Surface's dimensions, geometry, and children to prepare it for rendering. */ 361 397 void update() 362 { 398 { 363 399 Style cs = getComputedStyle(); 364 400 updateDimensions(cs); … … 380 416 int height = cast(int)height(); 381 417 382 //textBlock.update(text, cs, width, height); 383 //textBlock.update(text, cs, width, height); 384 textBlock.update(textBlock.getHtml(), cs, width, height); 385 Image textImage = textBlock.render(true, editable && focusSurface is this ? &textCursor : null); // TODO: Change true to Probe.NextPow2 386 387 if (textImage) 388 { if (!textTexture) // create texture on first go 389 textTexture = new Texture(textImage, Texture.Format.AUTO, false, "Surface Text", true); 390 else 391 textTexture.setImage(textImage); 392 textTexture.padding = Vec2i(nextPow2(width)-width, -(nextPow2(height)-height)); 393 } else 394 textTexture = null; 418 if (textBlock.update(cs, width, height)) 419 { Image textImage = textBlock.render(true, editable && focusSurface is this ? &textCursor : null); // TODO: Change true to Probe.NextPow2 420 421 if (textImage) 422 { if (!textTexture) // create texture on first go 423 textTexture = new Texture(textImage, Texture.Format.AUTO, false, "Surface Text", true); 424 else 425 textTexture.setImage(textImage); 426 textTexture.padding = Vec2i(nextPow2(width)-width, -(nextPow2(height)-height)); 427 } else 428 textTexture = null; 429 } 395 430 396 431 textDirty = false; … … 438 473 } 439 474 440 /// 441 void click(byte buttons, Vec2i coordinates, bool allowFocus=true) 442 { bool propagate = true; 475 /** 476 * Trigger a click event and call the onClick callback function if set. 477 * Click events occur after a mouseDown and mouseUp when the mouse hasn't moved between the two. 478 * If the onClick function is not set, or if it returns true (propagate), call the parent's click function. 479 * Params: 480 * button = 481 * coordinates = Coordinates relative to the Surface, with style.transform taken into account. 482 * allowFocus = Used internally to prevent focus from propagating updward */ 483 void click(Input.MouseButton button, Vec2i coordinates, bool allowFocus=true) 484 { bool propagate = true; // TODO: Should coordinates be relative to inner area? 443 485 if(onClick) 444 propagate = onClick(this, buttons, coordinates); 445 if (allowFocus && Surface.focusSurface !is this) 446 focus(); // give focus on click if not already focussed. 486 propagate = onClick(this, button, coordinates); 487 if (editable) 488 { if (allowFocus && Surface.focusSurface !is this) 489 focus(); // give focus on click if editable not already focussed. 490 textCursor.position = textBlock.xyToCursor(coordinates); 491 textDirty = true; // redraw 492 } 493 447 494 if(parent && propagate) 448 parent.click(buttons, coordinates, false); 449 } 450 451 495 parent.click(button, coordinates, false); 496 } 497 452 498 /** 453 499 * Trigger a keyDown event and call the onKeyDown callback function if set. 454 * If the onKeyDown function is not set, call the parent's keyDown function.500 * If the onKeyDown function is not set, or if it returns true (propagate), call the parent's keyDown function. 455 501 * Params: 456 502 * key = SDL's key code of the pressed key. 457 503 * mod = Modifier key held down while key was pressed.*/ 458 void keyDown(int key, int mod= ModifierKey.NONE)504 void keyDown(int key, int mod=Input.ModifierKey.NONE) 459 505 { bool propagate = true; 460 506 if(onKeyDown) … … 466 512 /** 467 513 * Trigger a keyUp event and call the onKeyUp callback function if set. 468 * If the onKeyUp function is not set, call the parent's keyUp function.514 * If the onKeyUp function is not set, or if it returns true (propagate), call the parent's keyUp function. 469 515 * Params: 470 516 * key = SDL's key code of the pressed key. 471 517 * mod = Modifier key held down while key was pressed.*/ 472 void keyUp(int key, int mod= ModifierKey.NONE)518 void keyUp(int key, int mod=Input.ModifierKey.NONE) 473 519 { bool propagate = true; 474 520 if(onKeyUp) … … 479 525 480 526 /** 481 * Trigger a keyPress event and call the onKeyPress callback function if set. 482 * If the onKeyPress function is not set, call the parent's keyPress function. 527 * Trigger a keyPress event and call the onKeyPress callback function if set. 528 * Keypress events occur after a keyDown event and reoccur at Input's key repeat rates until after a keyUp occurs. 529 * If the onKeyPress function is not set, or if it returns true (propagate), call the parent's keyPress function. 530 * If editable is true, the TextBlock of this Surface will receive the input. 483 531 * Params: 484 532 * key = SDL's key code of the pressed key. 485 533 * mod = Modifier key held down while key was pressed. 486 534 * unicode = unicode value of pressed key. */ 487 void keyPress(int key, int mod=ModifierKey.NONE, dchar unicode=0) 488 { 535 void keyPress(int key, int mod=Input.ModifierKey.NONE, dchar unicode=0) { 489 536 bool propagate = true; 490 537 if(onKeyPress) 491 propagate = onKeyPress(this, key, mod); 492 if (propagate) 493 { if (editable) 494 { 495 textBlock.input(key, mod, unicode, textCursor, getComputedStyle()); 496 textDirty = true; 497 } 498 if(parent) 499 parent.keyPress(key, mod); 500 } 538 propagate = onKeyPress(this, key, mod); 539 if (editable) 540 { textBlock.input(key, mod, unicode, textCursor); 541 textDirty = true; 542 } 543 if(parent && propagate) 544 parent.keyPress(key, mod); 501 545 } 502 546 503 547 /** 504 548 * Trigger a mouseDown event and call the onMouseDown callback function if set. 505 * If the onMouseDown function is not set, call the parent's mouseDown function.*/ 506 void mouseDown(byte buttons, Vec2i coordinates){ 549 * If the onMouseDown function is not set, or if it returns true (propagate), call the parent's mouseDown function. 550 * Params: 551 * button = Current state of the mouse buttons 552 * coordinates = Coordinates relative to the Surface, with style.transform taken into account. */ 553 void mouseDown(Input.MouseButton button, Vec2i coordinates) { 507 554 mouseMoved = false; 508 555 bool propagate = true; 509 556 if(onMouseDown) 510 propagate = onMouseDown(this, button s, coordinates);557 propagate = onMouseDown(this, button, coordinates); 511 558 if(parent && propagate) 512 parent.mouseDown(button s, coordinates);559 parent.mouseDown(button, coordinates); 513 560 } 514 561 515 562 /** 516 563 * Trigger a mouseUp event and call the onMouseUp callback function if set. 517 * If the onMouseUp function is not set, call the parent's mouseUp function.*/ 518 void mouseUp(byte buttons, Vec2i coordinates){ 564 * If the onMouseUp function is not set, or if it returns true (propagate), call the parent's mouseUp function. 565 * Params: 566 * button = Current state of the mouse buttons 567 * coordinates = Coordinates relative to the Surface, with style.transform taken into account. */ 568 void mouseUp(Input.MouseButton button, Vec2i coordinates) { 519 569 bool propagate = true; 520 570 if(onMouseUp) 521 propagate = onMouseUp(this, button s, coordinates);571 propagate = onMouseUp(this, button, coordinates); 522 572 if (!mouseMoved) // trigger the click event if the mouse button went down and up without the mouse moving. 523 click(button s, coordinates);573 click(button, coordinates); 524 574 if(parent && propagate) 525 parent.mouseUp(buttons, coordinates); 526 } 527 528 /** 529 * Trigger a mouseMove event and call the onMouseMove callback function if set. */ 530 void mouseMove(byte buttons, Vec2i amount){ 575 parent.mouseUp(button, coordinates); 576 } 577 578 /** 579 * Trigger a mouseMove event and call the onMouseMove callback function if set. 580 * If the onMouseMove function is not set, or if it returns true (propagate), call the parent's mouseMove function.*/ 581 void mouseMove(Vec2i amount) { 531 582 mouseMoved = true; 532 583 bool propagate = true; 533 584 if(onMouseMove) 534 propagate = onMouseMove(this, buttons,amount);585 propagate = onMouseMove(this, amount); 535 586 if(parent && propagate) 536 parent.mouseMove(buttons, amount); 537 } 538 539 /** 540 * Trigger a mouseOver event and call the onMouseOver callback function if set. */ 541 void mouseOver(byte buttons, Vec2i coordinates) { 587 parent.mouseMove(amount); 588 } 589 590 /** 591 * Trigger a mouseOver event and call the onMouseOver callback function if set. 592 * If the onMouseOver function is not set, or if it returns true (propagate), call the parent's mouseOver function.*/ 593 void mouseOver() { 542 594 if(!mouseIn) 543 { bool propagate = true; 544 595 { bool propagate = true; 545 596 mouseIn = true; 546 597 if(onMouseOver) 547 propagate = onMouseOver(this , buttons, coordinates);598 propagate = onMouseOver(this); 548 599 if(parent && propagate) 549 parent.mouseOver(buttons, coordinates); 550 } 551 } 552 553 /** 554 * Trigger a mouseOut event and call the onMouseOut callback function if set */ 555 void mouseOut(Surface next, byte buttons, Vec2i coordinates) 600 parent.mouseOver(); 601 } 602 } 603 604 /** 605 * Trigger a mouseOut event and call the onMouseOut callback function if set 606 * If the onMouseOut function is not set, or if it returns true (propagate), call the parent's mouseOut function.*/ 607 void mouseOut(Surface next) 556 608 { 557 609 if(mouseIn) 558 { bool propagate = true;610 { 559 611 if(isChild(next)) 560 return; 561 else562 {mouseIn = false;563 if(onMouseOut)564 propagate = onMouseOut(this, buttons, coordinates);565 if(next !is parent && parent && propagate)566 parent.mouseOut(next, buttons, coordinates);567 }612 return; // Don't do anything if mouseOut occurs when going into a child. 613 614 mouseIn = false; 615 bool propagate = true; 616 if(onMouseOut) 617 propagate = onMouseOut(this); 618 if(next !is parent && parent && propagate) 619 parent.mouseOut(next); 568 620 } 569 621 } … … 608 660 } 609 661 610 611 /*612 * Get a 4-sided polygon of the outline of this surface, after all styles and the transformation are applied.613 * Coordinates are relative to the parent Surface.614 * Params:615 * polygon = A pointer to a Vec2f[4] where the result will be stored. */616 protected Vec2f[] getPolygon(in Vec2f[] polygon=null)617 { if (polygon.length < 4)618 polygon = new Vec2f[4];619 polygon[0] = Vec3f(0).transform(style.transform).vec2f + offset; // top left620 polygon[1] = Vec3f(size.x, 0, 0).transform(style.transform).vec2f + offset; // top right621 polygon[2] = size.vec3f.transform(style.transform).vec2f + offset; // bottom right622 polygon[3] = Vec3f(0, size.y, 0).transform(style.transform).vec2f + offset; // bottom left623 return polygon;624 }625 626 627 662 // Set style dimensions from pixels. 628 663 protected void top(float v) trunk/src/yage/gui/textblock.d
r200 r201 45 45 /** 46 46 * Render text and simple html with styles to an image. 47 * This class is used internally by the engine. In most cases it shouldn't need to be called externally.. */ 47 * TextBlock has two modes of input: setHtml() and the input() function that receives keypresses. 48 * This class is used internally by the engine. In most cases it shouldn't need to be called externally. */ 48 49 struct TextBlock 49 50 { … … 54 55 55 56 private char[] html; 57 private bool htmlDirty = true; // html has changed, letters may be out of date 58 private bool lettersDirty = false; // letters have chagned via input, html may be out of date 56 59 package InlineStyle style; // base style of entire text block 57 60 private Style.TextAlign alignment; … … 91 94 * Get the cursor position from an xy pixel position. */ 92 95 int xyToCursor(Vec2i xy) 93 { 96 { if (!lines.length) 97 return 0; 98 94 99 // Calculate line 95 int line; 96 for (; line<lines.length-1 && 0 <= xy.y; line++) 97 xy.y -= lines[line].height; 100 int line, y; 101 while(true) 102 { y += lines[line].height; 103 if (line>=lines.length-1 || y >= xy.y) 104 break; 105 line++; 106 } 98 107 99 108 // Take alignment into account … … 105 114 for (; position<lines[line].letters.length && 0 < xy.x; position++) 106 115 xy.x -= lines[line].letters[position].advanceX; 116 117 /* 118 int position, x; 119 while(true) 120 { y += lines[line].letters[position].advanceX; 121 if (position>=lines[line].letters.length-1 || x > xy.x) 122 break; 123 position++; 124 } 125 */ 107 126 108 127 return lineToCursor(line, position); … … 144 163 } 145 164 146 /// 147 char[] getHtml() 148 { return html; 165 /** 166 * Reverse the normal function of TextLayout and convert letters[] back to a string of html text. 167 * The text may use different tags than the original html, (since some information is lost) 168 * but will be functionally the same. */ 169 public char[] getHtml() 170 { 171 if (!lettersDirty) 172 return html; 173 174 // If the user has typed text, regenerate html from scratch 175 html = "<span>"; 176 InlineStyle style = this.style; 177 InlineStyle currentStyle = style; // style of the previous letter 178 179 foreach(i, l; letters.data) 180 { 181 InlineStyle* newStyle = cast(InlineStyle*) l.extra; 182 if (currentStyle != *newStyle) // if style has changed since last letter 183 { 184 char[][] styleString; 185 186 // TODO: Would it be better to create arrays to group sequential letters of the same style? 187 // then we could make a single xml node to contain those that have similar styles. 188 // If nothing else, the first version of this function could just return unformatted text. 189 // Should text be stored lazily so we don't have to recreate this all on every keypress? 190 191 // Only print styles that don't match the Surface's style 192 if (style.fontFamily && style.fontFamily != newStyle.fontFamily) 193 styleString ~= swritef(`font-family: url('%s')`, newStyle.fontFamily); 194 if (dword(style.fontSize) != dword(newStyle.fontSize)) 195 styleString ~= swritef(`font-size: %spx`, newStyle.fontSize); 196 if (style.color != newStyle.color) 197 styleString ~= swritef(`color: %spx`, newStyle.color); 198 if (style.fontWeight != newStyle.fontWeight) 199 styleString ~= swritef(`font-weight: %s`, Style.enumToString(newStyle.fontWeight)); 200 if (style.fontStyle != newStyle.fontStyle) 201 styleString ~= swritef(`font-style: %s`, Style.enumToString(newStyle.fontStyle)); 202 if (style.textDecoration != newStyle.textDecoration) 203 styleString ~= swritef(`text-decoration: %s`, Style.enumToString(newStyle.textDecoration)); 204 if (dword(style.lineHeight) != dword(newStyle.lineHeight)) 205 styleString ~= swritef(`lineHeight: %spx`, newStyle.lineHeight); 206 if (dword(style.letterSpacing) != dword(newStyle.letterSpacing)) 207 styleString ~= swritef(`letterSpacing: %spx`, newStyle.letterSpacing); 208 209 html ~= swritef(`</span><span style="%s">`, join(styleString, "; ")); 210 currentStyle = *newStyle; 211 } 212 switch (l.letter) 213 { case '>': html ~= "\>"; break; 214 case '<': html ~= "\<"; break; 215 case '&': html ~= "\&"; break; 216 case '\n': html ~= "<br/>"; break; 217 case ' ': 218 if (i>0 && letters[i-1].letter ==' ') 219 { html ~= "\ "; // encode multiple spaces as " " 220 break; 221 } // fall through: 222 default: 223 html ~= l.toString(); 224 } 225 } 226 html ~= "</span>"; 227 return html; 149 228 } 150 229 … … 156 235 * unicode = Unicode value of the pressed key. 157 236 * cursor = The Surface's TextCursor. */ 158 void input(int key, int mod, dchar unicode, inout TextCursor cursor , Style computedStyle)237 void input(int key, int mod, dchar unicode, inout TextCursor cursor) 159 238 { 160 style = InlineStyle(computedStyle); 161 //Log.trace(cursor.position, " " , letters.length); 239 240 // If the html has changed we need to update the lines before continuing. 241 if (htmlDirty) 242 { letters.length = 0; 243 styles.length = 0; 244 HtmlParser.htmlToLetters(html, style, letters, styles); 245 lines = lettersToLines(letters.data, width, lines); 246 htmlDirty = false; 247 } 248 lettersDirty = true; 249 162 250 assert(cursor.position <= letters.length); 163 251 static int xPosition; // save the cursor's x position when moving from one line to the next. … … 185 273 int x = xPosition = xPosition ? xPosition : cursorToXy(cursor.position).x; 186 274 x -= Line.getOffset(newLine.width, width, alignment); 187 for (; i<newLine.letters.length && x >=0; i++)275 for (; i<newLine.letters.length && x>=0; i++) 188 276 x-= newLine.letters[i].advanceX; // find the cursor position for the previous x position 189 cursor.position = lineToCursor(currentLine-1, i-1);277 cursor.position = lineToCursor(currentLine-1, max(i-1, 0)); 190 278 } 191 279 break; … … 196 284 int x = xPosition = xPosition ? xPosition : cursorToXy(cursor.position).x; 197 285 x -= Line.getOffset(newLine.width, width, alignment); 198 for (; i<newLine.letters.length && x >=0; i++)286 for (; i<newLine.letters.length && x>=0; i++) 199 287 x-= newLine.letters[i].advanceX; 200 cursor.position = lineToCursor(currentLine+1, i-1); 288 //if (currentLine <lines.length-1) 289 // i--; // if not the last line, go back one before the character that causes the new line. 290 cursor.position = lineToCursor(currentLine+1, max(i-1, 0)); 201 291 } 202 292 break; … … 204 294 cursor.position -= linePosition; 205 295 break; 206 case SDLK_END: 207 auto letters = lines[currentLine].letters; 208 int newPosition = (cast(int)letters.length) - linePosition; 209 if (currentLine != lines.length-1) 210 newPosition--; // if not the last line, go back one before the character that causes the new line. 211 cursor.position += newPosition; 296 case SDLK_END: 297 if (lines.length) 298 { auto letters = lines[currentLine].letters; 299 int newPosition = (cast(int)letters.length) - linePosition; 300 if (currentLine != lines.length-1) 301 newPosition--; // if not the last line, go back one before the character that causes the new line. 302 cursor.position += newPosition; 303 } 212 304 break; 213 305 … … 230 322 if (unicode=='\r') 231 323 unicode='\n'; 232 //Log.trace(cast(int)unicode);233 324 234 325 // Get the style to use for a new letter … … 248 339 break; 249 340 250 251 // TODO: tabs, center cursor position, end crashes on centered textblock, click to position cursor, selection, ctrl+a, z, x, c, v 341 // TODO: tabs, click to position cursor, selection, ctrl+a, z, x, c, v 252 342 } 253 343 254 344 lines = lettersToLines(letters.data, width, lines); 255 //Log.trace(lines.length);256 345 } 257 346 … … 312 401 result.overlayAndColor(letter.image, istyle.color, x+letter.left, baseline-letter.top); 313 402 314 // Render underline, overline, and line through403 // Render underline, overline, and line-through 315 404 if (istyle.textDecoration == Style.TextDecoration.UNDERLINE) 316 405 for (int h=max(0, baseline); h<min(baseline+lineWidth, height); h++) … … 357 446 358 447 /** 359 * Reverse the normal function of TextLayout and convert letters[] back to a string of html text. 360 * The text may use different tags than the original html, (since some information is lost) 361 * but will be functionally the same. */ 362 char[] toString() 363 { 364 char[] result = "<span>"; 365 InlineStyle style = this.style; 366 InlineStyle currentStyle = style; // style of the previous letter 367 368 foreach(Letter l; letters) 369 { 370 InlineStyle* newStyle = cast(InlineStyle*) l.extra; 371 if (currentStyle != *newStyle) // if style has changed since last letter 372 { 373 char[][] styleString; 374 375 // TODO: Would it be better to create arrays to group sequential letters of the same style? 376 // then we could make a single xml node to contain those that have similar styles. 377 // If nothing else, the first version of this function could just return unformatted text. 378 // Should text be stored lazily so we don't have to recreate this all on every keypress? 379 380 // Only print styles that don't match the Surface's style 381 if (style.fontFamily && style.fontFamily != newStyle.fontFamily) 382 styleString ~= swritef(`font-family: url('%s')`, newStyle.fontFamily); 383 if (dword(style.fontSize) != dword(newStyle.fontSize)) 384 styleString ~= swritef(`font-size: %spx`, newStyle.fontSize); 385 if (style.color != newStyle.color) 386 styleString ~= swritef(`color: %spx`, newStyle.color); 387 if (style.fontWeight != newStyle.fontWeight) 388 styleString ~= swritef(`font-weight: %s`, Style.enumToString(newStyle.fontWeight)); 389 if (style.fontStyle != newStyle.fontStyle) 390 styleString ~= swritef(`font-style: %s`, Style.enumToString(newStyle.fontStyle)); 391 if (style.textDecoration != newStyle.textDecoration) 392 styleString ~= swritef(`text-decoration: %s`, Style.enumToString(newStyle.textDecoration)); 393 if (dword(style.lineHeight) != dword(newStyle.lineHeight)) 394 styleString ~= swritef(`lineHeight: %spx`, newStyle.lineHeight); 395 if (dword(style.letterSpacing) != dword(newStyle.letterSpacing)) 396 styleString ~= swritef(`letterSpacing: %spx`, newStyle.letterSpacing); 397 398 result ~= swritef(`</span><span style="%s">`, join(styleString, "; ")); 399 currentStyle = *newStyle; 400 } 401 result ~= l.toString(); 402 } 403 404 return result ~ "</span>"; 405 } 406 407 /** 408 * Replace the text with new text, rebuilding the internal lines and letters data structures. 409 * This is unlike input(), which modifies the text based on a single keystroke. 448 * Set the contents of the Textblock with html. 410 449 * Params: 411 * text= String of utf-8 encoded html text to render.450 * html = String of utf-8 encoded html text to render. 412 451 * The following html tags are supported:<br> 413 452 * a, b, br, del, i, span, sub, sup, u <br> … … 415 454 * color, font-family, font-size[%|px], font-style[normal|italic|oblique], font-weight[normal|bold], 416 455 * letter-spacing[%|px], line-height[%|px], 417 * text-align[left|center|right] text-decoration[none|underline|overline|line-through] 456 * text-align[left|center|right] text-decoration[none|underline|overline|line-through] */ 457 void setHtml(char[] html) 458 { this.html = html; 459 htmlDirty = true; 460 lettersDirty = false; 461 } 462 463 /** 464 * Replace the text with new text, rebuilding the internal lines and letters data structures. 465 * This is unlike input(), which modifies the text based on a single keystroke. 466 * Params: 418 467 * style = A style with fontSize and lineHeight in terms of pixels 419 468 * width = Available width for rendering text … … 421 470 * Returns: True if the text will need to be re-rendered, false otherwise. 422 471 * TODO: Should this be a constructor to maintain RAII? */ 423 bool update( char[] html,Style style, int width, int height)472 bool update(Style style, int width, int height) 424 473 { 425 474 InlineStyle istyle = InlineStyle(style); 426 475 alignment = style.textAlign; 427 476 428 // If text has changed 429 //bool newLetters = text != (*this).text || istyle != (*this).style; 430 bool newLetters = html != this.html || istyle != this.style; 477 // If letters have changed 478 if (lettersDirty) // recreate html from letters. 479 html = getHtml(); 480 481 // Reparse the arrays of letters and styles from the html 482 bool newLetters = htmlDirty || istyle != this.style; 431 483 if (newLetters) 432 { 433 // Update the arrays of letters and styles 434 letters.length = 0; 484 { letters.length = 0; 435 485 styles.length = 0; 436 HtmlParser.htmlToLetters(html, style, letters, styles);437 438 this.html = html;439 this.style = istyle;440 }486 HtmlParser.htmlToLetters(html, istyle, letters, styles); 487 } 488 489 this.style = istyle; 490 htmlDirty = false; 441 491 442 492 // If text or dimensions have changed 443 493 if (newLetters || width != this.width || height != this.height) 444 { 445 this.width = width; 494 { this.width = width; 446 495 this.height = height; 447 496 lines = lettersToLines(letters.data, width, lines); 448 497 return true; 449 498 } 499 450 500 return false; 451 501 } … … 631 681 * Returns: 632 682 */ 633 static void htmlToLetters(char[] htmlText, Style style, inout ArrayBuilder!(Letter) letters, inout ArrayBuilder!(InlineStyle) styles)683 static void htmlToLetters(char[] htmlText, InlineStyle style, inout ArrayBuilder!(Letter) letters, inout ArrayBuilder!(InlineStyle) styles) 634 684 { 635 685 char[] lookaside = Memory.allocate!(char)(htmlText.length+13); // +13 for <span></span> that surrounds it … … 646 696 } 647 697 648 htmlNodeToLetters(doc.query.nodes[0], InlineStyle(style), letters, styles);698 htmlNodeToLetters(doc.query.nodes[0], style, letters, styles); 649 699 } 650 700 … … 687 737 styles ~= style; 688 738 if (input.value.length) 689 { char[] text = htmlEntityDecode(input.value);739 { char[] text = entityDecode(input.value); 690 740 foreach (dchar c; text) // dchar to iterate over each utf-8 char group 691 741 { if (style.fontFamily) … … 749 799 * Note that this could avoid heap activity altogether with lookaside buffers. 750 800 * See: http://en.wikipedia.org/wiki/Character_encodings_in_HTML#XML_character_entity_references */ 751 private static char[] htmlEntityDecode(char[] text) 752 { text = text.substitute("&", "&"); // TODO: fix garbage created by this function. 801 private static char[] entityDecode(char[] text) 802 { // TODO: Perform this in one pass 803 text = text.substitute("&", "&"); // TODO: fix garbage created by this function. 753 804 text = text.substitute("<", "<"); 754 805 text = text.substitute(">", ">"); … … 761 812 { char[] test = "<>Hello Goodbye &"'<>"; 762 813 char[] result="<>Hello Goodbye\ &\"'<>"; 763 assert ( htmlEntityDecode(test) == result);814 assert (entityDecode(test) == result); 764 815 } 765 816 } trunk/src/yage/system/graphics/render.d
r188 r201 742 742 // Bind surface properties 743 743 glPushMatrix(); 744 glTranslatef(surface.left(), surface.top(), 0); 744 745 glMultMatrixf(surface.style.transform.ptr); 745 glTranslatef(surface.left(), surface.top(), 0);746 746 surface.style.backfaceVisibility ? glDisable(GL_CULL_FACE) : glEnable(GL_CULL_FACE); 747 747 748 // Render the surface 748 749 geometry(surface.getGeometry()); 749 750 trunk/src/yage/system/input.d
r200 r201 23 23 abstract class Input 24 24 { 25 /// This is a mirror of SDLMod (SDL's modifier key struct) 26 enum ModifierKey 27 { NONE = 0x0000, /// Allowed values. 28 LSHIFT= 0x0001, /// ditto 29 RSHIFT= 0x0002, /// ditto 30 LCTRL = 0x0040, /// ditto 31 RCTRL = 0x0080, /// ditto 32 LALT = 0x0100, /// ditto 33 RALT = 0x0200, /// ditto 34 LMETA = 0x0400, /// ditto 35 RMETA = 0x0800, /// ditto 36 NUM = 0x1000, /// ditto 37 CAPS = 0x2000, /// ditto 38 MODE = 0x4000, /// ditto 39 RESERVED = 0x8000, /// ditto 40 CTRL = LCTRL | RCTRL, /// ditto 41 SHIFT = LSHIFT | RSHIFT, /// ditto 42 ALT = LALT | RALT, /// ditto 43 META = LMETA | RMETA /// ditto 44 }; 45 46 /// 47 enum MouseButton 48 { LEFT=1, /// Allowed values. 49 CENTER, /// ditto 50 RIGHT, /// ditto 51 WHEEL_UP, /// ditto 52 WHEEL_DOWN, /// ditto 53 FOUR, /// ditto 54 FIVE, /// ditto 55 SIX, /// ditto 56 SEVEN, /// ditto 57 EIGHT /// ditto 58 } 59 25 60 public static int KEY_DELAY = 500; /// milliseconds before repeating a call to keyPress after holding a key down. 26 61 public static int KEY_REPEAT = 30; /// milliseconds before subsequent calls to keyPress after KEY_DELAY occurs. 27 62 28 protected static Vec2i mouse; // The current pixel location of the mouse cursor; (0, 0) is top left. 63 /// Position of the mouse and state of each button. 64 struct Mouse 65 { Vec2i position; /// 66 bool left; /// ditto 67 bool center; /// ditto 68 bool right; /// ditto 69 bool four; /// ditto 70 bool five; /// ditto 71 bool six; /// ditto 72 bool seven; /// ditto 73 bool eight; /// ditto 74 75 /// 76 char[] toString() 77 { return position.toString() ~ (left?"L":"") ~ (center?"C":"") ~ (right?"R":"") ~ (four?"4":"") ~ 78 (five?"5":"") ~ (six?"6":"") ~ (seven?"7":"") ~ (eight?"8":""); 79 } 80 81 // used internally 82 private void fromMouseButton(ushort mouseButton, bool state) 83 { switch (mouseButton) 84 { case MouseButton.LEFT: left=state; break; 85 case MouseButton.CENTER: center=state; break; 86 case MouseButton.RIGHT: right=state; break; 87 case MouseButton.FOUR: four=state; break; 88 case MouseButton.FIVE: five=state; break; 89 case MouseButton.SIX: six=state; break; 90 case MouseButton.SEVEN: seven=state; break; 91 case MouseButton.EIGHT: eight=state; break; 92 default: break; 93 } } 94 95 } 96 static Mouse mouse; /// Stores the current state of the mouse. 97 98 //protected static ubyte mouseButtons; /// A bitmask of MouseButton for the current state of the mouse buttons. 99 100 //protected static Vec2i mouse; // The current pixel location of the mouse cursor; (0, 0) is top left. 29 101 protected static Surface currentSurface; // Surface that the mouse is currently over 30 102 … … 37 109 static void processAndSendTo(Surface surface) 38 110 { 111 assert(surface); 39 112 40 113 SDL_EnableUNICODE(1); … … 48 121 // Keyboard 49 122 case SDL_KEYDOWN: 50 if(focus) // keysym.sym gets all keys on the keyboard, including separate keys for numpad, keysym.unicde should be reserved for text.51 { focus.keyDown(event.key.keysym.sym, event.key.keysym.mod);52 123 53 // Kepress will be called with the key repeat settings. 54 focus.keyPress(event.key.keysym.sym, event.key.keysym.mod, event.key.keysym.unicode); 55 lastKeyDown = event.key.keysym; 56 lastKeyDownTime = clock()*1000 / CLOCKS_PER_SEC; 57 } 124 // keysym.sym gets all keys on the keyboard, including separate keys for numpad, keysym.unicde should be reserved for text. 125 focus.keyDown(event.key.keysym.sym, event.key.keysym.mod); 126 127 // Kepress will be called with the key repeat settings. 128 focus.keyPress(event.key.keysym.sym, event.key.keysym.mod, event.key.keysym.unicode); 129 lastKeyDown = event.key.keysym; 130 lastKeyDownTime = clock()*1000 / CLOCKS_PER_SEC; 131 58 132 break; 59 133 case SDL_KEYUP: 60 if(focus) 61 focus.keyUp(event.key.keysym.sym, event.key.keysym.mod); 134 focus.keyUp(event.key.keysym.sym, event.key.keysym.mod); 62 135 if (event.key.keysym.sym==lastKeyDown.sym) // if the same key we're repeating 63 136 lastKeyDownTime = uint.max; // stop repeating … … 66 139 // Mouse 67 140 case SDL_MOUSEBUTTONDOWN: 141 mouse.fromMouseButton(event.button.button, true); // set 68 142 auto over = getMouseSurface(surface); 69 143 if(over) 70 over.mouseDown(event.button.button, mouse); 144 { 145 Vec2i localMouse = currentSurface.parentToLocal(mouse.position.toFloat()).toInt(); 146 over.mouseDown(cast(MouseButton)event.button.button, localMouse); 147 } 71 148 72 149 break; 73 150 case SDL_MOUSEBUTTONUP: 151 mouse.fromMouseButton(event.button.button, false); // clear 74 152 auto over = getMouseSurface(surface); 75 153 if(over) 76 over.mouseUp(event.button.button, mouse); 154 { Vec2i localMouse = currentSurface.globalToLocal(mouse.position.toFloat()).toInt(); 155 over.mouseUp(cast(MouseButton)event.button.button, localMouse); 156 } 77 157 78 158 break; 79 159 case SDL_MOUSEMOTION: 80 mouse. x = event.motion.x;81 mouse. y = event.motion.y;160 mouse.position.x = event.motion.x; 161 mouse.position.y = event.motion.y; 82 162 83 163 // Doing this before getMouseSurface() fixes the mouse leaving the surface while dragging. 84 164 if(currentSurface) 85 currentSurface.mouseMove(event.button.button, Vec2i(event.motion.xrel, event.motion.yrel)); 165 { if (currentSurface !is Surface.getGrabbedSurface()) 166 { Vec2i localMouse = currentSurface.globalToLocal(mouse.position.toFloat()).toInt(); 167 currentSurface.mouseX = localMouse.x; 168 currentSurface.mouseY = localMouse.y; 169 } 170 currentSurface.mouseMove(Vec2i(event.motion.xrel, event.motion.yrel)); 171 } 86 172 87 173 // If the surface that the mouse is in has changed … … 90 176 { 91 177 if(currentSurface) //Tell it that the mouse left 92 currentSurface.mouseOut(over , event.button.button, mouse);93 if(over) // Tell it that the mouse entered94 over.mouseOver( event.button.button, mouse);178 currentSurface.mouseOut(over); 179 if(over) // Tell it that the mouse entered 180 over.mouseOver(); 95 181 96 182 currentSurface = over; //The new current surface … … 116 202 // Key repeat 117 203 if (focus) 118 { 119 uint now = clock()*1000/CLOCKS_PER_SEC; // time in milliseconds 204 { uint now = clock()*1000/CLOCKS_PER_SEC; // time in milliseconds 120 205 if (now - KEY_DELAY > lastKeyDownTime) 121 206 { focus.keyPress(lastKeyDown.sym, lastKeyDown.mod, lastKeyDown.unicode); … … 130 215 if(Surface.getGrabbedSurface()) 131 216 return Surface.getGrabbedSurface(); 132 return surface.findSurface(mouse. x, mouse.y);217 return surface.findSurface(mouse.position); 133 218 } 134 219
