------------------------------------------------------------------------------
--                                                                          --
--                An Ada2005 binding to the Qt C++ framework                --
--                                                                          --
------------------------------------------------------------------------------
--                                                                          --
-- Copyright © 2008, 2009 Vadim Godunko <vgodunko@gmail.com>                --
--                                                                          --
-- QtAda is free software;  you can  redistribute it and/or modify it under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 2,  or (at your option) any later ver- --
-- sion. QtAda is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
-- for  more details.  You should have  received  a copy of the GNU General --
-- Public License distributed with QtAda;  see file COPYING.  If not, write --
-- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
-- Boston, MA 02110-1301, USA.                                              --
--                                                                          --
------------------------------------------------------------------------------
--  $Revision: 3574 $ $Date: 2009-08-30 12:15:21 +0400 (Sun, 30 Aug 2009) $
------------------------------------------------------------------------------
with Ada.Numerics.Generic_Elementary_Functions;

with Qt4.Abstract_Item_Models;
pragma Warnings (Off, Qt4.Abstract_Item_Models);
--  XXX Gnat Pro 6.1.0w (20070424-41)
with Qt4.Abstract_Item_Delegates;
pragma Warnings (Off, Qt4.Abstract_Item_Delegates);
--  XXX Gnat Pro 6.1.0w (20070424-41)
with Qt4.Brushes;
with Qt4.Colors;
with Qt4.Font_Metrics;
with Qt4.Item_Selection_Ranges;
with Qt4.Item_Selections.Constructors;
with Qt4.Model_Index_Lists;
with Qt4.Painters;
with Qt4.Painter_Paths;
with Qt4.Palettes;
with Qt4.Pens;
with Qt4.Rubber_Bands.Constructors;
with Qt4.Scroll_Bars;
pragma Warnings (Off, Qt4.Scroll_Bars);
--  XXX Gnat Pro 6.1.0w (20070424-41)
with Qt4.Sizes;
with Qt4.Styles;
with Qt4.Style_Option_View_Items;
with Qt4.Variants;
with Qt4.Widgets;

with Pie_Views.MOC;
pragma Warnings (Off, Pie_Views.MOC);
--  Child package MOC must be included in the application.

package body Pie_Views is

   use type Qt4.Q_Integer;
   use type Qt4.Q_Real;
   use type Qt4.Rubber_Bands.Q_Rubber_Band_Access;

   package Q_Real_Elementary_Functions is
     new Ada.Numerics.Generic_Elementary_Functions (Qt4.Q_Real);

   function Get_Double_Value (Data : Qt4.Variants.Q_Variant) return Qt4.Q_Real;

   ------------------
   -- Constructors --
   ------------------

   package body Constructors is

      ------------
      -- Create --
      ------------

      function Create return not null Pie_View_Access is
         Self : constant Pie_View_Access := new Pie_Views.Pie_View;

      begin
         Qt4.Abstract_Item_Views.Directors.Constructors.Initialize (Self);

         Self.Margin      := 8;
         Self.Total_Size  := 300;
         Self.Pie_Size    := Self.Total_Size - 2 * Self.Margin;
         Self.Total_Value := 0.0;
         Self.Valid_Items := 0;

         Self.Horizontal_Scroll_Bar.Set_Range (0, 0);
         Self.Vertical_Scroll_Bar.Set_Range (0, 0);

         return Self;
      end Create;

   end Constructors;

   ------------------
   -- Data_Changed --
   ------------------

   overriding procedure Data_Changed
    (Self         : not null access Pie_View;
     Top_Left     : Qt4.Model_Indices.Q_Model_Index;
     Bottom_Right : Qt4.Model_Indices.Q_Model_Index)
   is
   begin
      Qt4.Abstract_Item_Views.Directors.Q_Abstract_Item_View_Director
       (Self.all).Data_Changed (Top_Left, Bottom_Right);

      Self.Valid_Items := 0;
      Self.Total_Value := 0.0;

      for Row in 0 .. Self.Model.Row_Count (Self.Root_Index) - 1 loop
         declare
             Index : constant Qt4.Model_Indices.Q_Model_Index
               := Self.Model.Index (Row, 1, Self.Root_Index);
             Value : constant Qt4.Q_Real
               := Get_Double_Value (Self.Model.Data (Index));

         begin
            if Value > 0.0 then
               Self.Total_Value := Self.Total_Value + Value;
               Self.Valid_Items := Self.Valid_Items + 1;
            end if;
         end;
      end loop;

      Self.Viewport.Update;
   end Data_Changed;

   ----------
   -- Edit --
   ----------

   overriding function Edit
    (Self    : not null access Pie_View;
     Index   : Qt4.Model_Indices.Q_Model_Index;
     Trigger : Qt4.Abstract_Item_Views.Edit_Trigger;
     Event   : access Qt4.Events.Q_Event'Class)
       return Boolean
   is
   begin
      if Index.Column = 0 then
         return
           Qt4.Abstract_Item_Views.Directors.Q_Abstract_Item_View_Director
            (Self.all).Edit (Index, Trigger, Event);

      else
         return False;
      end if;
   end Edit;

   ----------------------
   -- Get_Double_Value --
   ----------------------

   function Get_Double_Value
    (Data : Qt4.Variants.Q_Variant) return Qt4.Q_Real
   is
      Result : Qt4.Q_Real;

   begin
      Result := Qt4.Q_Real (Data.To_Double);

      return Result;

      exception
         when Constraint_Error =>
           return 0.0;
   end Get_Double_Value;

   -----------------------
   -- Horizontal_Offset --
   -----------------------

   overriding function Horizontal_Offset
    (Self : not null access constant Pie_View)
       return Qt4.Q_Integer
   is
   begin
      return Self.Horizontal_Scroll_Bar.Value;
   end Horizontal_Offset;

   --------------
   -- Index_At --
   --------------

   overriding function Index_At
    (Self  : not null access constant Pie_View;
     Point : Qt4.Points.Q_Point)
       return Qt4.Model_Indices.Q_Model_Index
   is
      use Q_Real_Elementary_Functions;

      W_X : constant Qt4.Q_Integer
        := Point.X + Self.Horizontal_Scroll_Bar.Value;
      W_Y : constant Qt4.Q_Integer := Point.Y + Self.Vertical_Scroll_Bar.Value;

      Result : Qt4.Model_Indices.Q_Model_Index;

   begin
      if Self.Valid_Items = 0 then
         return Result;
      end if;

      if W_X < Self.Total_Size then
         declare
            C_X         : constant Qt4.Q_Real
              := Qt4.Q_Real (W_X - Self.Total_Size / 2);
            C_Y         : constant Qt4.Q_Real
              := Qt4.Q_Real (Self.Total_Size / 2 - W_Y);

            --  Determine the distance from the center point of the pie chart.

            D           : constant Qt4.Q_Real := Sqrt (C_X ** 2 + C_Y ** 2);
            Angle       : Qt4.Q_Real;
            Start_Angle : Qt4.Q_Real := 0.0;

         begin
            if Qt4.Q_Integer (D) = 0
              or Qt4.Q_Integer (D) > Self.Pie_Size / 2
            then
               return Result;
            end if;

            Angle := (180.0 / Ada.Numerics.Pi) * Arccos (C_X / D);

            if Qt4.Q_Integer (C_Y) < 0 then
               Angle := 360.0 - Angle;
            end if;

            for Row in 0 .. Self.Model.Row_Count (Self.Root_Index) - 1 loop
               declare
                  Index      : constant Qt4.Model_Indices.Q_Model_Index
                    := Self.Model.Index (Row, 1, Self.Root_Index);
                  Value      : constant Qt4.Q_Real
                    := Get_Double_Value (Self.Model.Data (Index));
                  Slice_Angle : Qt4.Q_Real;

               begin
                  if Value > 0.0 then
                     Slice_Angle := 360.0 * Value / Self.Total_Value;

                     if Angle >= Start_Angle then
                        if Angle <= Start_Angle + Slice_Angle then
                           return Self.Model.Index (Row, 1, Self.Root_Index);
                        end if;
                     end if;

                     Start_Angle := Start_Angle + Slice_Angle;
                  end if;
               end;
            end loop;
         end;

      else
         declare
            Item_Height : constant Qt4.Q_Integer
              := Qt4.Font_Metrics.Create (Self.all.View_Options.Font).Height;
            List_Item   : constant Qt4.Q_Integer
              := (W_Y - Self.Margin) / Item_Height;
            Valid_Row   : Qt4.Q_Integer := 0;

         begin
            for Row in 0 .. Self.Model.Row_Count (Self.Root_Index) - 1 loop
               declare
                  Index : constant Qt4.Model_Indices.Q_Model_Index
                    := Self.Model.Index (Row, 1, Self.Root_Index);
                  Value : constant Qt4.Q_Real
                    := Get_Double_Value (Self.Model.Data (Index));

               begin
                  if  Value > 0.0 then
                     if List_Item = Valid_Row then
                        return Self.Model.Index (Row, 0, Self.Root_Index);
                     end if;

                     Valid_Row := Valid_Row + 1;
                  end if;
               end;
            end loop;
         end;
      end if;

      return Result;
   end Index_At;

   ---------------------
   -- Is_Index_Hidden --
   ---------------------

   overriding function Is_Index_Hidden
    (Self  : not null access constant Pie_View;
     Index : Qt4.Model_Indices.Q_Model_Index)
       return Boolean
   is
      pragma Unreferenced (Self);
      pragma Unreferenced (Index);

   begin
      return False;
   end Is_Index_Hidden;

   ---------------
   -- Item_Rect --
   ---------------

   function Item_Rect
    (Self  : not null access constant Pie_View'Class;
     Index : Qt4.Model_Indices.Q_Model_Index)
       return Qt4.Rects.Q_Rect
   is
      Value_Index : Qt4.Model_Indices.Q_Model_Index;
      Result      : Qt4.Rects.Q_Rect;

   begin
      if not Index.Is_Valid then
        return Result;
      end if;

      --  Check whether the index's row is in the list of rows represented
      --  by slices.

      if Index.Column /= 1 then
         Value_Index := Self.Model.Index (Index.Row, 1, Self.Root_Index);

      else
         Value_Index := Index;
      end if;

      if  Get_Double_Value (Self.Model.Data (Value_Index)) > 0.0 then
         declare
            List_Item   : Qt4.Q_Integer := 0;
            Item_Height : Qt4.Q_Integer;

         begin
            for J in reverse 0 .. Index.Row - 1 loop
               if Get_Double_Value
                      (Self.Model.Data
                        (Self.Model.Index
                          (Index.Row - 1, 1, Self.Root_Index))) > 0.0
               then
                  List_Item := List_Item + 1;
               end if;
            end loop;

            case Index.Column is
               when 0 =>
                  Item_Height :=
                     Qt4.Font_Metrics.Create (Self.View_Options.Font).Height;

                  return
                    Qt4.Rects.Create
                     (Self.Total_Size,
                      Self.Margin + List_Item * Item_Height,
                      Self.Total_Size - Self.Margin,
                      Item_Height);

               when 1 =>
                  return Self.Viewport.Rect;

               when others =>
                  raise Program_Error;
            end case;
         end;
      end if;

      return Result;
   end Item_Rect;

   -----------------
   -- Item_Region --
   -----------------

   function Item_Region
    (Self  : not null access Pie_View'Class;
     Index : Qt4.Model_Indices.Q_Model_Index)
       return Qt4.Regions.Q_Region
   is
      use type Qt4.Model_Indices.Q_Model_Index;

      Start_Angle : Qt4.Q_Real := 0.0;
      Result      : Qt4.Regions.Q_Region;

   begin
      if not Index.Is_Valid then
         return Result;
      end if;

      if Index.Column /= 1 then
         return Qt4.Regions.Create (Self.Item_Rect (Index));
      end if;

      if Get_Double_Value (Self.Model.Data (Index)) <= 0.0 then
         return Result;
      end if;

      for J in 0 .. Self.Model.Row_Count (Self.Root_Index) - 1 loop
         declare
            Slice_Index  : constant Qt4.Model_Indices.Q_Model_Index
              := Self.Model.Index (1, 1, Self.Root_Index);
            Value        : constant Qt4.Q_Real
              := Get_Double_Value (Self.Model.Data (Slice_Index));
            Angle        : Qt4.Q_Real := 360.0;

         begin
            if Value > 0.0 then
               Angle := 360.0 * Value / Self.Total_Value;

               if Slice_Index = Index then
                  declare
                     Slice_Path : Qt4.Painter_Paths.Q_Painter_Path;

                  begin
                     Slice_Path.Move_To
                      (Qt4.Q_Real (Self.Total_Size) / 2.0,
                       Qt4.Q_Real (Self.Total_Size) / 2.0);
                     Slice_Path.Arc_To
                      (Qt4.Q_Real (Self.Margin),
                       Qt4.Q_Real (Self.Margin),
                       Qt4.Q_Real (Self.Margin + Self.Pie_Size),
                       Qt4.Q_Real (Self.Margin + Self.Pie_Size),
                       Start_Angle,
                       Angle);
                     Slice_Path.Close_Subpath;

                     return
                       Qt4.Regions.Create
                        (Slice_Path.To_Fill_Polygon.To_Polygon);
                  end;
               end if;

               Start_Angle := Start_Angle + Angle;
            end if;
         end;
      end loop;

      return Result;
   end Item_Region;

   ----------------------
   -- Mouse_Move_Event --
   ----------------------

   overriding procedure Mouse_Move_Event
    (Self  : not null access Pie_View;
     Event : not null access Qt4.Mouse_Events.Q_Mouse_Event'Class)
   is
   begin
      if Self.Rubber_Band /= null then
         Qt4.Rubber_Bands.Set_Geometry
          (Self.Rubber_Band,
           Qt4.Rects.Create (Self.Origin, Event.Pos).Normalized);
      end if;

      Qt4.Abstract_Item_Views.Directors.Q_Abstract_Item_View_Director
       (Self.all).Mouse_Move_Event (Event);
   end Mouse_Move_Event;

   -----------------------
   -- Mouse_Press_Event --
   -----------------------

   overriding procedure Mouse_Press_Event
    (Self  : not null access Pie_View;
     Event : not null access Qt4.Mouse_Events.Q_Mouse_Event'Class)
   is
   begin
      Qt4.Abstract_Item_Views.Directors.Q_Abstract_Item_View_Director
       (Self.all).Mouse_Press_Event (Event);

      Self.Origin := Event.Pos;

      if Self.Rubber_Band = null then
         Self.Rubber_Band :=
           Qt4.Rubber_Bands.Constructors.Create
            (Qt4.Rubber_Bands.Rectangle, Self);
      end if;

      Qt4.Rubber_Bands.Set_Geometry
       (Self.Rubber_Band,
        Qt4.Rects.Create (Self.Origin, Qt4.Sizes.Create));
      Self.Rubber_Band.Show;
   end Mouse_Press_Event;

   -------------------------
   -- Mouse_Release_Event --
   -------------------------

   overriding procedure Mouse_Release_Event
    (Self  : not null access Pie_View;
     Event : not null access Qt4.Mouse_Events.Q_Mouse_Event'Class)
   is
   begin
      Qt4.Abstract_Item_Views.Directors.Q_Abstract_Item_View_Director
       (Self.all).Mouse_Release_Event (Event);

      if Self.Rubber_Band /= null then
         Self.Rubber_Band.Hide;
      end if;

      Self.Viewport.Update;
   end Mouse_Release_Event;

   -----------------
   -- Move_Cursor --
   -----------------

   overriding function Move_Cursor
    (Self      : not null access Pie_View;
     Action    : Qt4.Abstract_Item_Views.Cursor_Action;
     Modifiers : Qt4.Keyboard_Modifiers)
       return Qt4.Model_Indices.Q_Model_Index
   is
      pragma Unreferenced (Modifiers);

--      use Qt4.Abstract_Item_Views;

      Current : Qt4.Model_Indices.Q_Model_Index := Self.Current_Index;

   begin
      case Action is
         when Qt4.Abstract_Item_Views.Move_Left
           | Qt4.Abstract_Item_Views.Move_Up
         =>
            if Current.Row > 0 then
               Current :=
                 Self.Model.Index
                  (Current.Row - 1, Current.Column, Self.Root_Index);

            else
               Current :=
                 Self.Model.Index
                  (0, Current.Column, Self.Root_Index);
            end if;

         when Qt4.Abstract_Item_Views.Move_Right
           | Qt4.Abstract_Item_Views.Move_Down
         =>
            if Current.Row < Self.Rows (Current) - 1 then
               Current :=
                 Self.Model.Index
                  (Current.Row + 1, Current.Column, Self.Root_Index);

            else
               Current :=
                 Self.Model.Index
                  (Self.Rows (Current), Current.Column, Self.Root_Index);
            end if;

         when others =>
            null;
      end case;

      Self.Viewport.Update;

      return Current;
   end Move_Cursor;

   -----------------
   -- Paint_Event --
   -----------------

   overriding
   procedure Paint_Event
    (Self  : not null access Pie_View;
     Event : not null access Qt4.Paint_Events.Q_Paint_Event'Class)
   is
      use type Qt4.Model_Indices.Q_Model_Index;
      use type Qt4.Styles.State;

      Selection  : constant not null access
        Qt4.Item_Selection_Models.Q_Item_Selection_Model'Class
          := Self.Selection_Model;
      Option     : constant
        Qt4.Style_Option_View_Items.Q_Style_Option_View_Item
          := Self.View_Options;
      Background : constant Qt4.Brushes.Q_Brush := Option.Palette.Base;
      Foreground : constant Qt4.Pens.Q_Pen
        := Qt4.Pens.Create (Option.Palette.Color (Qt4.Palettes.Window_Text));
      Painter    : Qt4.Painters.Q_Painter
        := Qt4.Painters.Create (Self.Viewport);

      --  Viewport rectangles

      Pie_Rect   : constant Qt4.Rects.Q_Rect
        := Qt4.Rects.Create
            (Self.Margin, Self.Margin, Self.Pie_Size, Self.Pie_Size);

      Start_Angle : Qt4.Q_Real := 0.0;
      Key_Number  : Qt4.Q_Integer := 0;

   begin
      Painter.Set_Render_Hint (Qt4.Painters.Antialiasing);

      Painter.Fill_Rect (Event.Rect, Background);
      Painter.Set_Pen (Foreground);

      if Self.Valid_Items > 0 then
         Painter.Save;
         Painter.Translate
          (Qt4.Q_Real (Pie_Rect.X - Self.Horizontal_Scroll_Bar.Value),
           Qt4.Q_Real (Pie_Rect.Y - Self.Vertical_Scroll_Bar.Value));
         Painter.Draw_Ellipse (0, 0, Self.Pie_Size, Self.Pie_Size);

         for Row in 0 .. Self.Model.Row_Count (Self.Root_Index) - 1 loop
            declare
               Index : constant Qt4.Model_Indices.Q_Model_Index
                 := Self.Model.Index (Row, 1, Self.Root_Index);
               Value : constant Qt4.Q_Real
                 := Get_Double_Value (Self.Model.Data (Index));

            begin
               if Value > 0.0 then
                  declare
                     Angle : constant Qt4.Q_Real
                       := 360.0 * Value / Self.Total_Value;
                     Color_Index : constant Qt4.Model_Indices.Q_Model_Index
                       := Self.Model.Index (Row, 0, Self.Root_Index);
                     Color : constant Qt4.Colors.Q_Color
                       := Qt4.Colors.Create
                           (Self.Model.Data
                             (Color_Index, Qt4.Decoration_Role).To_String);

                  begin
                     if Self.Current_Index = Index then
                        Painter.Set_Brush
                         (Qt4.Brushes.Create (Color, Qt4.Dense_4_Pattern));

                     elsif Selection.Is_Selected (Index) then
                        Painter.Set_Brush
                         (Qt4.Brushes.Create (Color, Qt4.Dense_3_Pattern));

                     else
                        Painter.Set_Brush (Qt4.Brushes.Create (Color));
                     end if;

                     Painter.Draw_Pie
                      (0,
                       0,
                       Self.Pie_Size,
                       Self.Pie_Size,
                       Qt4.Q_Integer (Start_Angle * 16.0),
                       Qt4.Q_Integer (Angle * 16.0));

                     Start_Angle := Start_Angle + Angle;
                  end;
              end if;
            end;
        end loop;

        Painter.Restore;

        for Row in 0 .. Self.Model.Row_Count (Self.Root_Index) - 1 loop
            declare
               Index : constant Qt4.Model_Indices.Q_Model_Index
                 := Self.Model.Index (Row, 1, Self.Root_Index);
               Value : constant Qt4.Q_Real
                 := Get_Double_Value (Self.Model.Data (Index));

            begin
               if Value > 0.0 then
                  declare
                     Label_Index : constant Qt4.Model_Indices.Q_Model_Index
                       := Self.Model.Index (Row, 0, Self.Root_Index);
                     Option      : constant
                       Qt4.Style_Option_View_Items.Q_Style_Option_View_Item
                         := Self.View_Options;

                  begin
                     Option.Set_Rect (Self.Visual_Rect (Label_Index));

                     if Selection.Is_Selected (Label_Index) then
                        Option.Set_State
                         (Option.State + Qt4.Styles.State_Selected);
                     end if;

                     if Self.Current_Index = Label_Index then
                        Option.Set_State
                         (Option.State + Qt4.Styles.State_Has_Focus);
                     end if;

                     Self.Item_Delegate.Paint (Painter, Option, Label_Index);

                     Key_Number := Key_Number + 1;
                  end;
               end if;
            end;
         end loop;
      end if;
   end Paint_Event;

   ------------------
   -- Resize_Event --
   ------------------

   overriding procedure Resize_Event
    (Self  : not null access Pie_View;
     Event : not null access Qt4.Resize_Events.Q_Resize_Event'Class)
   is
      pragma Unreferenced (Event);

   begin
      Self.Update_Geometries;
   end Resize_Event;

   ----------
   -- Rows --
   ----------

   function Rows
    (Self  : not null access Pie_View'Class;
     Index : Qt4.Model_Indices.Q_Model_Index)
       return Qt4.Q_Integer
   is
   begin
      return Self.Model.Row_Count (Self.Model.Parent (Index));
   end Rows;

   ------------------------------
   -- Rows_About_To_Be_Removed --
   ------------------------------

   overriding procedure Rows_About_To_Be_Removed
    (Self   : not null access Pie_View;
     Parent : Qt4.Model_Indices.Q_Model_Index;
     Start  : Qt4.Q_Integer;
     Stop   : Qt4.Q_Integer)
   is
   begin
      for Row in Start .. Stop loop
         declare
             Index : constant Qt4.Model_Indices.Q_Model_Index
               := Self.Model.Index (Row, 1, Self.Root_Index);
             Value : constant Qt4.Q_Real
               := Get_Double_Value (Self.Model.Data (Index));

         begin
            if Value > 0.0 then
               Self.Total_Value := Self.Total_Value - Value;
               Self.Valid_Items := Self.Valid_Items - 1;
            end if;
         end;
      end loop;

      Qt4.Abstract_Item_Views.Directors.Q_Abstract_Item_View_Director
       (Self.all).Rows_About_To_Be_Removed (Parent, Start, Stop);
   end Rows_About_To_Be_Removed;

   -------------------
   -- Rows_Inserted --
   -------------------

   overriding procedure Rows_Inserted
    (Self   : not null access Pie_View;
     Parent : Qt4.Model_Indices.Q_Model_Index;
     Start  : Qt4.Q_Integer;
     Stop   : Qt4.Q_Integer)
   is
   begin
      for Row in Start .. Stop loop
         declare
             Index : constant Qt4.Model_Indices.Q_Model_Index
               := Self.Model.Index (Row, 1, Self.Root_Index);
             Value : constant Qt4.Q_Real
               := Get_Double_Value (Self.Model.Data (Index));

         begin
            if Value > 0.0 then
               Self.Total_Value := Self.Total_Value + Value;
               Self.Valid_Items := Self.Valid_Items + 1;
            end if;
         end;
      end loop;

      Qt4.Abstract_Item_Views.Directors.Q_Abstract_Item_View_Director
       (Self.all).Rows_Inserted (Parent, Start, Stop);
   end Rows_Inserted;

   ------------------------
   -- Scroll_Contents_By --
   ------------------------

   overriding procedure Scroll_Contents_By
    (Self : not null access Pie_View;
     Dx   : Qt4.Q_Integer;
     Dy   : Qt4.Q_Integer)
   is
   begin
      Self.Viewport.Scroll (Dx, Dy);
   end Scroll_Contents_By;

   ---------------
   -- Scroll_To --
   ---------------

   overriding procedure Scroll_To
    (Self  : not null access Pie_View;
     Index : Qt4.Model_Indices.Q_Model_Index;
     Hint  : Qt4.Abstract_Item_Views.Abstract_Item_View_Scroll_Hint
       := Qt4.Abstract_Item_Views.Ensure_Visible)
   is
      pragma Unreferenced (Hint);

      Area : constant Qt4.Rects.Q_Rect := Self.Viewport.Rect;
      Rect : constant Qt4.Rects.Q_Rect := Self.Visual_Rect (Index);

   begin
      if Rect.Left < Area.Left then
         Self.Horizontal_Scroll_Bar.Set_Value
         (Self.Horizontal_Scroll_Bar.Value + Rect.Left - Area.Left);

      elsif Rect.Right > Area.Right then
         Self.Horizontal_Scroll_Bar.Set_Value
          (Self.Horizontal_Scroll_Bar.Value +
             Qt4.Q_Integer'Min
              (Rect.Right - Area.Right, Rect.Left - Area.Left));
      end if;

      if Rect.Top < Area.Top then
         Self.Vertical_Scroll_Bar.Set_Value
          (Self.Vertical_Scroll_Bar.Value + Rect.Top - Area.Top);

      elsif Rect.Bottom > Area.Bottom then
        Self.Vertical_Scroll_Bar.Set_Value
         (Self.Vertical_Scroll_Bar.Value +
            Qt4.Q_Integer'Min
             (Rect.Bottom - Area.Bottom, Rect.Top - Area.Top));
      end if;

      Self.Update;
   end Scroll_To;

   -------------------
   -- Set_Selection --
   -------------------

   overriding procedure Set_Selection
    (Self  : not null access Pie_View;
     Rect  : Qt4.Rects.Q_Rect;
     Flags : Qt4.Item_Selection_Models.Selection_Flags)
   is
      Contents_Rect : constant Qt4.Rects.Q_Rect
        := Rect.Translated
            (Self.Horizontal_Scroll_Bar.Value,
             Self.Vertical_Scroll_Bar.Value).Normalized;
      Rows          : constant Qt4.Q_Integer
        := Self.Model.Row_Count (Self.Root_Index);
      Columns       : constant Qt4.Q_Integer
        := Self.Model.Column_Count (Self.Root_Index);
      Indices       : Qt4.Model_Index_Lists.Q_Model_Index_List;

   begin
      for Row in 0 .. Rows - 1 loop
         for Column in 0 .. Columns - 1 loop
            declare
               Index  : constant Qt4.Model_Indices.Q_Model_Index
                 := Self.Model.Index (Row, Column, Self.Root_Index);
               Region : constant Qt4.Regions.Q_Region
                 := Self.Item_Region (Index);

            begin
               if not Region.Intersects (Contents_Rect) then
                  Indices.Append (Index);
               end if;
            end;
         end loop;
      end loop;

      if Indices.Size > 0 then
         declare
            First_Row    : Qt4.Q_Integer := Indices.Item_At (0).Row;
            Last_Row     : Qt4.Q_Integer := Indices.Item_At (0).Row;
            First_Column : Qt4.Q_Integer := Indices.Item_At (0).Column;
            Last_Column  : Qt4.Q_Integer := Indices.Item_At (0).Column;
            Selection    : Qt4.Item_Selections.Q_Item_Selection;

         begin
            for J in 1 .. Indices.Size - 1 loop
               First_Row :=
                 Qt4.Q_Integer'Min (First_Row, Indices.Item_At (J).Row);
               Last_Row :=
                 Qt4.Q_Integer'Max (Last_Row, Indices.Item_At (J).Row);
               First_Column :=
                 Qt4.Q_Integer'Min (First_Column, Indices.Item_At (J).Column);
               Last_Column :=
                 Qt4.Q_Integer'Max (Last_Column, Indices.Item_At (J).Column);
            end loop;

            Selection :=
              Qt4.Item_Selections.Constructors.Create
               (Self.Model.Index (First_Row, First_Column, Self.Root_Index),
                Self.Model.Index (Last_Row, Last_Column, Self.Root_Index));
            Self.Selection_Model.Select_Item (Selection, Flags);
         end;

      else
         declare
            No_Index  : Qt4.Model_Indices.Q_Model_Index;
            Selection : constant Qt4.Item_Selections.Q_Item_Selection
              := Qt4.Item_Selections.Constructors.Create (No_Index, No_Index);

         begin
            Self.Selection_Model.Select_Item (Selection, Flags);
         end;
      end if;

      Self.Update;
   end Set_Selection;

   -----------------------
   -- Update_Geometries --
   -----------------------

   procedure Update_Geometries (Self : not null access Pie_View'Class) is
   begin
      Self.Horizontal_Scroll_Bar.Set_Page_Step
       (Qt4.Widgets.Width (Self.Viewport));
      Self.Horizontal_Scroll_Bar.Set_Range
       (0,
        Qt4.Q_Integer'Max
         (0, 2 * Self.Total_Size - Qt4.Widgets.Width (Self.Viewport)));

      Self.Vertical_Scroll_Bar.Set_Page_Step
       (Qt4.Widgets.Height (Self.Viewport));
      Self.Vertical_Scroll_Bar.Set_Range
       (0,
        Qt4.Q_Integer'Max
         (0, Self.Total_Size - Qt4.Widgets.Height (Self.Viewport)));
   end Update_Geometries;

   ---------------------
   -- Vertical_Offset --
   ---------------------

   overriding function Vertical_Offset
    (Self : not null access constant Pie_View)
       return Qt4.Q_Integer
   is
   begin
      return Self.Vertical_Scroll_Bar.Value;
   end Vertical_Offset;

   -----------------
   -- Visual_Rect --
   -----------------

   overriding function Visual_Rect
    (Self  : not null access constant Pie_View;
     Index : Qt4.Model_Indices.Q_Model_Index)
       return Qt4.Rects.Q_Rect
   is
      Tmp_Rect : constant Qt4.Rects.Q_Rect := Self.all.Item_Rect (Index);

   begin
      if Tmp_Rect.Is_Valid then
         return
           Qt4.Rects.Create
            (Tmp_Rect.Left - Self.Horizontal_Scroll_Bar.Value,
             Tmp_Rect.Top - Self.Vertical_Scroll_Bar.Value,
             Tmp_Rect.Width,
             Tmp_Rect.Height);

      else
         return Tmp_Rect;
      end if;
   end Visual_Rect;

   ---------------------------------
   -- Visual_Region_For_Selection --
   ---------------------------------

   overriding function Visual_Region_For_Selection
    (Self      : not null access constant Pie_View;
     Selection : Qt4.Item_Selections.Q_Item_Selection)
       return Qt4.Regions.Q_Region
   is
      use type Qt4.Regions.Q_Region;

      Ranges : constant Qt4.Q_Integer := Selection.Count;
      Region : Qt4.Regions.Q_Region;

   begin
      if Ranges = 0 then
         return Qt4.Regions.Create (Qt4.Rects.Create);
      end if;

      for J in 0 .. Ranges - 1 loop
         declare
            R : constant Qt4.Item_Selection_Ranges.Q_Item_Selection_Range
              := Selection.Item_At (J);

         begin
            for Row in R.Top .. R.Bottom loop
               for Col in R.Left .. R.Right loop
                  declare
                      Index : constant Qt4.Model_Indices.Q_Model_Index
                        := Self.Model.Index (Row, Col, Self.Root_Index);

                  begin
                     Region :=
                       Region.United
                        (Qt4.Regions.Create (Self.Visual_Rect (Index)));
                  end;
               end loop;
            end loop;
         end;
      end loop;

      return Region;
   end Visual_Region_For_Selection;

end Pie_Views;
