1--------------------- 2-- "KhiCAS" : TI-Nspire Giac UI in Nspire-Lua 3-- Version 1.05 - 18/06/2014 4-- GPL v3 License 5-- http://tiplanet.org/forum/viewtopic.php?f=43&t=14800 6--------------------- 7-- Giac CAS engine by Bernard Parisse 8-- http://www-fourier.ujf-grenoble.fr/~parisse/ 9--------------------- 10-- The UI is highly based on Xavier 'critor' Andréani's "SuperSpire" 11-- See http://tiplanet.org/forum/viewtopic.php?t=13851&p=157015 12------------------- 13-- ETK GUI Lib by Jim Bauwens and Adrien "Adriweb" Bertrand 14-- Additions/mods by Xavier 15-- some more little changes by Adrien 16-- (borders, horiz. lines, readonly, copy/paste, errHandler etc.) 17------------------- 18 19platform.apilevel = '2.0' 20 21hasGiac = pcall(nrequire, "luagiac") 22if not hasGiac then 23 luagiac = { caseval = function(str) return math.evalStr(str) end } 24 print("Giac module not loaded ! Fallback on Nspire's math engine.") 25end 26 27-- localized useful functions 28 29local mathmin = math.min 30local mathmax = math.max 31local mathrandom = math.random 32 33ts = 0.0 34 35 36-- ETK Stuff 37 38--------------------------------------------------------------------- View: Widgets & Events manager 39 40defaultFocus = nil 41 42View = class() 43 44function View:init(window) 45 self.window = window 46 self.widgetList = {} 47 self.focusList = {} 48 self.currentFocus = 0 49 self.currentCursor = "default" 50 51 -- Previous location of mouse pointer 52 self.prev_mousex = 0 53 self.prev_mousey = 0 54end 55 56 57function View:invalidate() 58 self.window:invalidate() 59end 60 61function View:setCursor(cursor) 62 if cursor ~= self.currentCursor then 63 self.currentCursor = cursor 64 self:invalidate() 65 end 66end 67 68 69function View:add(o) 70 table.insert(self.widgetList, o) 71 self:repos(o) 72 if o.acceptsFocus then 73 table.insert(self.focusList, 1, o) 74 if self.currentFocus > 0 then 75 self.currentFocus = self.currentFocus + 1 76 end 77 end 78 return o 79end 80 81function View:remove(o) 82 if self:getFocus() == o then 83 o:releaseFocus() 84 end 85 local i = 1 86 local f = 0 87 local oldf 88 while i <= #self.focusList do 89 if self.focusList[i] == o then 90 f = i 91 end 92 i = i + 1 93 end 94 if f > 0 then 95 if self:getFocus() == o then 96 self:tabForward() 97 end 98 table.remove(self.focusList, f) 99 if self.currentFocus > f then 100 self.currentFocus = self.currentFocus - 1 101 end 102 end 103 f = 0 104 i = 1 105 while i <= #self.widgetList do 106 if self.widgetList[i] == o then 107 f = i 108 end 109 i = i + 1 110 end 111 if f > 0 then 112 table.remove(self.widgetList, f) 113 end 114 -- table.remove(self.widgetList, o) 115 -- table.remove(self.focusList, o) 116end 117 118function View:repos(o) 119 local x = o.x 120 local y = o.y 121 local w = o.w 122 local h = o.h 123 if o.hConstraint == "right" then 124 x = scrWidth - o.w - o.dx1 125 elseif o.hConstraint == "center" then 126 x = (scrWidth - o.w + o.dx1) / 2 127 elseif o.hConstraint == "justify" then 128 w = scrWidth - o.x - o.dx1 129 end 130 if o.vConstraint == "bottom" then 131 y = scrHeight - o.h - o.dy1 132 elseif o.vConstraint == "middle" then 133 y = (scrHeight - o.h + o.dy1) / 2 134 elseif o.vConstraint == "justify" then 135 h = scrHeight - o.y - o.dy1 136 end 137 o:repos(x, y) 138 o:resize(w, h) 139end 140 141function View:resize() 142 for _, o in ipairs(self.widgetList) do 143 self:repos(o) 144 end 145end 146 147function View:hide(o) 148 if o.visible then 149 o.visible = false 150 self:releaseFocus(o) 151 if o:contains(self.prev_mousex, self.prev_mousey) then 152 o:onMouseLeave(o.x - 1, o.y - 1) 153 end 154 self:invalidate() 155 end 156end 157 158function View:show(o) 159 if not o.visible then 160 o.visible = true 161 if o:contains(self.prev_mousex, self.prev_mousey) then 162 o:onMouseEnter(self.prev_mousex, self.prev_mousey) 163 end 164 self:invalidate() 165 end 166end 167 168function View:getFocus() 169 if self.currentFocus == 0 then 170 return nil 171 end 172 return self.focusList[self.currentFocus] 173end 174 175function View:setFocus(obj) 176 if self.currentFocus ~= 0 then 177 if self.focusList[self.currentFocus] == obj then 178 return 179 end 180 self.focusList[self.currentFocus]:releaseFocus() 181 end 182 self.currentFocus = 0 183 for i = 1, #self.focusList do 184 if self.focusList[i] == obj then 185 self.currentFocus = i 186 obj:setFocus() 187 self:invalidate() 188 break 189 end 190 end 191end 192 193function View:releaseFocus(obj) 194 if self.currentFocus ~= 0 then 195 if self.focusList[self.currentFocus] == obj then 196 self.currentFocus = 0 197 obj:releaseFocus() 198 self:invalidate() 199 end 200 end 201end 202 203function View:sendStringToFocus(str) 204 local o = self:getFocus() 205 if not o then 206 o = defaultFocus 207 self:setFocus(o) 208 end 209 if o then 210 if o.visible then 211 if o:addString(str) then 212 self:invalidate() 213 else 214 o = nil 215 end 216 end 217 end 218 219 if not o then -- look for a default handler 220 for _, o in ipairs(self.focusList) do 221 if o.visible then 222 if o:addString(str) then 223 self:setFocus(o) 224 self:invalidate() 225 break 226 end 227 end 228 end 229 end 230end 231 232 233function View:backSpaceHandler() 234 -- Does the focused widget accept BackSpace? 235 local o = self:getFocus() 236 if o then 237 if o.visible and o.acceptsBackSpace then 238 o:backSpaceHandler() 239 self:setFocus(o) 240 self:invalidate() 241 else 242 o = nil 243 end 244 end 245 if not o then -- look for a default handler 246 for _, o in ipairs(self.focusList) do 247 if o.visible and o.acceptsBackSpace then 248 o:backSpaceHandler() 249 self:setFocus(o) 250 self:invalidate() 251 break; 252 end 253 end 254 end 255end 256 257 258function View:tabForward() 259 local nextFocus = self.currentFocus + 1 260 if nextFocus > #self.focusList then 261 nextFocus = 1 262 end 263 self:setFocus(self.focusList[nextFocus]) 264 if self:getFocus() then 265 if not self:getFocus().visible then 266 self:tabForward() 267 end 268 end 269 self:invalidate() 270end 271 272 273function View:tabBackward() 274 local nextFocus = self.currentFocus - 1 275 if nextFocus < 1 then 276 nextFocus = #self.focusList 277 end 278 self:setFocus(self.focusList[nextFocus]) 279 if not self:getFocus().visible then 280 self:tabBackward() 281 end 282 self:invalidate() 283end 284 285 286function View:onMouseDown(x, y) 287 -- Find a widget that has a mouse down handler and bounds the click point 288 for _, o in ipairs(self.widgetList) do 289 if o.visible and o.acceptsFocus and o:contains(x, y) then 290 self.mouseCaptured = o 291 o:onMouseDown(o, window, x - o.x, y - o.y) 292 self:setFocus(o) 293 self:invalidate() 294 return 295 end 296 end 297 if self:getFocus() then 298 self:setFocus(nil) 299 self:invalidate() 300 end 301end 302 303 304function View:onMouseMove(x, y) 305 local prev_mousex = self.prev_mousex 306 local prev_mousey = self.prev_mousey 307 for _, o in ipairs(self.widgetList) do 308 local xyin = o:contains(x, y) 309 local prev_xyin = o:contains(prev_mousex, prev_mousey) 310 if xyin and not prev_xyin and o.visible then 311 -- Mouse entered widget 312 o:onMouseEnter(x, y) 313 self:invalidate() 314 elseif prev_xyin and (not xyin or not o.visible) then 315 -- Mouse left widget 316 o:onMouseLeave(x, y) 317 self:invalidate() 318 end 319 end 320 self.prev_mousex = x 321 self.prev_mousey = y 322end 323 324 325function View:onMouseUp(x, y) 326 local mc = self.mouseCaptured 327 if mc then 328 self.mouseCaptured = nil 329 if mc:contains(x, y) then 330 mc:onMouseUp(x - mc.x, y - mc.y) 331 else 332 -- mc:cancelClick() 333 end 334 end 335end 336 337 338function View:enterHandler() 339 -- Does the focused widget accept Enter? 340 local o = self:getFocus() 341 if o then 342 if o.visible and o.acceptsEnter then 343 o:enterHandler() 344 self:setFocus(o) 345 self:invalidate() 346 else 347 o = nil 348 end 349 end 350 if not o then -- look for a default handler 351 for _, o in ipairs(self.focusList) do 352 if o.visible and o.acceptsEnter then 353 o:enterHandler() 354 self:setFocus(o) 355 self:invalidate() 356 break; 357 end 358 end 359 end 360end 361 362function View:arrowLeftHandler() 363 -- Does the focused widget accept ArrowLeft? 364 local o = self:getFocus() 365 if o then 366 if o.visible and o.acceptsArrowLeft then 367 o:arrowLeftHandler() 368 self:setFocus(o) 369 self:invalidate() 370 else 371 o = nil 372 end 373 end 374 if not o then -- look for a default handler 375 for _, o in ipairs(self.focusList) do 376 if o.visible and o.acceptsArrowLeft then 377 o:arrowLeftHandler() 378 self:setFocus(o) 379 self:invalidate() 380 break; 381 end 382 end 383 end 384end 385 386function View:arrowRightHandler() 387 -- Does the focused widget accept ArrowRight? 388 local o = self:getFocus() 389 if o then 390 if o.visible and o.acceptsArrowRight then 391 o:arrowRightHandler() 392 self:setFocus(o) 393 self:invalidate() 394 else 395 o = nil 396 end 397 end 398 if not o then -- look for a default handler 399 for _, o in ipairs(self.focusList) do 400 if o.visible and o.acceptsArrowRight then 401 o:arrowRightHandler() 402 self:setFocus(o) 403 self:invalidate() 404 break; 405 end 406 end 407 end 408end 409 410function View:arrowUpHandler() 411 -- Does the focused widget accept ArrowUp? 412 local o = self:getFocus() 413 if o then 414 if o.visible and o.acceptsArrowUp then 415 o:arrowUpHandler() 416 self:setFocus(o) 417 self:invalidate() 418 else 419 o = nil 420 end 421 end 422 if not o then -- look for a default handler 423 for _, o in ipairs(self.focusList) do 424 if o.visible and o.acceptsArrowUp then 425 o:arrowUpHandler() 426 self:setFocus(o) 427 self:invalidate() 428 break; 429 end 430 end 431 end 432end 433 434function View:arrowDownHandler() 435 -- Does the focused widget accept ArrowDown? 436 local o = self:getFocus() 437 if o then 438 if o.visible and o.acceptsArrowDown then 439 o:arrowDownHandler() 440 self:setFocus(o) 441 self:invalidate() 442 else 443 o = nil 444 end 445 end 446 if not o then -- look for a default handler 447 for _, o in ipairs(self.focusList) do 448 if o.visible and o.acceptsArrowDown then 449 o:arrowDownHandler() 450 self:setFocus(o) 451 self:invalidate() 452 break; 453 end 454 end 455 end 456end 457 458function View:paint(gc) 459 local fo = self:getFocus() 460 for _, o in ipairs(self.widgetList) do 461 if o.visible then 462 o:paint(gc, fo == o) 463 if fo == o then 464 gc:setColorRGB(100, 150, 255) 465 gc:drawRect(o.x - 1, o.y - 1, o.w + 1, o.h + 1) 466 gc:setPen("thin", "smooth") 467 gc:setColorRGB(0) 468 end 469 end 470 end 471 cursor.set(self.currentCursor) 472end 473 474theView = nil 475 476--------------------------------------------------------------------- Widget 477 478Widget = class() 479 480function Widget:setHConstraints(hConstraint, dx1) 481 self.hConstraint = hConstraint 482 self.dx1 = dx1 483end 484 485function Widget:setVConstraints(vConstraint, dy1) 486 self.vConstraint = vConstraint 487 self.dy1 = dy1 488end 489 490function Widget:init(view, x, y, w, h) 491 self.xOrig = x 492 self.yOrig = y 493 self.view = view 494 self.x = x 495 self.y = y 496 self.w = w 497 self.h = h 498 self.acceptsFocus = false 499 self.visible = true 500 self.acceptsEnter = false 501 self.acceptsEscape = false 502 self.acceptsTab = false 503 self.acceptsDelete = false 504 self.acceptsBackSpace = false 505 self.acceptsReturn = false 506 self.acceptsArrowUp = false 507 self.acceptsArrowDown = false 508 self.acceptsArrowLeft = false 509 self.acceptsArrowRight = false 510 self.hConstraint = "left" 511 self.vConstraint = "top" 512end 513 514function Widget:repos(x, y) 515 self.x = x 516 self.y = y 517end 518 519function Widget:resize(w, h) 520 self.w = w 521 self.h = h 522end 523 524function Widget:setFocus() 525end 526 527function Widget:releaseFocus() 528end 529 530function Widget:contains(x, y) 531 return x >= self.x and x <= self.x + self.w 532 and y >= self.y and y <= self.y + self.h 533end 534 535 536function Widget:onMouseEnter(x, y) 537 -- Implemented in subclasses 538end 539 540 541function Widget:onMouseLeave(x, y) 542 -- Implemented in subclasses 543end 544 545function Widget:paint(gc, focused) 546 -- Implemented in subclasses 547end 548 549function Widget:enterHandler() 550end 551 552function Widget:escapeHandler() 553end 554 555function Widget:tabHandler() 556end 557 558function Widget:deleteHandler() 559end 560 561function Widget:backSpaceHandler() 562end 563 564function Widget:returnHandler() 565end 566 567function Widget:arrowUpHandler() 568end 569 570function Widget:arrowDownHandler() 571end 572 573function Widget:arrowLeftHandler() 574end 575 576function Widget:arrowRightHandler() 577end 578 579function Widget:onMouseDown(x, y) 580end 581 582function Widget:onMouseUp(x, y) 583end 584 585--------------------------------------------------------------------- Button widget 586 587Button = class(Widget) 588 589function Button:init(view, x, y, w, h, default, command, shortcut) 590 Widget.init(self, view, x, y, w, h) 591 -- Button configuration 592 self.acceptsFocus = true 593 self.acceptsBackspace = false 594 self.command = command or function() end -- what to do when pressed 595 self.default = default -- is default button when ENTER is pressed 596 self.shortcut = shortcut 597 -- Current button state 598 self.clicked = false 599 self.highlighted = false 600 self.acceptsEnter = true 601end 602 603-- Act on key press on button 604function Button:enterHandler() 605 if self.acceptsEnter then 606 self:command() 607 end 608end 609 610function Button:escapeHandler() 611 if self.acceptsEscape then 612 self:command() 613 end 614end 615 616function Button:tabHandler() 617 if self.acceptsTab then 618 self:command() 619 end 620end 621 622function Button:deleteHandler() 623 if self.acceptsDelete then 624 self:command() 625 end 626end 627 628function Button:backSpaceHandler() 629 if self.acceptsBackSpace then 630 self:command() 631 end 632end 633 634function Button:returnHandler() 635 if self.acceptsReturn then 636 self:command() 637 end 638end 639 640function Button:arrowUpHandler() 641 if self.acceptsArrowUp then 642 self:command() 643 end 644end 645 646function Button:arrowDownHandler() 647 if self.acceptsArrowDown then 648 self:command() 649 end 650end 651 652function Button:arrowLeftHandler() 653 if self.acceptsArrowLeft then 654 self:command() 655 end 656end 657 658function Button:arrowRightHandler() 659 if self.acceptsArrowRight then 660 self:command() 661 end 662end 663 664function Button:arrowUpHandler() 665 if self.acceptsArrowUp then 666 self:command() 667 end 668end 669 670function Button:arrowDownHandler() 671 if self.acceptsArrowDown then 672 self:command() 673 end 674end 675 676function Button:onMouseDown(x, y) 677 self.clicked = true 678 self.highlighted = true 679end 680 681function Button:onMouseEnter(x, y) 682 theView:setCursor("hand pointer") 683 if self.clicked and not self.highlighted then 684 self.highlighted = true 685 end 686end 687 688function Button:onMouseLeave(x, y) 689 theView:setCursor("default") 690 if self.clicked and self.highlighted then 691 self.highlighted = false 692 end 693end 694 695function Button:cancelClick() 696 if self.clicked then 697 self.highlighted = false 698 self.clicked = false 699 end 700end 701 702function Button:onMouseUp(x, y) 703 self:cancelClick() 704 self:command() 705end 706 707function Button:addString(str) 708 if str == " " or str == self.shortcut then 709 self:command() 710 return true 711 end 712 return false 713end 714 715--------------------------------------------------------------------- ImgLabel widget 716 717ImgLabel = class(Widget) 718 719function ImgLabel:init(view, x, y, img) 720 self.img = image.new(img) 721 self.w = image.width(self.img) 722 self.h = image.height(self.img) 723 Widget.init(self, view, x, y, self.w, self.h, false, command, shortcut) 724end 725 726function ImgLabel:paint(gc, focused) 727 gc:drawImage(self.img, self.x, self.y) 728end 729 730--------------------------------------------------------------------- ImgButton widget 731 732ImgButton = class(Button) 733 734function ImgButton:init(view, x, y, img, command, shortcut) 735 self.img = image.new(img) 736 self.w = image.width(self.img) 737 self.h = image.height(self.img) 738 Button.init(self, view, x, y, self.w, self.h, false, command, shortcut) 739end 740 741function ImgButton:paint(gc, focused) 742 gc:drawImage(self.img, self.x, self.y) 743end 744 745--------------------------------------------------------------------- TextButton widget 746 747TextButton = class(Button) 748 749function TextButton:init(view, x, y, text, command, shortcut) 750 self.textid = text 751 self.text = getLocaleText(text) 752 self:resize(0, 0) 753 Button.init(self, view, x, y, self.w, self.h, false, command, shortcut) 754end 755 756function TextButton:resize(w, h) 757 self.text = getLocaleText(self.textid) 758 self.w = getStringWidth(self.text) + 5 759 self.h = getStringHeight(self.text) + 5 760end 761 762 763function TextButton:paint(gc, focused) 764 gc:setColorRGB(223, 223, 223) 765 gc:drawRect(self.x + 1, self.y + 1, self.w - 2, self.h - 2) 766 gc:setColorRGB(191, 191, 191) 767 gc:fillRect(self.x + 1, self.y + 1, self.w - 3, self.h - 3) 768 gc:setColorRGB(223, 223, 223) 769 gc:drawString(self.text, self.x + 3, self.y + 3, "top") 770 gc:setColorRGB(0) 771 gc:drawString(self.text, self.x + 2, self.y + 2, "top") 772 gc:drawRect(self.x, self.y, self.w - 2, self.h - 2) 773end 774 775--------------------------------------------------------------------- vertical scroll bar 776VScrollBar = class(Widget) 777 778function VScrollBar:init(view, x, y, w, h) 779 self.pos = 10 780 self.siz = 10 781 Widget.init(self, view, x, y, w, h, false) 782end 783 784function VScrollBar:paint(gc, focused) 785 gc:setColorRGB(0) 786 gc:drawRect(self.x, self.y, self.w, self.h) 787 gc:fillRect(self.x + 2, self.y + self.h - (self.h - 4) * (self.pos + self.siz) / 100 - 2, self.w - 3, mathmax(1, (self.h - 4) * self.siz / 100 + 1)) 788end 789 790--------------------------------------------------------------------- Text widget 791 792TextLabel = class(Widget) 793 794function TextLabel:init(view, x, y, text) 795 self:setText(text) 796 Widget.init(self, view, x, y, self.w, self.h, false) 797end 798 799function TextLabel:resize(w, h) 800 self.text = getLocaleText(self.textid) 801 self.w = getStringWidth(self.text) 802 self.h = getStringHeight(self.text) 803end 804 805function TextLabel:setText(text) 806 self.textid = text 807 self.text = getLocaleText(text) 808 self:resize(0, 0) 809end 810 811function TextLabel:getText() 812 return self.text 813end 814 815function TextLabel:paint(gc, focused) 816 gc:setColorRGB(0) 817 gc:drawString(self.text, self.x, self.y, "top") 818end 819 820--------------------------------------------------------------------- editable RichText widget 821 822RichTextEditor = class(Widget) 823 824function RichTextEditor:init(view, x, y, w, h, text) 825 self.editor = D2Editor.newRichText() 826 self.readOnly = false 827 self:repos(x, y) 828 self.editor:setFontSize(fsize) 829 self.editor:setFocus(false) 830 self.text = text 831 self:resize(w, h) 832 Widget.init(self, view, x, y, self.w, self.h, true) 833 self.acceptsFocus = true 834 self.editor:setExpression(text) 835 self.editor:setBorder(1) 836end 837 838function RichTextEditor:onMouseEnter(x, y) 839 theView:setCursor("text") 840end 841 842function RichTextEditor:onMouseLeave(x, y) 843 theView:setCursor("default") 844end 845 846function RichTextEditor:repos(x, y) 847 if not self.editor then self = nil; return; end 848 self.editor:setBorderColor((showEditorsBorders and 0) or 0xffffff) 849 self.editor:move(x+1, y+1) 850 Widget.repos(self, x, y) 851end 852 853function RichTextEditor:resize(w, h) 854 if not self.editor then self = nil; return; end 855 self.editor:resize(w-1, h-1) 856 Widget.resize(self, w, h) 857end 858 859function RichTextEditor:setFocus() 860 self.editor:setFocus(true) 861end 862 863function RichTextEditor:releaseFocus() 864 self.editor:setFocus(false) 865end 866 867function RichTextEditor:addString(str) 868 local currentText = self.editor:getText() or "" 869 self.editor:setText(currentText .. str) 870 return true 871end 872 873 874function RichTextEditor:paint(gc, focused) 875 -- self.editor:paint(gc) 876end 877 878--------------------------------------------------------------------- editable Math widget 879 880MathEditor = class(RichTextEditor) 881 882-- pretty printed square root characters from MathBoxes take two 'special' characters in returned expression string 883-- cursor position in expression returned by getExpression() then does not match cursor position in string after the square root 884function string.ulen(s) 885 if not s then return 0 else return select(2, s:gsub("[^\128-\193]", "")) end 886end 887ulen = string.ulen 888 889function MathEditor:init(view, x, y, w, h, text) 890 RichTextEditor.init(self, view, x, y, w, h, text) 891 self.editor:setBorder(1) 892 self.acceptsEnter = true 893 self.acceptsBackSpace = true 894 self.result = false 895 -- add editor focus listener which does: setFocus(getME(editor)) 896 self.editor:registerFilter({ 897 arrowLeft = function() 898 local _, curpos = self.editor:getExpressionSelection() 899 if curpos < 7 then 900 on.arrowLeft() 901 return true 902 end 903 return false 904 end, 905 arrowRight = function() 906 local currentText, curpos = self.editor:getExpressionSelection() 907 if curpos > ulen(currentText) - 2 then 908 on.arrowRight() 909 return true 910 end 911 return false 912 end, 913 tabKey = function() 914 theView:tabForward() 915 return true 916 end, 917 mouseDown = function(x, y) 918 theView:onMouseDown(x, y) 919 return false 920 end, 921 backspaceKey = function() 922 if (self == fctEditor) then 923 self:fixCursor() 924 local _, curpos = self.editor:getExpressionSelection() 925 if curpos <= 6 then return true end 926 return false 927 else 928 self:backSpaceHandler() 929 return true 930 end 931 end, 932 deleteKey = function() 933 if (self == fctEditor) then 934 self:fixCursor() 935 local currentText, curpos = self.editor:getExpressionSelection() 936 if curpos >= ulen(currentText) - 1 then return true end 937 return false 938 else 939 self:backSpaceHandler() 940 return true 941 end 942 end, 943 enterKey = function() 944 self:enterHandler() 945 return true 946 end, 947 returnKey = function() 948 theView:enterHandler() 949 return true 950 end, 951 escapeKey = function() 952 on.escapeKey() 953 return true 954 end, 955 clearKey = function() 956 if self == fctEditor then 957 self.editor:setExpression("") 958 self:fixContent() 959 else 960 self:backSpaceHandler() 961 end 962 return true 963 end, 964 charIn = function(c) 965 if (self == fctEditor) then 966 if self.editor:getExpression() then 967 self:fixCursor() 968 end 969 return false 970 else 971 return self.readOnly 972 end 973 end 974 }) 975end 976 977function MathEditor:fixContent() 978 local currentText = self.editor:getExpressionSelection() 979 if not currentText or currentText == "" then 980 self.editor:createMathBox() 981 end 982end 983 984function MathEditor:fixCursor() 985 local currentText, curpos, selstart = self.editor:getExpressionSelection() 986 local l = ulen(currentText) 987 if curpos < 6 or selstart < 6 or curpos > l - 1 or selstart > l - 1 then 988 if curpos < 6 then curpos = 6 end 989 if selstart < 6 then selstart = 6 end 990 if curpos > l - 1 then curpos = l - 1 end 991 if selstart > l - 1 then selstart = l - 1 end 992 self.editor:setExpression(currentText, curpos, selstart) 993 end 994end 995 996function MathEditor:getExpression() 997 if not self.editor then self = nil; return ""; end 998 local rawexpr = self.editor:getExpression() 999 local expr = "" 1000 local n = rawexpr:len() 1001 local b = 0 1002 local bs = 0 1003 local bi = 0 1004 local status = 0 1005 local i = 1 1006 local c 1007 while i <= n do 1008 c = rawexpr:sub(i, i) 1009 if c == "{" then 1010 b = b + 1 1011 elseif c == "}" then 1012 b = b - 1 1013 end 1014 if status == 0 then 1015 if rawexpr:sub(i, i + 5) == "\\0el {" then 1016 bs = i + 6 1017 i = i + 5 1018 status = 1 1019 bi = b 1020 b = b + 1 1021 end 1022 else 1023 if b == bi then 1024 status = 0 1025 expr = expr .. rawexpr:sub(bs, i - 1) 1026 end 1027 end 1028 i = i + 1 1029 end 1030 return expr 1031end 1032 1033function MathEditor:setFocus() 1034 if not self.editor then self = nil; return; end 1035 self.editor:setFocus(true) 1036end 1037 1038function MathEditor:releaseFocus() 1039 if not self.editor then self = nil; return; end 1040 self.editor:setFocus(false) 1041end 1042 1043function MathEditor:addString(str) 1044 if not self.editor then self = nil; return; end 1045 self:fixCursor() 1046 local currentText, curpos, selstart = self.editor:getExpressionSelection() 1047 currentText = currentText:usub(1, mathmin(curpos, selstart)) .. str .. currentText:usub(mathmax(curpos, selstart) + 1, ulen(currentText)) 1048 self.editor:setExpression(currentText, mathmin(curpos, selstart) + ulen(str)) 1049 return true 1050end 1051 1052function MathEditor:backSpaceHandler() 1053 backSpaceHandler(self) 1054end 1055 1056function MathEditor:enterHandler() 1057 enterHandler(self) 1058end 1059 1060function MathEditor:paint(gc) 1061 if not self.editor then self = nil; return; end 1062 if showHLines and not self.result then 1063 gc:setColorRGB(100, 100, 100) 1064 local ycoord = self.y - (showEditorsBorders and 0 or 2) 1065 gc:drawLine(1, ycoord, platform.window:width() - sbv.w - 2, ycoord) 1066 gc:setColorRGB(0) 1067 end 1068end 1069 1070--------------------------------------------------------------------- events handling 1071function on.arrowUp() 1072 if theView:getFocus() == fctEditor then 1073 on.tabKey() 1074 else 1075 on.tabKey() 1076 if theView:getFocus() ~= fctEditor then on.tabKey() end 1077 end 1078 reposView() 1079end 1080 1081function on.arrowDown() 1082 if theView:getFocus() == fctEditor then return end 1083 on.backtabKey() 1084 if theView:getFocus() ~= fctEditor then on.backtabKey() end 1085 reposView() 1086end 1087 1088function on.arrowLeft() 1089 if theView:getFocus() == fctEditor then return end 1090 on.tabKey() 1091 reposView() 1092end 1093 1094function on.arrowRight() 1095 if theView:getFocus() == fctEditor then return end 1096 on.backtabKey() 1097 reposView() 1098end 1099 1100function on.charIn(ch) 1101 theView:sendStringToFocus(ch) 1102end 1103 1104function on.tabKey() 1105 theView:tabForward() 1106 reposView() 1107end 1108 1109function on.backtabKey() 1110 theView:tabBackward() 1111 reposView() 1112end 1113 1114function on.escapeKey() 1115 -- nothing to do ? 1116end 1117 1118function on.enterKey() 1119 theView:enterHandler() 1120end 1121on.returnKey = on.enterKey 1122 1123function on.mouseMove(x, y) 1124 theView:onMouseMove(x, y) 1125end 1126 1127function on.mouseDown(x, y) 1128 theView:onMouseDown(x, y) 1129 -- theView:invalidate() 1130end 1131 1132function on.mouseUp(x, y) 1133 theView:onMouseUp(x, y) 1134end 1135 1136function initFontGC(gc) 1137 gc:setFont(font, style, fsize) 1138end 1139 1140function getStringHeightGC(text, gc) 1141 initFontGC(gc) 1142 return gc:getStringHeight(text) 1143end 1144 1145function getStringHeight(text) 1146 return platform.withGC(getStringHeightGC, text) 1147end 1148 1149function getStringWidthGC(text, gc) 1150 initFontGC(gc) 1151 return gc:getStringWidth(text) 1152end 1153 1154function getStringWidth(text) 1155 return platform.withGC(getStringWidthGC, text) 1156end 1157 1158function initGUI() 1159 showEditorsBorders = false 1160 showHLines = true 1161 scrWidth = platform.window:width() 1162 scrHeight = platform.window:height() 1163 if (scrWidth > 0 or scrHeight > 0) then 1164 theView = View(platform.window) 1165 sbv = VScrollBar(theView, 0, -1, 5, scrHeight + 1) 1166 sbv:setHConstraints("right", 0) 1167 theView:add(sbv) 1168 fctEditor = MathEditor(theView, 2, border, 50, 30, "") 1169 -- fctEditor = MathEditor(theView, border, border, 50, 30, "") 1170 fctEditor:setHConstraints("justify", 1) 1171 -- fctEditor:setHConstraints("justify", border + scrWidth - sbv.x) 1172 fctEditor:setVConstraints("bottom", 1) 1173 fctEditor.editor:setSizeChangeListener(function(editor, w, h) 1174 return resizeME(editor, w, h) 1175 end) 1176 theView:add(fctEditor) 1177 fctEditor.editor:setText("") 1178 fctEditor.editor:setBorder(0) 1179 fctEditor:fixContent() 1180 sbv:setVConstraints("justify", scrHeight - fctEditor.y + border) 1181 theView:setFocus(fctEditor) 1182 inited = true 1183 end 1184 toolpalette.enableCopy(true) 1185 toolpalette.enablePaste(true) 1186end 1187 1188function resizeGC(gc) 1189 scrWidth = platform.window:width() 1190 scrHeight = platform.window:height() 1191 if not inited then 1192 initGUI() 1193 end 1194 if inited then 1195 initFontGC(gc) 1196 strFullHeight = gc:getStringHeight("H") 1197 strHeight = strFullHeight - 3 1198 theView:resize() 1199 reposME() 1200 theView:invalidate() 1201 end 1202end 1203 1204function on.resize() 1205 platform.withGC(resizeGC) 1206end 1207 1208forcefocus = true 1209function on.activate() 1210 forcefocus = true 1211end 1212 1213dispinfos = true 1214function on.paint(gc) 1215 if not inited then 1216 initGUI() 1217 initFontGC(gc) 1218 strFullHeight = gc:getStringHeight("H") 1219 strHeight = strFullHeight - 3 1220 end 1221 if inited then 1222 local obj 1223 obj = theView:getFocus() 1224 initFontGC(gc) 1225 if not obj then theView:setFocus(fctEditor) end 1226 if (forcefocus) then 1227 if obj == fctEditor then 1228 fctEditor.editor:setFocus(true) 1229 if fctEditor.editor:hasFocus() then forcefocus = false end 1230 else 1231 forcefocus = false 1232 end 1233 end 1234 if dispinfos then 1235 gc:setColorRGB(0) 1236 gc:setFont("sansserif", "r", 10) 1237 gc:drawString("Giac CAS engine :", 2, 0, "top") 1238 if hasGiac then 1239 gc:setColorRGB(0, 127, 0) 1240 gc:drawString("OK.", gc:getStringWidth("Giac CAS engine :") + 6, 0, "top") 1241 gc:setColorRGB(0) 1242 gc:drawString("Giac (c) B. Parisse/R. De Graeve, license GPL3", 2, 1 * strHeight, "top") 1243 gc:drawString("Not allowed during exams if", 2, 2 * strHeight, "top") 1244 gc:drawString("CAS calculators are forbidden!", 2, 3 * strHeight, "top") 1245 gc:drawString("Type ?commandname for short help", 2, scrHeight/2-20, "top") 1246 gc:drawString("Beta version, report bugs/issues you encounter !", 2, scrHeight/2, "top") 1247 else 1248 gc:setColorRGB(255, 0, 0) 1249 gc:drawString("NO.", gc:getStringWidth("Giac CAS engine :") + 6, 0, "top") 1250 gc:setColorRGB(0) 1251 gc:drawString("Make sure to have the .luax file and Ndless installed!", 2, strHeight, "top") 1252 gc:drawString("Hint: run ndless_installer again", 2, 2 * strHeight, "top") 1253 gc:setFont("sansserif", "i", 10) 1254 gc:drawString("Fallback on the Nspire's math engine.", 2, 3 * strHeight + 8, "top") 1255 end 1256 gc:setFont("sansserif", "r", fsize) 1257 end 1258 theView:paint(gc) 1259 -- gc:drawString(ts, 2, 0, "top") 1260 gc:drawRect(0, fctEditor.y - 2, scrWidth, fctEditor.y - 2) 1261 end 1262end 1263 1264--------------------------------------------------------------------- global variables 1265 1266font = "sansserif" 1267style = "r" 1268fsize = 12 1269 1270scrWidth = 0 1271scrHeight = 0 1272inited = false 1273delim = " ≟ " 1274border = 3 1275 1276strHeight = 0 1277strFullHeight = 0 1278 1279--------------------------------------------------------------------- global functions 1280 1281evalstr = false 1282 1283histME1 = {} 1284histME2 = {} 1285 1286function addME(expr, res) 1287 local mee = MathEditor(theView, border, border, 50, 30, "") 1288 mee.readOnly = true 1289 table.insert(histME1, mee) 1290 mee:setHConstraints("left", border) 1291 mee.editor:setSizeChangeListener(function(editor, w, h) 1292 return resizeME(editor, w + 3, h) 1293 end) 1294 mee.editor:setExpression("\\0el {" .. expr .. "}", 0) 1295 mee:fixCursor() 1296 mee.editor:setReadOnly(true) 1297 theView:add(mee) 1298 1299 local mer = MathEditor(theView, border, border, 50, 30, "") 1300 mer.result = true 1301 mer.readOnly = true 1302 table.insert(histME2, mer) 1303 mer:setHConstraints("right", scrWidth - sbv.x + border) 1304 mer.editor:setSizeChangeListener(function(editor, w, h) 1305 return resizeMEpar(editor, w + border, h) 1306 end) 1307 mer.editor:setExpression("\\0el {" .. res .. "}", 0) 1308 mer:fixCursor() 1309 mer.editor:setReadOnly(true) 1310 theView:add(mer) 1311 reposME() 1312end 1313 1314limpsuff = "(+)" 1315limmsuff = "(-)" 1316function cleanAns1(expr) 1317 local a, b = expr:find(delim, 1, true) 1318 local c = 0 1319 local i = 1 1320 local l = string.len(expr) 1321 if a then 1322 c = expr:find(".", 1, true) 1323 if not c then c = 0 end 1324 if c == 0 or c > b then 1325 expr = expr:sub(1, a - 1) 1326 else 1327 expr = expr:sub(b + 1, l) 1328 end 1329 return cleanAns1(expr) 1330 end 1331 l = string.len(expr) 1332 a, b = expr:find(limpsuff, 1, true) 1333 if (not (a)) then 1334 a, b = expr:find(limmsuff, 1, true) 1335 else 1336 a = a - 2 1337 local texpr = "" 1338 if (a > 1) then texpr = expr:sub(1, a - 1) end 1339 if (b < l) then texpr = texpr .. expr:sub(b + 1, l) end 1340 expr = texpr 1341 end 1342 return expr 1343end 1344 1345function escapeStr(expr) 1346 local expr2 = "" 1347 local l = string.len(expr) 1348 local c 1349 for i = 1, l do 1350 c = expr:sub(i, i) 1351 if c == "\"" then 1352 c = "\\\"" 1353 end 1354 expr2 = expr2 .. c 1355 end 1356 return expr2 1357end 1358 1359function backSpaceHandler(widget) 1360 local i = 1 1361 local f = 0 1362 local n = mathmax(#histME1, #histME2) 1363 if (widget ~= fctEditor) then 1364 while (f == 0 and i <= n) do 1365 if histME1[i] == widget or histME2[i] == widget then 1366 f = i 1367 end 1368 i = i + 1 1369 end 1370 end 1371 if f > 0 then 1372 destroyD2Editor(histME1[f].editor) 1373 destroyD2Editor(histME2[f].editor) 1374 theView:remove(histME1[f]) 1375 theView:remove(histME2[f]) 1376 table.remove(histME1, f) 1377 table.remove(histME2, f) 1378 reposME() 1379 end 1380end 1381 1382function enterHandler(widget) 1383 local expr, exprkeep 1384 local svar 1385 local incerr = "incompatible data type" 1386 if (widget ~= fctEditor) then 1387 expr = cleanAns1(widget:getExpression()) 1388 theView:setFocus(fctEditor) 1389 fctEditor:addString(expr) 1390 else 1391 if (fctEditor.editor:getExpression()) then 1392 expr = fctEditor.editor:getExpression() 1393 expr = fctEditor:getExpression() 1394 if (expr and expr ~= "") then 1395 dispinfos = false 1396 t1 = timer.getMilliSecCounter() 1397 res = luagiac.caseval(expr) or "Error" 1398 t2 = timer.getMilliSecCounter() 1399 ts = string.format("Time : %f" , ( t2 - t1 ) / 1000. ) 1400 fctEditor.editor:setText("") 1401 fctEditor:fixContent() 1402 ioffset = 0 1403 1404 res = " " .. res 1405 expr = " " .. expr 1406 expr = expr:gsub("^%s+", " ") 1407 addME(expr, res) 1408 end 1409 end 1410 end 1411end 1412 1413function getParME(editor) 1414 for i = 1, #histME2 do 1415 if histME2[i].editor == editor then 1416 return histME1[i] 1417 end 1418 end 1419 return nil 1420end 1421 1422function getME(editor) 1423 if (fctEditor.editor == editor) then 1424 return fctEditor 1425 else 1426 for i = 1, #histME1 do 1427 if histME1[i].editor == editor then 1428 return histME1[i] 1429 end 1430 end 1431 for i = 1, #histME2 do 1432 if histME2[i].editor == editor then 1433 return histME2[i] 1434 end 1435 end 1436 end 1437 return nil 1438end 1439 1440function getMEindex(me) 1441 local ti 1442 if (fctEditor.editor == me) then 1443 return 0 1444 else 1445 ti = 0 1446 for i = #histME1, 1, -1 do 1447 if histME1[i] == me then 1448 return ti 1449 end 1450 ti = ti + 1 1451 end 1452 ti = 0 1453 for i = #histME2, 1, -1 do 1454 if histME2[i] == me then 1455 return ti 1456 end 1457 ti = ti + 1 1458 end 1459 end 1460 return 0 1461end 1462 1463function resizeMEpar(editor, w, h) 1464 local pare = getParME(editor) 1465 if pare then 1466 resizeMElim(editor, w, h, pare.w + pare.dx1 * 2) 1467 else 1468 resizeME(editor, w, h) 1469 end 1470end 1471 1472function resizeME(editor, w, h) 1473 if not editor then return end 1474 resizeMElim(editor, w, h, scrWidth / 2) 1475end 1476 1477function resizeMElim(editor, w, h, lim) 1478 if not editor then return end 1479 local met = getME(editor) 1480 if met then 1481 met.needw = w 1482 met.needh = h 1483 w = mathmax(w, 0) 1484 w = mathmin(w, scrWidth - met.dx1 * 2) 1485 h = mathmax(h, strFullHeight + 8) 1486 if (me ~= fctEditor) then 1487 w = mathmin(w, (scrWidth - lim) - 2 * met.dx1 + 1) 1488 end 1489 met:resize(w, h) 1490 needcenter = true 1491 reposME() 1492 theView:invalidate() 1493 end 1494 return editor 1495end 1496 1497ioffset = 0 1498function reposView() 1499 local focusedME = theView:getFocus() 1500 if focusedME and focusedME ~= fctEditor then 1501 local y = focusedME.y 1502 local h = focusedME.h 1503 local y0 = fctEditor.y 1504 local index = getMEindex(focusedME) 1505 if y < 0 and ioffset < index then 1506 ioffset = ioffset + 1 1507 reposME() 1508 reposView() 1509 end 1510 if y + h > y0 and ioffset > index then 1511 ioffset = ioffset - 1 1512 reposME() 1513 reposView() 1514 end 1515 end 1516end 1517 1518function reposME() 1519 local h, y, ry, res, i0, beforeh, totalh, visih, h1, h2 1520 totalh = 0 1521 beforeh = 0 1522 visih = 0 1523 fctEditor.y = scrHeight - fctEditor.h 1524 theView:repos(fctEditor) 1525 sbv:setVConstraints("justify", scrHeight - fctEditor.y + border) 1526 theView:repos(sbv) 1527 y = fctEditor.y 1528 i0 = mathmax(#histME1, #histME2) 1529 for i = i0, 1, -1 do 1530 h = 0 1531 h1 = 0 1532 h2 = 0 1533 if i <= #histME1 then h1 = mathmax(h1, histME1[i].h) end 1534 if i <= #histME2 then h2 = mathmax(h2, histME2[i].h) end 1535 h = mathmax(h1, h2) 1536 if i0 - i >= ioffset then 1537 if y >= 0 then 1538 if y >= h + border then 1539 visih = visih + h + border 1540 else 1541 visih = visih + y 1542 end 1543 end 1544 y = y - h - border 1545 ry = y 1546 totalh = totalh + h + border 1547 else 1548 ry = scrHeight 1549 beforeh = beforeh + h + border 1550 totalh = totalh + h + border 1551 end 1552 if i <= #histME1 then 1553 histME1[i].y = ry 1554 theView:repos(histME1[i]) 1555 if histME1[i].focus then res = histME1[i] end 1556 end 1557 if i <= #histME2 then 1558 histME2[i].y = ry + mathmax(0, h1 - h2) 1559 theView:repos(histME2[i]) 1560 if histME2[i].focus then res = histME2[i] end 1561 end 1562 end 1563 if totalh == 0 then 1564 sbv.pos = 0 1565 sbv.siz = 100 1566 else 1567 sbv.pos = beforeh * 100 / totalh 1568 sbv.siz = visih * 100 / totalh 1569 end 1570 theView:invalidate() 1571end 1572 1573function destroyD2Editor(editor) 1574 if not editor then return end 1575 editor:setVisible(false) 1576 editor:move(-10000, -10000) 1577 editor:resize(1, 1) 1578 editor = nil 1579end 1580 1581function reset() 1582 for _, v in pairs(theView.widgetList) do 1583 theView:remove(v) 1584 end 1585 for _, e in pairs(histME1) do 1586 destroyD2Editor(e.editor) 1587 end 1588 for _, e in pairs(histME2) do 1589 destroyD2Editor(e.editor) 1590 end 1591 histME1 = {} 1592 histME2 = {} 1593 fsize = 10 1594 applyFontSizeChange() 1595 platform.window:invalidate() 1596 myErrorHandler() 1597end 1598 1599function myErrorHandler(line, errMsg, callStack, locals) 1600 if errMsg then print(errMsg) end 1601 defaultFocus = nil 1602 theView = nil 1603 collectgarbage() 1604 initGUI() 1605 if errMsg then addME("Script error", errMsg) end 1606 collectgarbage() 1607 return true -- let the script continue 1608end 1609 1610platform.registerErrorHandler(myErrorHandler) 1611 1612 1613--------------------------------------------------------------------- toolpalette stuff 1614 1615function toggleBorders() 1616 showEditorsBorders = not showEditorsBorders 1617 on.resize() 1618end 1619 1620function set1d() 1621 fctEditor.editor:setDisable2DinRT(true) 1622 on.resize() 1623end 1624 1625function set2d() 1626 fctEditor.editor:setDisable2DinRT(false) 1627 on.resize() 1628end 1629 1630function toggleHLines() 1631 showHLines = not showHLines 1632 on.resize() 1633end 1634 1635function applyFontSizeChange() 1636 fctEditor.editor:setFontSize(fsize) 1637 for _, e in pairs(histME1) do 1638 e.editor:setFontSize(fsize) 1639 end 1640 for _, e in pairs(histME2) do 1641 e.editor:setFontSize(fsize) 1642 end 1643end 1644 1645function fontDown() 1646 fsize = fsize > 6 and (fsize - 1) or fsize 1647 applyFontSizeChange() 1648end 1649 1650function fontUp() 1651 fsize = fsize < 30 and (fsize + 1) or fsize 1652 applyFontSizeChange() 1653end 1654 1655function menustring( ch ) 1656-- theView:sendStringToFocus( ch ) 1657 if fctEditor then fctEditor:addString( ch ) end 1658end 1659 1660menu = { 1661 { "Algebra", 1662 { "factor(expr)", function() menustring( "factor(" ) end }, 1663 { "normal(expr)", function() menustring( "normal(" ) end }, 1664 { "simplify(expr)", function() menustring( "simplify(" ) end }, 1665 { "subst(expr,var,value)", function() menustring( "subst(" ) end }, 1666 { "convert(expr,...)", function() menustring( "convert(" ) end }, 1667 { "solve(expr,var)", function() menustring( "solve(" ) end }, 1668 { "fsolve(expr,var,guess)", function() menustring( "fsolve(" ) end }, 1669 { "rsolve(eq,un)", function() menustring( "rsolve(" ) end }, 1670 { "partfrac(expr)", function() menustring( "partfrac(" ) end }, 1671 { "tcollect(expr)", function() menustring( "tcollect(" ) end }, 1672 { "texpand(expr)", function() menustring( "texpand(" ) end }, 1673 { "cfactor(expr)", function() menustring( "cfactor(" ) end }, 1674 { "cpartfrac(expr)", function() menustring( "cpartfrac(" ) end }, 1675 { "csolve(expr,var)", function() menustring( "csolve(" ) end }, 1676 }, 1677 { "Calculus", 1678 { "diff(expr,var)", function() menustring( "diff(" ) end }, 1679 { "int(expr,var)", function() menustring( "int(" ) end }, 1680 { "limit(expr,var,value,[1|-1])", function() menustring( "limit(" ) end }, 1681 { "series(expr,var=value,order,[1|-1])", function() menustring( "series(" ) end }, 1682 { "sum(expr,var,min,max)", function() menustring( "sum(" ) end }, 1683 { "desolve(eq,x,y)", function() menustring( "desolve(" ) end }, 1684 }, 1685 { "Complex and Reals", 1686 { "abs(x)", function() menustring( "abs(" ) end }, 1687 { "floor(x)", function() menustring( "floor(" ) end }, 1688 { "sign(x)", function() menustring( "sign(" ) end }, 1689 { "ceil(x)", function() menustring( "ceil(" ) end }, 1690 { "max(x)", function() menustring( "max(" ) end }, 1691 { "min(x)", function() menustring( "min(" ) end }, 1692 { "round(x[,n])", function() menustring( "round(" ) end }, 1693 { "evalf(x[,prec])", function() menustring( "evalf(" ) end }, 1694 { "[inf..sup]", function() menustring( "[..]") end }, 1695 { "re(z)", function() menustring( "re(" ) end }, 1696 { "im(z)", function() menustring( "im(" ) end }, 1697 { "conj(z)", function() menustring( "conj(" ) end }, 1698 { "arg(z)", function() menustring( "arg(" ) end }, 1699 { "convert(expr,interval[,prec])", function() menustring( "convert(,interval)" ) end }, 1700 }, 1701 { "Integers", 1702 { "iquo(a,b): euclidean quotient", function() menustring( "iquo(" ) end }, 1703 { "irem(a,b): euclidean remainder", function() menustring( "irem(" ) end }, 1704 { "is_prime(p)", function() menustring( "is_prime" ) end }, 1705 { "nextprime(n)", function() menustring( "nextprime(" ) end }, 1706 { "ifactor(n): factor integer", function() menustring( "ifactor(" ) end }, 1707 { "idivis(n): divisor list", function() menustring( "idivis(" ) end }, 1708 { "iegcd(a,b): a*u+b*v=gcd(a,b)", function() menustring( "iegcd(" ) end }, 1709 { "iabcuv(a,b,c): a*u+b*v=c", function() menustring( "iabcuv(" ) end }, 1710 { "euler(n): Euler indicatrix", function() menustring( "euler(" ) end }, 1711 { "ichrem([a,n],[b,m]): Chinese remainder", function() menustring( "ichrem(" ) end }, 1712 { "powmod(a,m,n): a^m mod n", function() menustring( "powmod(" ) end }, 1713 }, 1714 { "Linalg", 1715 { "linsolve(", function() menustring( "linsolve(" ) end }, 1716 { "rref(M)", function() menustring( "rref(" ) end }, 1717 { "ref(M)", function() menustring( "ref(" ) end }, 1718 { "ker(M)", function() menustring( "ker(" ) end }, 1719 { "image(M)", function() menustring( "image(" ) end }, 1720 { "det(M)", function() menustring( "det(" ) end }, 1721 { "inv(M)", function() menustring( "inv(" ) end }, 1722 { "bug(M)", function() menustring( "bug(" ) end }, 1723 { "eigenvalues(M)", function() menustring( "eigenvalues(" ) end }, 1724 { "eigenvectors(M)", function() menustring( "eigenvects(" ) end }, 1725 { "jordan(M)", function() menustring( "jordan(" ) end }, 1726 { "matpow(M,n): M^n", function() menustring( "matpow(" ) end }, 1727 }, 1728 { "Matrix, Vector", 1729 { "dot(v1,v2)", function() menustring( "dot(" ) end }, 1730 { "cross(v1,v2)", function() menustring( "cross(" ) end }, 1731 { "identity(n)", function() menustring( "identity(" ) end }, 1732 { "matrix(n,m,function)", function() menustring( "matrix(" ) end }, 1733 { "randmatrix(n,m,law,[params])", function() menustring( "randmatrix(" ) end }, 1734 { "hilbert(n)", function() menustring( "hilbert(" ) end }, 1735 { "vandermonde(list)", function() menustring( "vandermonde(" ) end }, 1736 { "l1norm(M)", function() menustring( "l1norm(" ) end }, 1737 { "l2norm(M)", function() menustring( "l2norm(" ) end }, 1738 { "linfnorm(M)", function() menustring( "linfnorm(" ) end }, 1739 { "cond(M,1|2|inf)", function() menustring( "cond(" ) end }, 1740 { "lu(M)", function() menustring( "lu(" ) end }, 1741 { "qr(M)", function() menustring( "qr(" ) end }, 1742 { "schur(M)", function() menustring( "schur(" ) end }, 1743 { "svd(M): sing. value dec.", function() menustring( "svd(" ) end }, 1744 { "svl(M): singular values", function() menustring( "svl(" ) end }, 1745 }, 1746 { "Polynomials", 1747 { "horner(P,x)", function() menustring( "horner(" ) end }, 1748 { "factor(P)", function() menustring( "factor(" ) end }, 1749 { "cfactor(P): complex factorization", function() menustring( "cfactor(" ) end }, 1750 { "proot(P)", function() menustring( "proot(" ) end }, 1751 { "pcoeff(list)", function() menustring( "pcoeff(" ) end }, 1752 { "degree(P,var)", function() menustring( "degree(" ) end }, 1753 { "canonical_form(P,var)", function() menustring( "canonical_form(" ) end }, 1754 { "lagrange(X,Y): interpolation", function() menustring( "lagrange(" ) end }, 1755 { "quorem(A,B): eucl. div.", function() menustring( "quorem(" ) end }, 1756 { "gcd(A,B)", function() menustring( "gcd(" ) end }, 1757 { "egcd(A,B,var): A*U+B*V=gcd(A,B)", function() menustring( "egcd(" ) end }, 1758 { "abcuv(A,B,C,var): A*U+B*V=C", function() menustring( "abcuv(" ) end }, 1759 { "coeff(P,var,n)", function() menustring( "coeff(" ) end }, 1760 { "symb2poly(P,var)", function() menustring( "symb2poly(" ) end }, 1761 { "poly2symb(list,var)", function() menustring( "poly2symb(" ) end }, 1762 { "resultant(A,B,var)", function() menustring( "resultant(" ) end }, 1763 { "gbasis(listpoly,listvar)", function() menustring( "gbasis(" ) end }, 1764 { "cyclotomic(n)", function() menustring( "cyclotomic(" ) end }, 1765 { "hermite(n)", function() menustring( "hermite(" ) end }, 1766 { "tchebyshev1(n)", function() menustring( "tchebyshev1(" ) end }, 1767 { "tchebyshev2(n)", function() menustring( "tchebyshev2(" ) end }, 1768 { "randpoly(n)", function() menustring( "randpoly(" ) end }, 1769 }, 1770 { "Proba", 1771 { "comb(n,p)", function() menustring( "comb(" ) end }, 1772 { "perm(n,p)", function() menustring( "perm(" ) end }, 1773 { "factorial(n)", function() menustring( "factorial(" ) end }, 1774 { "rand()", function() menustring( "rand(" ) end }, 1775 { "binomial(n,p,k)", function() menustring( "binomial(" ) end }, 1776 { "binomial_cdf(n,p,x)", function() menustring( "binomial_cdf(" ) end }, 1777 { "binomial_icdf(n,p,y)", function() menustring( "binomial_icdf(" ) end }, 1778 { "normald(m,sigma,x)", function() menustring( "normald(" ) end }, 1779 { "normald_cdf(m,sigma,x)", function() menustring( "normald_cdf(" ) end }, 1780 { "normald_icdf(m.sigma,y)", function() menustring( "normald_icdf(" ) end }, 1781 { "poisson(mu,k)", function() menustring( "poisson(" ) end }, 1782 { "exponentiald(mu,x)", function() menustring( "exponentiald(" ) end }, 1783 { "geometric(p,k)", function() menustring( "geometric(" ) end }, 1784 { "chisquared(n,x)", function() menustring( "chisquared(" ) end }, 1785 { "uniformd(a,b,x)", function() menustring( "uniformd(" ) end }, 1786 { "chisquaret(l1,l2): chi2 test", function() menustring( "chisquaret(" ) end }, 1787 { "normalt: Z-test", function() menustring( "normalt(" ) end }, 1788 { "studentt: Student-test", function() menustring( "studentt(" ) end }, 1789 }, 1790 { "Program", 1791 { ";", function() menustring( ";\n\r" ) end }, 1792 { "function", function() menustring( "f(x):={ local y; y:=x*x; return y; }" ) end }, 1793 { "local", function() menustring( "local ;\n" ) end }, 1794 { "return", function() menustring( "return ;" ) end }, 1795 { "print", function() menustring( "print(" ) end }, 1796 { "if/then", function() menustring( "if then ; fi;" ) end }, 1797 { "if/then/else", function() menustring( "if then ; else ; fi;" ) end }, 1798 { "for", function() menustring( "for j from 1 to 5 do ; od;" ) end }, 1799 { "while", function() menustring( "while do ; od;" ) end }, 1800 { "repeat", function() menustring( "repeat ; until ;" ) end }, 1801 { "break", function() menustring( "break;" ) end }, 1802 { "continue", function() menustring( "continue;" ) end }, 1803 }, 1804 { "Lists", 1805 { "seq(expr,var,inf,sup)", function() menustring( "seq(" ) end }, 1806 { "size(l)", function() menustring( "size(" ) end }, 1807 { "op(l): list to sequence", function() menustring( "op(" ) end }, 1808 { "apply(f,l) apply function", function() menustring( "apply(" ) end }, 1809 { "append(l,expr)", function() menustring( "append(" ) end }, 1810 { "concat(l1,l2)", function() menustring( "concat(" ) end }, 1811 { "head(l): first element", function() menustring( "head(" ) end }, 1812 { "tail(l)", function() menustring( "tail(" ) end }, 1813 { "sort(l[,function])", function() menustring( "sort(" ) end }, 1814 { "revlist(l)", function() menustring( "revlist(" ) end }, 1815 { "contains(l,expr)", function() menustring( "contains(" ) end }, 1816 { "suppress(l,n)", function() menustring( "suppress(" ) end }, 1817 { "remove(function,l)", function() menustring( "remove(" ) end }, 1818 }, 1819 { 1820 "Options", 1821 { "save variables", function() menustring( "write(\"a.tns\",0" ) end }, 1822 { "read variables", function() menustring( "eval(read(\"a.tns\"))" ) end }, 1823 "-", 1824 -- { "1d", set1d }, 1825 -- { "2d", set2d }, 1826 { "Show/hide editors borders", toggleBorders }, 1827 { "Show/hide horizontal lines", toggleHLines }, 1828 "-", 1829 { "Increase font size", fontUp }, 1830 { "Decrease font size", fontDown }, 1831 "-", 1832 { "Restart CAS", function() menustring( "restart;" ) end }, 1833 { "Clear history", reset } 1834 } 1835} 1836toolpalette.register(menu) 1837