Native Mac OS X OtaClock replica
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MainWindow.m 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. //
  2. // MainWindow.m
  3. // OtaClock
  4. //
  5. // Created by Thomas Buck on 16.08.15.
  6. // Copyright (c) 2015 xythobuz. All rights reserved.
  7. //
  8. #import "MainView.h"
  9. #import "MainWindow.h"
  10. #define RESIZE_START 1
  11. #define RESIZE_END 5
  12. #define RESIZE_STEP 1
  13. #define CONFIG_START_SCALE @"window_scale"
  14. #define CONFIG_KEEP_POSITION @"keep_position"
  15. #define CONFIG_KEEP_ON_TOP @"keep_on_top"
  16. #define MOUSE_CENTER_X 67
  17. #define MOUSE_CENTER_Y 47
  18. #define EYE_BLINK 0
  19. #define EYE_TOP_RIGHT 4
  20. #define EYE_TOP_LEFT 2
  21. #define EYE_BOTTOM_RIGHT 3
  22. #define EYE_BOTTOM_LEFT 1
  23. @interface MainWindow ()
  24. @property (assign) NSSize defaultSize;
  25. @property (assign) NSInteger startScale;
  26. @property (assign) NSInteger lastEyeState;
  27. @property (weak) IBOutlet MainView *mainView;
  28. @property (weak) IBOutlet NSMenuItem *lockPositionItem;
  29. @property (weak) IBOutlet NSMenuItem *keepOnTopItem;
  30. @property (weak) IBOutlet NSMenuItem *changeSize1;
  31. @property (weak) IBOutlet NSMenuItem *changeSize2;
  32. @property (weak) IBOutlet NSMenuItem *changeSize3;
  33. @property (weak) IBOutlet NSMenuItem *changeSize4;
  34. @property (weak) IBOutlet NSMenuItem *changeSize5;
  35. @end
  36. @implementation MainWindow
  37. @synthesize dragStart;
  38. @synthesize keepPosition;
  39. @synthesize defaultSize;
  40. @synthesize startScale;
  41. @synthesize lastEyeState;
  42. - (id)initWithContentRect:(NSRect)contentRect
  43. styleMask:(NSUInteger)aStyle
  44. backing:(NSBackingStoreType)bufferingType
  45. defer:(BOOL)flag {
  46. self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
  47. if (self != nil) {
  48. [self setAlphaValue:1.0];
  49. [self setOpaque:NO];
  50. lastEyeState = EYE_TOP_LEFT;
  51. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  52. // load and see if window should be kept on top
  53. if ([defaults objectForKey:CONFIG_KEEP_ON_TOP] != nil) {
  54. if ([defaults boolForKey:CONFIG_KEEP_ON_TOP]) {
  55. [self setLevel:NSFloatingWindowLevel];
  56. }
  57. }
  58. // load and see if window pos should be fixed
  59. if ([defaults objectForKey:CONFIG_KEEP_POSITION] == nil) {
  60. keepPosition = NO;
  61. } else {
  62. keepPosition = [defaults boolForKey:CONFIG_KEEP_POSITION];
  63. }
  64. // load window scale factor
  65. if ([defaults objectForKey:CONFIG_START_SCALE] == nil) {
  66. startScale = 1;
  67. } else {
  68. startScale = [defaults integerForKey:CONFIG_START_SCALE];
  69. }
  70. }
  71. [self setAcceptsMouseMovedEvents:YES];
  72. [NSEvent addGlobalMonitorForEventsMatchingMask:NSMouseMovedMask handler:^(NSEvent *mouseMovedEvent) { [self mouseMoved:mouseMovedEvent]; }];
  73. return self;
  74. }
  75. - (void)setDefaultBackgroundSize:(NSSize)size {
  76. defaultSize = size;
  77. NSRect frame = [self frame];
  78. frame.size = defaultSize;
  79. frame.size.width *= startScale;
  80. frame.size.height *= startScale;
  81. // We need to do all initialization of view state in here, because they are not ready in init
  82. if (keepPosition) [self.lockPositionItem setState:NSOnState];
  83. if ([self level] == NSFloatingWindowLevel) [self.keepOnTopItem setState:NSOnState];
  84. if (startScale == 1) [self.changeSize1 setState:NSOnState];
  85. if (startScale == 2) [self.changeSize2 setState:NSOnState];
  86. if (startScale == 3) [self.changeSize3 setState:NSOnState];
  87. if (startScale == 4) [self.changeSize4 setState:NSOnState];
  88. if (startScale == 5) [self.changeSize5 setState:NSOnState];
  89. [[self.mainView render] drawWith:lastEyeState]; // Initialize render image
  90. [self setFrame:frame display:YES];
  91. }
  92. - (IBAction)changeSize:(NSMenuItem *)sender {
  93. NSRect frame = [self frame];
  94. [self.changeSize1 setState:NSOffState];
  95. [self.changeSize2 setState:NSOffState];
  96. [self.changeSize3 setState:NSOffState];
  97. [self.changeSize4 setState:NSOffState];
  98. [self.changeSize5 setState:NSOffState];
  99. BOOL found = NO;
  100. for (int i = RESIZE_START; i <= RESIZE_END; i += RESIZE_STEP) {
  101. NSString *title = [NSString stringWithFormat:@"%dx", i];
  102. if ([[sender title] isEqualToString:title]) {
  103. [sender setState:NSOnState];
  104. NSSize newSize = defaultSize;
  105. newSize.height *= i;
  106. newSize.width *= i;
  107. frame.size = newSize;
  108. found = YES;
  109. startScale = i;
  110. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  111. [defaults setInteger:i forKey:CONFIG_START_SCALE];
  112. [defaults synchronize];
  113. break;
  114. }
  115. }
  116. if (found == NO) {
  117. NSLog(@"Unknown changeSize sender: %@", sender);
  118. } else {
  119. [self setFrame:frame display:YES];
  120. }
  121. }
  122. - (IBAction)lockPosition:(NSMenuItem *)sender {
  123. BOOL state = [sender state];
  124. if (state == NSOffState) {
  125. // Lock position
  126. state = NSOnState;
  127. [sender setState:state];
  128. self.keepPosition = YES;
  129. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  130. [defaults setBool:YES forKey:CONFIG_KEEP_POSITION];
  131. [defaults synchronize];
  132. } else {
  133. // Unlock position
  134. state = NSOffState;
  135. [sender setState:state];
  136. self.keepPosition = NO;
  137. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  138. [defaults setBool:NO forKey:CONFIG_KEEP_POSITION];
  139. [defaults synchronize];
  140. }
  141. }
  142. - (IBAction)keepOnTop:(NSMenuItem *)sender {
  143. BOOL state = [sender state];
  144. if (state == NSOffState) {
  145. // Keep window on top
  146. state = NSOnState;
  147. [sender setState:state];
  148. [self setLevel:NSFloatingWindowLevel];
  149. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  150. [defaults setBool:YES forKey:CONFIG_KEEP_ON_TOP];
  151. [defaults synchronize];
  152. } else {
  153. // Don't keep window on top
  154. state = NSOffState;
  155. [sender setState:state];
  156. [self setLevel:NSNormalWindowLevel];
  157. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  158. [defaults setBool:NO forKey:CONFIG_KEEP_ON_TOP];
  159. [defaults synchronize];
  160. }
  161. }
  162. - (BOOL)canBecomeKeyWindow {
  163. return YES;
  164. }
  165. - (void)mouseDown:(NSEvent *)theEvent {
  166. dragStart = [theEvent locationInWindow];
  167. }
  168. - (void)mouseDragged:(NSEvent *)theEvent {
  169. NSRect screenVisibleFrame = [[NSScreen mainScreen] visibleFrame];
  170. NSRect windowFrame = [self frame];
  171. NSPoint newOrigin = windowFrame.origin;
  172. if (self.keepPosition == NO) {
  173. NSPoint currentLocation = [theEvent locationInWindow];
  174. newOrigin.x += (currentLocation.x - dragStart.x);
  175. newOrigin.y += (currentLocation.y - dragStart.y);
  176. if ((newOrigin.y + windowFrame.size.height) > (screenVisibleFrame.origin.y + screenVisibleFrame.size.height)) {
  177. newOrigin.y = screenVisibleFrame.origin.y + (screenVisibleFrame.size.height - windowFrame.size.height);
  178. }
  179. [self setFrameOrigin:newOrigin];
  180. }
  181. }
  182. - (void)mouseMoved:(NSEvent *)theEvent {
  183. NSPoint mousePoint = [NSEvent mouseLocation];
  184. mousePoint.x -= [self frame].origin.x;
  185. mousePoint.y -= [self frame].origin.y;
  186. BOOL top = (mousePoint.y > (MOUSE_CENTER_Y * startScale));
  187. BOOL right = (mousePoint.x > (MOUSE_CENTER_X * startScale));
  188. NSInteger eyeState = EYE_BOTTOM_LEFT;
  189. if (top && right) {
  190. eyeState = EYE_TOP_RIGHT;
  191. } else if (top && (!right)) {
  192. eyeState = EYE_TOP_LEFT;
  193. } else if ((!top) && right) {
  194. eyeState = EYE_BOTTOM_RIGHT;
  195. }
  196. if (eyeState != lastEyeState) {
  197. lastEyeState = eyeState;
  198. [[self.mainView render] drawWith:lastEyeState];
  199. self.mainView.needsDisplay = YES;
  200. }
  201. }
  202. @end