Subversion Repositories Kolibri OS

Rev

Rev 9208 | Rev 9431 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. (*
  2.     Copyright 2021 Anton Krotov
  3.  
  4.     This file is part of CEdit.
  5.  
  6.     CEdit is free software: you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation, either version 3 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     CEdit is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with CEdit. If not, see <http://www.gnu.org/licenses/>.
  18. *)
  19.  
  20. MODULE Scroll;
  21.  
  22. IMPORT G := Graph, K := KolibriOS, U := Utils;
  23.  
  24. CONST
  25.  
  26.         ScrollIPC* = 0;
  27.         DELAY = 40;
  28.  
  29. TYPE
  30.  
  31.         tScroll* = RECORD
  32.                 vertical, Inc*, Dec*, mouse: BOOLEAN;
  33.                 top*, left*,
  34.                 width*, height*: INTEGER; (* read only *)
  35.                 btnSize, sliderSize: INTEGER;
  36.                 pos, Slider, pos0, maxVal*, value*: INTEGER;
  37.                 canvas*: G.tCanvas
  38.         END;
  39.  
  40.         tProcedure* = PROCEDURE;
  41.  
  42. VAR
  43.  
  44.         ScrollChange: tProcedure;
  45.         delay: INTEGER;
  46.  
  47.  
  48. PROCEDURE MouseUp (VAR scroll: tScroll);
  49. BEGIN
  50.         scroll.Slider := -1;
  51.         scroll.Inc := FALSE;
  52.         scroll.Dec := FALSE;
  53.         scroll.mouse := FALSE;
  54. END MouseUp;
  55.  
  56.  
  57. PROCEDURE create* (vertical: BOOLEAN; width, height: INTEGER; btnSize, sliderSize: INTEGER; VAR scroll: tScroll);
  58. VAR
  59.         res: tScroll;
  60. BEGIN
  61.         MouseUp(res);
  62.         res.vertical := vertical;
  63.         res.left := 0;
  64.         res.top := 0;
  65.         res.width := width;
  66.         res.height := height;
  67.         res.btnSize := btnSize;
  68.         res.sliderSize := sliderSize;
  69.         res.pos := 0;
  70.         res.maxVal := 0;
  71.         res.canvas := G.CreateCanvas(width, height);
  72.         scroll := res
  73. END create;
  74.  
  75.  
  76. PROCEDURE Rect (canvas: G.tCanvas; left, top, right, bottom: INTEGER);
  77. BEGIN
  78.         G.FillRect(canvas, left, top, right, bottom);
  79.         G.SetColor(canvas, K.borderColor);
  80.         G.Rect(canvas, left, top, right, bottom);
  81. END Rect;
  82.  
  83.  
  84. PROCEDURE _paint (scroll: tScroll);
  85. VAR
  86.         canvas: G.tCanvas;
  87.         x, y, d, x1, x2, y1, y2,
  88.         width, height, btn: INTEGER;
  89.  
  90.  
  91.         PROCEDURE SetColor (canvas: G.tCanvas; c: BOOLEAN);
  92.         VAR
  93.                 color: INTEGER;
  94.         BEGIN
  95.                 IF c THEN
  96.                         color := K.btnColor
  97.                 ELSE
  98.                         color := K.btnTextColor
  99.                 END;
  100.                 G.SetColor(canvas, color)
  101.         END SetColor;
  102.  
  103.  
  104. BEGIN
  105.         btn := scroll.btnSize;
  106.         width := scroll.width;
  107.         height := scroll.height;
  108.         canvas := scroll.canvas;
  109.         G.SetColor(canvas, K.winColor);
  110.         G.clear(canvas);
  111.         G.SetColor(canvas, K.borderColor);
  112.         G.Rect(canvas, 0, 0, width - 1, height - 1);
  113.         IF scroll.vertical THEN
  114.                 SetColor(canvas, ~scroll.Dec);
  115.                 Rect(canvas, 0, 0, width - 1, btn - 1);
  116.                 SetColor(canvas, ~scroll.Inc);
  117.                 Rect(canvas, 0, height - btn, width - 1, height - 1);
  118.                 G.SetColor(canvas, K.btnColor);
  119.                 Rect(canvas, 0, btn + scroll.pos - 1, width - 1, btn + scroll.pos + scroll.sliderSize - 1);
  120.  
  121.                 G.SetColor(canvas, K.btnTextColor);
  122.  
  123.                 y := btn + scroll.pos + scroll.sliderSize DIV 2 - 1;
  124.                 G.HLine(canvas, y, width DIV 4, 3*width DIV 4);
  125.                 G.HLine(canvas, y - 3, width DIV 3, 2*width DIV 3);
  126.                 G.HLine(canvas, y + 3, width DIV 3, 2*width DIV 3);
  127.  
  128.                 d := 4*width DIV 10;
  129.                 x1 := (width - d) DIV 2;
  130.                 x2 := x1 + d;
  131.  
  132.                 SetColor(canvas, scroll.Dec);
  133.                 y := (btn - d DIV 2) DIV 2 + d DIV 2 - 1;
  134.                 G.Triangle(canvas, x1 - 1, y, x2, y, G.triUp);
  135.  
  136.                 SetColor(canvas, scroll.Inc);
  137.                 y := y + height - btn - d DIV 2 + 1;
  138.                 G.Triangle(canvas, x1 - 1, y, x2, y, G.triDown);
  139.         ELSE
  140.                 SetColor(canvas, ~scroll.Dec);
  141.                 Rect(canvas, 0, 0, btn - 1, height - 1);
  142.                 SetColor(canvas, ~scroll.Inc);
  143.                 Rect(canvas, width - btn, 0, width - 1, height - 1);
  144.                 G.SetColor(canvas, K.btnColor);
  145.                 Rect(canvas, btn + scroll.pos - 1, 0, btn + scroll.pos + scroll.sliderSize - 1, height - 1);
  146.  
  147.                 G.SetColor(canvas, K.btnTextColor);
  148.  
  149.                 x := btn + scroll.pos + scroll.sliderSize DIV 2 - 1;
  150.                 G.VLine(canvas, x, height DIV 4, 3*height DIV 4);
  151.                 G.VLine(canvas, x - 3, height DIV 3, 2*height DIV 3);
  152.                 G.VLine(canvas, x + 3, height DIV 3, 2*height DIV 3);
  153.  
  154.                 d := 4*height DIV 10;
  155.                 y1 := (height - d) DIV 2;
  156.                 y2 := y1 + d;
  157.  
  158.                 SetColor(canvas, scroll.Dec);
  159.                 x := (btn - d DIV 2) DIV 2 + d DIV 2 - 1;
  160.                 G.Triangle(canvas, x, y1 - 1, x, y2, G.triLeft);
  161.  
  162.                 SetColor(canvas, scroll.Inc);
  163.                 x := x + width - btn - d DIV 2 + 1;
  164.                 G.Triangle(canvas, x, y1 - 1, x, y2, G.triRight);
  165.         END;
  166.         G.DrawCanvas(scroll.canvas, scroll.left, scroll.top)
  167. END _paint;
  168.  
  169.  
  170. PROCEDURE paint* (scroll: tScroll);
  171. BEGIN
  172.         IF scroll.canvas # NIL THEN
  173.                 _paint(scroll)
  174.         END
  175. END paint;
  176.  
  177.  
  178. PROCEDURE resize* (VAR scroll: tScroll; width, height: INTEGER);
  179. BEGIN
  180.         G.destroy(scroll.canvas);
  181.         scroll.canvas := G.CreateCanvas(width, height);
  182.         scroll.width := width;
  183.         scroll.height := height;
  184.         paint(scroll)
  185. END resize;
  186.  
  187.  
  188. PROCEDURE setValue* (VAR scroll: tScroll; value: INTEGER);
  189. VAR
  190.         pos, maxPos, n, m: INTEGER;
  191. BEGIN
  192.         IF scroll.vertical THEN
  193.                 maxPos := scroll.height
  194.         ELSE
  195.                 maxPos := scroll.width
  196.         END;
  197.         maxPos := maxPos - scroll.btnSize*2 - scroll.sliderSize + 1;
  198.         IF (value < 0) OR (scroll.maxVal <= 0) THEN
  199.                 value := 0;
  200.                 pos := 0
  201.         ELSIF value > scroll.maxVal THEN
  202.                 value := scroll.maxVal;
  203.                 pos := maxPos
  204.         ELSE
  205.                 IF (maxPos + 1) >= scroll.maxVal THEN
  206.                         n := (maxPos + 1) DIV scroll.maxVal;
  207.                         m := (maxPos + 1) MOD scroll.maxVal;
  208.                         pos := value*n + MIN(value, m)
  209.                 ELSE
  210.                         pos := FLOOR(FLT(value)*FLT(maxPos + 1)/FLT(scroll.maxVal))
  211.                 END;
  212.                 IF pos > maxPos THEN
  213.                         pos := maxPos;
  214.                         value := scroll.maxVal
  215.                 END
  216.         END;
  217.         scroll.pos := pos;
  218.         scroll.value := value
  219. END setValue;
  220.  
  221.  
  222. PROCEDURE change* (VAR scroll: tScroll);
  223. BEGIN
  224.         IF scroll.Inc THEN
  225.                 setValue(scroll, scroll.value + 1)
  226.         ELSIF scroll.Dec THEN
  227.                 setValue(scroll, scroll.value - 1)
  228.         END;
  229.         paint(scroll)
  230. END change;
  231.  
  232.  
  233. PROCEDURE ceil (p, q: INTEGER): INTEGER;
  234.         RETURN p DIV q + ORD(p MOD q # 0)
  235. END ceil;
  236.  
  237.  
  238. PROCEDURE setPos (VAR scroll: tScroll; pos: INTEGER);
  239. VAR
  240.         maxPos, value, n, m, x, x0, q: INTEGER;
  241. BEGIN
  242.         IF scroll.maxVal > 0 THEN
  243.                 IF scroll.vertical THEN
  244.                         maxPos := scroll.height
  245.                 ELSE
  246.                         maxPos := scroll.width
  247.                 END;
  248.                 maxPos := maxPos - scroll.btnSize*2 - scroll.sliderSize + 1;
  249.                 IF pos <= 0 THEN
  250.                         pos := 0;
  251.                         value := 0
  252.                 ELSIF pos >= maxPos THEN
  253.                         pos := maxPos;
  254.                         value := scroll.maxVal
  255.                 ELSE
  256.                         IF scroll.maxVal <= maxPos + 1 THEN
  257.                                 n := (maxPos + 1) DIV scroll.maxVal;
  258.                                 m := (maxPos + 1) MOD scroll.maxVal;
  259.  
  260.                                 q := m*(n + 1);
  261.                                 IF q < pos THEN
  262.                                         value := ceil(pos - m, n)
  263.                                 ELSIF q > pos THEN
  264.                                         value := ceil(pos, n + 1)
  265.                                 ELSE
  266.                                         value := m
  267.                                 END;
  268.  
  269.                                 x := value*n + MIN(value, m);
  270.                                 x0 := (value - 1)*n + MIN(value - 1, m);
  271.  
  272.                                 IF x - pos > pos - x0 THEN
  273.                                         pos := x0;
  274.                                         DEC(value)
  275.                                 ELSE
  276.                                         pos := x;
  277.                                         IF pos > maxPos THEN
  278.                                                 pos := maxPos;
  279.                                                 value := scroll.maxVal
  280.                                         END
  281.                                 END
  282.                         ELSE
  283.                                 value := FLOOR(FLT(scroll.maxVal)*FLT(pos)/FLT(maxPos + 1))
  284.                         END
  285.                 END
  286.         ELSE
  287.                 pos := 0;
  288.                 scroll.value := 0
  289.         END;
  290.         scroll.pos := pos;
  291.         scroll.value := value
  292. END setPos;
  293.  
  294.  
  295. PROCEDURE MouseMove (VAR scroll: tScroll; x, y: INTEGER);
  296. VAR
  297.         c: INTEGER;
  298. BEGIN
  299.         IF scroll.vertical THEN
  300.                 c := y - scroll.top
  301.         ELSE
  302.                 c := x - scroll.left
  303.         END;
  304.         setPos(scroll, scroll.pos0 + c - scroll.Slider);
  305.         paint(scroll)
  306. END MouseMove;
  307.  
  308.  
  309. PROCEDURE SendIPC;
  310. VAR
  311.         msg: ARRAY 2 OF INTEGER;
  312. BEGIN
  313.         msg[0] := ScrollIPC;
  314.         msg[1] := 8;
  315.         K.SendIPC(K.ThreadID(), msg)
  316. END SendIPC;
  317.  
  318.  
  319. PROCEDURE receiveIPC* (VAR IPC: ARRAY OF INTEGER; VAR scrollIPC: BOOLEAN);
  320. BEGIN
  321.         scrollIPC := FALSE;
  322.         ScrollChange;
  323.         IF 0 IN K.MouseState() THEN
  324.                 WHILE (0 IN K.MouseState()) & (delay > 0) DO
  325.                         K.Pause(1);
  326.                 DEC(delay)
  327.                 END;
  328.                 IF delay = 0 THEN
  329.                         IPC[0] := 0;
  330.                         IPC[1] := 0;
  331.                         scrollIPC := TRUE;
  332.                 SendIPC;
  333.                 delay := 4
  334.                 ELSE
  335.                         delay := DELAY
  336.                 END
  337.         ELSE
  338.                 delay := DELAY
  339.         END
  340. END receiveIPC;
  341.  
  342.  
  343. PROCEDURE MouseDown (VAR scroll: tScroll; x, y: INTEGER);
  344. VAR
  345.         c, size: INTEGER;
  346. BEGIN
  347.         DEC(x, scroll.left);
  348.         DEC(y, scroll.top);
  349.         scroll.mouse := TRUE;
  350.         IF U.between(1, x, scroll.width - 2) & U.between(1, y, scroll.height - 2) THEN
  351.                 IF scroll.vertical THEN
  352.                         c := y;
  353.                         size := scroll.height
  354.                 ELSE
  355.                         c := x;
  356.                         size := scroll.width
  357.                 END;
  358.                 IF U.between(scroll.btnSize + scroll.pos - 1, c, scroll.btnSize + scroll.pos + scroll.sliderSize - 1) THEN
  359.                         scroll.pos0 := scroll.pos;
  360.                         scroll.Slider := c
  361.                 ELSIF U.between(0, c, scroll.btnSize - 1) THEN
  362.                         scroll.Dec := TRUE;
  363.                         SendIPC
  364.                 ELSIF U.between(size - scroll.btnSize, c, size - 1) THEN
  365.                         scroll.Inc := TRUE;
  366.                         SendIPC
  367.                 ELSE
  368.                         setPos(scroll, c - scroll.btnSize - scroll.sliderSize DIV 2);
  369.                         scroll.pos0 := scroll.pos;
  370.                         scroll.Slider := c;
  371.                         paint(scroll)
  372.                 END
  373.         END
  374. END MouseDown;
  375.  
  376.  
  377. PROCEDURE mouse* (VAR scroll: tScroll);
  378. VAR
  379.         msState: SET;
  380.         x, y: INTEGER;
  381. BEGIN
  382.         K.mouse(msState, x, y);
  383.         IF 0 IN msState THEN
  384.                 IF ~scroll.mouse THEN
  385.                         MouseDown(scroll, x, y)
  386.                 ELSIF scroll.Slider # -1 THEN
  387.                         MouseMove(scroll, x, y)
  388.                 END
  389.         ELSIF scroll.mouse THEN
  390.                 MouseUp(scroll);
  391.                 paint(scroll)
  392.         END
  393. END mouse;
  394.  
  395.  
  396. PROCEDURE init* (_ScrollChange: tProcedure);
  397. BEGIN
  398.         delay := DELAY;
  399.         ScrollChange := _ScrollChange
  400. END init;
  401.  
  402.  
  403. END Scroll.