1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.calendar
17 
18 import android.graphics.Rect
19 
20 class EventGeometry {
21     // This is the space from the grid line to the event rectangle.
22     private var mCellMargin = 0
23     private var mMinuteHeight = 0f
24     private var mHourGap = 0f
25     private var mMinEventHeight = 0f
setCellMarginnull26     fun setCellMargin(cellMargin: Int) {
27         mCellMargin = cellMargin
28     }
29 
setHourGapnull30     fun setHourGap(gap: Float) {
31         mHourGap = gap
32     }
33 
setMinEventHeightnull34     fun setMinEventHeight(height: Float) {
35         mMinEventHeight = height
36     }
37 
setHourHeightnull38     fun setHourHeight(height: Float) {
39         mMinuteHeight = height / 60.0f
40     }
41 
42     // Computes the rectangle coordinates of the given event on the screen.
43     // Returns true if the rectangle is visible on the screen.
computeEventRectnull44     fun computeEventRect(date: Int, left: Int, top: Int, cellWidth: Int, event: Event): Boolean {
45         if (event.drawAsAllday()) {
46             return false
47         }
48         val cellMinuteHeight = mMinuteHeight
49         val startDay: Int = event.startDay
50         val endDay: Int = event.endDay
51         if (startDay > date || endDay < date) {
52             return false
53         }
54         var startTime: Int = event.startTime
55         var endTime: Int = event.endTime
56 
57         // If the event started on a previous day, then show it starting
58         // at the beginning of this day.
59         if (startDay < date) {
60             startTime = 0
61         }
62 
63         // If the event ends on a future day, then show it extending to
64         // the end of this day.
65         if (endDay > date) {
66             endTime = DayView.MINUTES_PER_DAY
67         }
68         val col: Int = event.column
69         val maxCols: Int = event.maxColumns
70         val startHour = startTime / 60
71         var endHour = endTime / 60
72 
73         // If the end point aligns on a cell boundary then count it as
74         // ending in the previous cell so that we don't cross the border
75         // between hours.
76         if (endHour * 60 == endTime) endHour -= 1
77         event.top = top as Float
78         event.top += (startTime * cellMinuteHeight).toInt()
79         event.top += startHour * mHourGap
80         event.bottom = top as Float
81         event.bottom += (endTime * cellMinuteHeight).toInt()
82         event.bottom += endHour * mHourGap - 1
83 
84         // Make the rectangle be at least mMinEventHeight pixels high
85         if (event.bottom < event.top + mMinEventHeight) {
86             event.bottom = event.top + mMinEventHeight
87         }
88         val colWidth = (cellWidth - (maxCols + 1) * mCellMargin).toFloat() / maxCols.toFloat()
89         event.left = left + col * (colWidth + mCellMargin)
90         event.right = event.left + colWidth
91         return true
92     }
93 
94     /**
95      * Returns true if this event intersects the selection region.
96      */
eventIntersectsSelectionnull97     fun eventIntersectsSelection(event: Event, selection: Rect): Boolean {
98         return if (event.left < selection.right && event.right >= selection.left &&
99             event.top < selection.bottom && event.bottom >= selection.top) {
100             true
101         } else false
102     }
103 
104     /**
105      * Computes the distance from the given point to the given event.
106      */
pointToEventnull107     fun pointToEvent(x: Float, y: Float, event: Event): Float {
108         val left: Float = event.left
109         val right: Float = event.right
110         val top: Float = event.top
111         val bottom: Float = event.bottom
112         if (x >= left) {
113             if (x <= right) {
114                 return if (y >= top) {
115                     if (y <= bottom) {
116                         // x,y is inside the event rectangle
117                         0f
118                     } else y - bottom
119                     // x,y is below the event rectangle
120                 } else top - y
121                 // x,y is above the event rectangle
122             }
123 
124             // x > right
125             val dx = x - right
126             if (y < top) {
127                 // the upper right corner
128                 val dy = top - y
129                 return (Math.sqrt(dx as Double * dx + dy as Double * dy)) as Float
130             }
131             if (y > bottom) {
132                 // the lower right corner
133                 val dy = y - bottom
134                 return (Math.sqrt(dx as Double * dx + dy as Double * dy)) as Float
135             }
136             // x,y is to the right of the event rectangle
137             return dx
138         }
139         // x < left
140         val dx = left - x
141         if (y < top) {
142             // the upper left corner
143             val dy = top - y
144             return (Math.sqrt(dx as Double * dx + dy as Double * dy)) as Float
145         }
146         if (y > bottom) {
147             // the lower left corner
148             val dy = y - bottom
149             return (Math.sqrt(dx as Double * dx + dy as Double * dy)) as Float
150         }
151         // x,y is to the left of the event rectangle
152         return dx
153     }
154 }