summaryrefslogtreecommitdiffstats
path: root/win/rfbplayer/PlayerToolBar.cxx
blob: 3056f283cbf94e2e46f33d634627d5bc5006de03 (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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/* Copyright (C) 2005 TightVNC Team.  All Rights Reserved.
 *    
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT 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
 * along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 * USA.
 */

// -=- PlayerToolBar.cxx

#include <rfbplayer/rfbplayer.h>
#include <rfbplayer/resource.h>

PlayerToolBar::PlayerToolBar() 
: ToolBar(), hFont(0), timeStatic(0), speedEdit(0), posTrackBar(0),
  speedUpDown(0), sliderDragging(false), sliderStepMs(0)
{
}

void PlayerToolBar::create(RfbPlayer *player_, HWND parentHwnd_) {
  HDC hdc;
  SIZE sz;
  RECT tRect;
  NONCLIENTMETRICS nonClientMetrics;

  player = player_;

  // Get the default font for the main menu
  nonClientMetrics.cbSize = sizeof(NONCLIENTMETRICS);
  if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &nonClientMetrics, 0))
    MessageBox(0, "Can't access to the system font.", 
               "RfbPlayer", MB_OK | MB_ICONERROR);
  nonClientMetrics.lfMenuFont.lfHeight = 16;
  hFont = CreateFontIndirect(&nonClientMetrics.lfMenuFont);

  // Create the toolbar panel
  ToolBar::create(ID_TOOLBAR, parentHwnd_,
                  WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | CCS_NORESIZE);
  addBitmap(4, IDB_TOOLBAR);

  // Create the control buttons
  addButton(0, ID_PLAY);
  addButton(1, ID_PAUSE);
  addButton(2, ID_STOP);
  addButton(0, 0, TBSTATE_ENABLED, TBSTYLE_SEP);

  // Create the static control for the time output
  timeStatic = CreateWindowEx(0, "Static", "00m:00s (00m:00s)", 
    WS_CHILD | WS_VISIBLE, 0, 0, 20, 20, getHandle(), (HMENU)ID_TIME_STATIC, 
    GetModuleHandle(0), 0);
  SendMessage(timeStatic, WM_SETFONT,(WPARAM) hFont, TRUE);
  hdc = GetDC(timeStatic);
  SelectObject(hdc, hFont);
  GetTextExtentPoint32(hdc, "00m:00s (00m:00s)", 16, &sz);
  addButton(sz.cx + 10, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
  addButton(0, 10, TBSTATE_ENABLED, TBSTYLE_SEP);
  getButtonRect(4, &tRect);
  MoveWindow(timeStatic, tRect.left, tRect.top+2, tRect.right-tRect.left, 
    tRect.bottom-tRect.top, FALSE);
    
  // Create the trackbar control for the time position
  addButton(200, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
  getButtonRect(6, &tRect);
  posTrackBar = CreateWindowEx(0, TRACKBAR_CLASS, "Trackbar Control", 
    WS_CHILD | WS_VISIBLE | TBS_AUTOTICKS | TBS_ENABLESELRANGE,
    tRect.left, tRect.top, tRect.right-tRect.left, tRect.bottom-tRect.top,
    parentHwnd, (HMENU)ID_POS_TRACKBAR, GetModuleHandle(0), 0);
  // It's need to send notify messages to toolbar parent window
  SetParent(posTrackBar, getHandle());
  addButton(0, 10, TBSTATE_ENABLED, TBSTYLE_SEP);

  // Create the label with "Speed:" caption
  HWND speedStatic = CreateWindowEx(0, "Static", "Speed:", WS_CHILD | WS_VISIBLE, 
    0, 0, 5, 5, getHandle(), (HMENU)ID_SPEED_STATIC, GetModuleHandle(0), 0);
  SendMessage(speedStatic, WM_SETFONT,(WPARAM) hFont, TRUE);
  hdc = GetDC(speedStatic);
  SelectObject(hdc, hFont);
  GetTextExtentPoint32(hdc, "Speed:", 6, &sz);
  addButton(sz.cx + 10, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
  getButtonRect(8, &tRect);
  MoveWindow(speedStatic, tRect.left, tRect.top+2, tRect.right-tRect.left, 
    tRect.bottom-tRect.top, FALSE);

  // Create the edit control and the spin for the speed managing
  addButton(60, 0, TBSTATE_ENABLED, TBSTYLE_SEP);
  getButtonRect(9, &tRect);
  speedEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "Edit", "1.00", 
    WS_CHILD | WS_VISIBLE | ES_RIGHT, tRect.left, tRect.top, 
    tRect.right-tRect.left, tRect.bottom-tRect.top, parentHwnd,
    (HMENU)ID_SPEED_EDIT, GetModuleHandle(0), 0);
  SendMessage(speedEdit, WM_SETFONT,(WPARAM) hFont, TRUE);
  // It's need to send notify messages to toolbar parent window
  SetParent(speedEdit, getHandle());

  speedUpDown = CreateUpDownControl(WS_CHILD | WS_VISIBLE  
    | WS_BORDER | UDS_ALIGNRIGHT, 0, 0, 0, 0, getHandle(),
    ID_SPEED_UPDOWN, GetModuleHandle(0), speedEdit, 20, 1, 2);

  // Resize the toolbar window
  autoSize();
}

void PlayerToolBar::init(long sessionTimeMs_) {
  sessionTimeMs = sessionTimeMs_;

  setSessionTimeStr(sessionTimeMs);
  SendMessage(posTrackBar, TBM_SETRANGE, 
    TRUE, MAKELONG(0, min(sessionTimeMs / 1000, MAX_POS_TRACKBAR_RANGE)));
  if (sessionTimeMs == 0) {
    sliderStepMs = 1;
  } else {
    sliderStepMs = sessionTimeMs / SendMessage(posTrackBar, TBM_GETRANGEMAX, 0, 0);
  }
  updatePos(0);
}

void PlayerToolBar::enable() {
  enableButton(ID_PLAY, true);
  enableButton(ID_PAUSE, true);
  enableButton(ID_STOP, true);
  enableButton(ID_FULLSCREEN, true);
  EnableWindow(posTrackBar, true);
  EnableWindow(speedEdit, true);
  EnableWindow(speedUpDown, true);
}

void PlayerToolBar::disable() {
  enableButton(ID_PLAY, false);
  enableButton(ID_PAUSE, false);
  enableButton(ID_STOP, false);
  enableButton(ID_FULLSCREEN, false);
  EnableWindow(posTrackBar, false);
  EnableWindow(speedEdit, false);
  EnableWindow(speedUpDown, false);
}

LRESULT PlayerToolBar::processWM_COMMAND(WPARAM wParam, LPARAM lParam) {
  switch (LOWORD(wParam)) {

  case ID_RETURN:
    // Update the speed if return pressed in speedEdit
    if (getSpeedEditHwnd() == GetFocus()) {
      char speedStr[20], *stopStr;
      GetWindowText(getSpeedEditHwnd(), speedStr, sizeof(speedStr));
      double speed = strtod(speedStr, &stopStr);
      if (speed > 0) {
        speed = min(MAX_SPEED, speed);
      } else {
        speed = player->getSpeed();
      }
      player->setSpeed(speed);
      return FALSE;
    }
  }

  return TRUE;
}

LRESULT PlayerToolBar::processWM_HSCROLL(WPARAM wParam, LPARAM lParam) {
  long Pos = SendMessage(posTrackBar, TBM_GETPOS, 0, 0);
  Pos *= sliderStepMs;

  switch (LOWORD(wParam)) { 
  case TB_PAGEUP:
  case TB_PAGEDOWN:
  case TB_LINEUP:
  case TB_LINEDOWN:
  case TB_THUMBTRACK:
    sliderDragging = true;
    updatePos(Pos);
    return FALSE;
  case TB_THUMBPOSITION:
  case TB_ENDTRACK: 
    player->setPos(Pos);
    player->setPaused(player->isPaused());;
    updatePos(Pos);
    sliderDragging = false;
    return FALSE;
  default:
    break;
  }
  
  return TRUE;
}

LRESULT PlayerToolBar::processWM_NOTIFY(WPARAM wParam, LPARAM lParam) {
  switch (((NMHDR*)lParam)->code) {
  case UDN_DELTAPOS:
    if ((int)wParam == ID_SPEED_UPDOWN) {
      char speedStr[20] = "\0";
      DWORD speedRange = SendMessage(speedUpDown, UDM_GETRANGE, 0, 0);
      LPNM_UPDOWN upDown = (LPNM_UPDOWN)lParam;
      double speed;

      // The out of range checking
      if (upDown->iDelta > 0) {
        speed = min(upDown->iPos + upDown->iDelta, LOWORD(speedRange)) * 0.5;
      } else {
        // It's need to round the UpDown position
        if ((upDown->iPos * 0.5) != player->getSpeed()) {
          upDown->iDelta = 0;
        }
        speed = max(upDown->iPos + upDown->iDelta, HIWORD(speedRange)) * 0.5;
      }
      player->setSpeed(speed);
    }
  }

  // We always return TRUE to prevent the change in the updown contol 
  // position. The control's position changes in the RfbPlayer::setSpeed().
  return TRUE;
}

void PlayerToolBar::updatePos(long newPos) {
  // Update time pos in static control
  char timePos[30] = "\0";
  long time = newPos / 1000;
  sprintf(timePos, "%.2um:%.2us (%s)", time/60, time%60, fullSessionTimeStr);
  SetWindowText(timeStatic, timePos);

  // Update the position of slider
  if (!sliderDragging) {
    double error = SendMessage(posTrackBar, TBM_GETPOS, 0, 0) * 
      sliderStepMs / double(newPos);
    if (!((error > 1 - CALCULATION_ERROR) && (error <= 1 + CALCULATION_ERROR))) {
      SendMessage(posTrackBar, TBM_SETPOS, TRUE, newPos / sliderStepMs);
    }
  }
}

void PlayerToolBar::setSessionTimeStr(long sessionTimeMs) {
  sprintf(fullSessionTimeStr, "%.2um:%.2us", 
    sessionTimeMs / 1000 / 60, sessionTimeMs / 1000 % 60);
}

void PlayerToolBar::setTimePos(long pos) {
  SendMessage(posTrackBar, TBM_SETPOS, TRUE, pos);
}