summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa/wrench_menu_controller.mm
blob: 80ceed9df73c6e6447e88ea167945ce68fe49ddc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "chrome/browser/cocoa/wrench_menu_controller.h"

#include "app/menus/menu_model.h"
#include "base/sys_string_conversions.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#import "chrome/browser/cocoa/toolbar_controller.h"
#include "chrome/browser/wrench_menu_model.h"

@interface WrenchMenuController (Private)
- (WrenchMenuModel*)wrenchMenuModel;
- (void)adjustPositioning;
@end

@implementation WrenchMenuController

- (id)init {
  self = [super init];
  return self;
}

- (void)addItemToMenu:(NSMenu*)menu
              atIndex:(NSInteger)index
            fromModel:(menus::MenuModel*)model
           modelIndex:(int)modelIndex {
  // Non-button item types should be built as normal items.
  menus::MenuModel::ItemType type = model->GetTypeAt(modelIndex);
  if (type != menus::MenuModel::TYPE_BUTTON_ITEM) {
    [super addItemToMenu:menu
                 atIndex:index
               fromModel:model
              modelIndex:modelIndex];
    return;
  }

  // Handle the special-cased menu items.
  int command_id = model->GetCommandIdAt(modelIndex);
  scoped_nsobject<NSMenuItem> customItem(
      [[NSMenuItem alloc] initWithTitle:@""
                                 action:nil
                          keyEquivalent:@""]);
  switch (command_id) {
    case IDC_EDIT_MENU:
      DCHECK(editItem_);
      [customItem setView:editItem_];
      break;
    case IDC_ZOOM_MENU:
      DCHECK(zoomItem_);
      [customItem setView:zoomItem_];
      break;
    default:
      NOTREACHED();
      break;
  }
  [self adjustPositioning];
  [menu insertItem:customItem.get() atIndex:index];
}

- (NSMenu*)menu {
  NSMenu* menu = [super menu];
  if (![menu delegate]) {
    [menu setDelegate:self];
  }
  return menu;
}

- (void)menuWillOpen:(NSMenu*)menu {
  NSString* title = base::SysUTF16ToNSString(
      [self wrenchMenuModel]->GetLabelForCommandId(IDC_ZOOM_PERCENT_DISPLAY));
  [[zoomItem_ viewWithTag:IDC_ZOOM_PERCENT_DISPLAY] setTitle:title];

  NSImage* icon = [self wrenchMenuModel]->browser()->window()->IsFullscreen() ?
      [NSImage imageNamed:NSImageNameExitFullScreenTemplate] :
          [NSImage imageNamed:NSImageNameEnterFullScreenTemplate];
  [zoomFullScreen_ setImage:icon];
}

// Used to dispatch commands from the Wrench menu. The custom items within the
// menu cannot be hooked up directly to First Responder because the window in
// which the controls reside is not the BrowserWindowController, but a
// NSCarbonMenuWindow; this screws up the typical |-commandDispatch:| system.
- (IBAction)dispatchWrenchMenuCommand:(id)sender {
  NSInteger tag = [sender tag];

  // NSSegmentedControls (used for the Edit item) need a little help to get the
  // command_id of the pressed item.
  if ([sender isKindOfClass:[NSSegmentedControl class]])
    tag = [[sender cell] tagForSegment:[sender selectedSegment]];

  // The custom views within the Wrench menu are abnormal and keep the menu open
  // after a target-action. Close the menu manually.
  // TODO(rsesek): It'd be great if the zoom buttons didn't have to close the
  // menu. See http://crbug.com/48679 for more info.
  [menu_ cancelTracking];
  [self wrenchMenuModel]->ExecuteCommand(tag);
}

- (WrenchMenuModel*)wrenchMenuModel {
  return static_cast<WrenchMenuModel*>(model_);
}

// Fit the localized strings into the Cut/Copy/Paste control, then resize the
// whole menu item accordingly.
- (void)adjustPositioning {
  NSRect itemFrame = [editItem_ frame];
  NSRect controlFrame = [editControl_ frame];

  CGFloat originalControlWidth = NSWidth(controlFrame);
  // Maintain the carefully pixel-pushed gap between the edge of the menu and
  // the rightmost control.
  CGFloat edge = NSWidth(itemFrame) -
      (controlFrame.origin.x + originalControlWidth);

  // Resize the edit segmented control to fit the localized strings.
  [editControl_ sizeToFit];
  controlFrame = [editControl_ frame];
  CGFloat resizeAmount = NSWidth(controlFrame) - originalControlWidth;

  // Adjust the size of the entire menu item to account for changes in the size
  // of the segmented control.
  itemFrame.size.width += resizeAmount;
  [editItem_ setFrame:itemFrame];

  // Keep the spacing between the right edges of the menu and the control.
  controlFrame.origin.x = NSWidth(itemFrame) - edge - NSWidth(controlFrame);
  [editControl_ setFrame:controlFrame];
}

@end  // @implementation WrenchMenuController