Pārlūkot izejas kodu

button support, win32

David Rose 16 gadi atpakaļ
vecāks
revīzija
3c5259d286

+ 1 - 1
direct/src/plugin/Sources.pp

@@ -89,7 +89,7 @@
   #define INSTALL_HEADERS \
   #define INSTALL_HEADERS \
     p3d_plugin.h
     p3d_plugin.h
 
 
-  #define WIN_SYS_LIBS user32.lib gdi32.lib shell32.lib comctl32.lib
+  #define WIN_SYS_LIBS user32.lib gdi32.lib shell32.lib comctl32.lib msimg32.lib
 
 
 #end lib_target
 #end lib_target
 
 

+ 22 - 0
direct/src/plugin/p3dWinSplashWindow.I

@@ -12,3 +12,25 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinSplashWindow::WinImageData::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+inline P3DWinSplashWindow::WinImageData::
+WinImageData() {
+  _filename_changed = false;
+  _bitmap = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinSplashWindow::WinImageData::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+inline P3DWinSplashWindow::WinImageData::
+~WinImageData() {
+  dump_image();
+}
+

+ 217 - 96
direct/src/plugin/p3dWinSplashWindow.cxx

@@ -30,11 +30,9 @@ P3DWinSplashWindow(P3DInstance *inst) :
   _thread = NULL;
   _thread = NULL;
   _thread_id = 0;
   _thread_id = 0;
   _hwnd = NULL;
   _hwnd = NULL;
-  _bitmap = NULL;
   _progress_bar = NULL;
   _progress_bar = NULL;
   _text_label = NULL;
   _text_label = NULL;
   _thread_running = false;
   _thread_running = false;
-  _image_filename_changed = false;
   _install_label_changed = false;
   _install_label_changed = false;
   _install_progress = 0.0;
   _install_progress = 0.0;
 
 
@@ -78,12 +76,33 @@ set_wparams(const P3DWindowParams &wparams) {
 void P3DWinSplashWindow::
 void P3DWinSplashWindow::
 set_image_filename(const string &image_filename, ImagePlacement image_placement) {
 set_image_filename(const string &image_filename, ImagePlacement image_placement) {
   nout << "image_filename = " << image_filename << ", thread_id = " << _thread_id << "\n";
   nout << "image_filename = " << image_filename << ", thread_id = " << _thread_id << "\n";
-  ACQUIRE_LOCK(_install_lock);
-  if (_image_filename != image_filename) {
-    _image_filename = image_filename;
-    _image_filename_changed = true;
+  WinImageData *image = NULL;
+  switch (image_placement) {
+  case IP_background:
+    image = &_background_image;
+    break;
+
+  case IP_button_ready:
+    image = &_button_ready_image;
+    set_button_range(_button_ready_image);
+    break;
+
+  case IP_button_rollover:
+    image = &_button_rollover_image;
+    break;
+   
+  case IP_button_click:
+    image = &_button_click_image;
+    break;
+  }
+  if (image != NULL) {
+    ACQUIRE_LOCK(_install_lock);
+    if (image->_filename != image_filename) {
+      image->_filename = image_filename;
+      image->_filename_changed = true;
+    }
+    RELEASE_LOCK(_install_lock);
   }
   }
-  RELEASE_LOCK(_install_lock);
 
 
   if (_thread_id != 0) {
   if (_thread_id != 0) {
     // Post a silly message to spin the message loop.
     // Post a silly message to spin the message loop.
@@ -162,6 +181,7 @@ register_window_class() {
     ZeroMemory(&wc, sizeof(WNDCLASS));
     ZeroMemory(&wc, sizeof(WNDCLASS));
     wc.lpfnWndProc = st_window_proc;
     wc.lpfnWndProc = st_window_proc;
     wc.hInstance = application;
     wc.hInstance = application;
+    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
     wc.lpszClassName = "panda3d_splash";
     wc.lpszClassName = "panda3d_splash";
     
     
     if (!RegisterClass(&wc)) {
     if (!RegisterClass(&wc)) {
@@ -258,14 +278,22 @@ thread_run() {
 
 
     ACQUIRE_LOCK(_install_lock);
     ACQUIRE_LOCK(_install_lock);
     double install_progress = _install_progress;
     double install_progress = _install_progress;
-    if (_image_filename_changed) {
-      update_image_filename(_image_filename);
-    }
-    _image_filename_changed = false;
+
+    update_image(_background_image);
+    update_image(_button_ready_image);
+    update_image(_button_rollover_image);
+    update_image(_button_click_image);
+
     if (_install_label_changed && _progress_bar != NULL) {
     if (_install_label_changed && _progress_bar != NULL) {
       update_install_label(_install_label);
       update_install_label(_install_label);
     }
     }
     _install_label_changed = false;
     _install_label_changed = false;
+
+    if (_drawn_bstate != _bstate) {
+      // The button has changed state.  Redraw it.
+      _drawn_bstate = _bstate;
+      InvalidateRect(_hwnd, NULL, TRUE);
+    }
     RELEASE_LOCK(_install_lock);
     RELEASE_LOCK(_install_lock);
 
 
     if (install_progress != last_progress) {
     if (install_progress != last_progress) {
@@ -454,19 +482,22 @@ update_install_label(const string &install_label) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DWinSplashWindow::update_image_filename
+//     Function: P3DWinSplashWindow::update_image
 //       Access: Private
 //       Access: Private
-//  Description: Loads the splash image, converts to to BITMAP form,
-//               and stores it in _bitmap.  Runs only in the
-//               sub-thread.
+//  Description: Loads the image from the named file (if it has
+//               changed), converts to to BITMAP form, and stores it
+//               in _bitmap.  Runs only in the sub-thread.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void P3DWinSplashWindow::
 void P3DWinSplashWindow::
-update_image_filename(const string &image_filename) {
-  // Clear the old image.
-  if (_bitmap != NULL) {
-    DeleteObject(_bitmap);
-    _bitmap = NULL;
+update_image(WinImageData &image) {
+  if (!image._filename_changed) {
+    // No changes.
+    return;
   }
   }
+  image._filename_changed = false;
+
+  // Clear the old image.
+  image.dump_image();
 
 
   // Since we'll be displaying a new image, we need to refresh the
   // Since we'll be displaying a new image, we need to refresh the
   // window.
   // window.
@@ -474,50 +505,59 @@ update_image_filename(const string &image_filename) {
 
 
   // Go read the image.
   // Go read the image.
   string data;
   string data;
-  ImageData image;
-  if (!read_image_data(image, data, image_filename)) {
+  if (!read_image_data(image, data, image._filename)) {
     return;
     return;
   }
   }
 
 
-  // Temp legacy support.
-  _bitmap_width = image._width;
-  _bitmap_height = image._height;
-  int num_channels =image._num_channels;
-
   // Massage the data into Windows' conventions.
   // Massage the data into Windows' conventions.
-  int row_stride = _bitmap_width * num_channels;
-  int new_row_stride = (_bitmap_width * 3);
-  // DWORD-pad the row.
-  new_row_stride = 4 * ((new_row_stride + 3) / 4);
+  int row_stride = image._width * image._num_channels;
+  int new_row_stride = (image._width * 4);
 
 
-  int new_data_length = new_row_stride * _bitmap_height;
+  int new_data_length = new_row_stride * image._height;
   char *new_data = new char[new_data_length];
   char *new_data = new char[new_data_length];
 
 
-  if (num_channels == 3) {
+  if (image._num_channels == 4) {
     // We have to reverse the order of the RGB channels: libjpeg and
     // We have to reverse the order of the RGB channels: libjpeg and
     // Windows follow an opposite convention.
     // Windows follow an opposite convention.
-    for (int yi = 0; yi < _bitmap_height; ++yi) {
+    for (int yi = 0; yi < image._height; ++yi) {
       const char *sp = data.data() + yi * row_stride;
       const char *sp = data.data() + yi * row_stride;
       char *dp = new_data + yi * new_row_stride;
       char *dp = new_data + yi * new_row_stride;
-      for (int xi = 0; xi < _bitmap_width; ++xi) {
+      for (int xi = 0; xi < image._width; ++xi) {
         dp[0] = sp[2];
         dp[0] = sp[2];
         dp[1] = sp[1];
         dp[1] = sp[1];
         dp[2] = sp[0];
         dp[2] = sp[0];
-        sp += num_channels;
-        dp += 3;
+        dp[3] = sp[3];
+        sp += 4;
+        dp += 4;
       }
       }
     }
     }
-  } else if (num_channels == 1) {
+  } else if (image._num_channels == 3) {
+    // We have to reverse the order of the RGB channels: libjpeg and
+    // Windows follow an opposite convention.
+    for (int yi = 0; yi < image._height; ++yi) {
+      const char *sp = data.data() + yi * row_stride;
+      char *dp = new_data + yi * new_row_stride;
+      for (int xi = 0; xi < image._width; ++xi) {
+        dp[0] = sp[2];
+        dp[1] = sp[1];
+        dp[2] = sp[0];
+        dp[3] = (char)0xff;
+        sp += 3;
+        dp += 4;
+      }
+    }
+  } else if (image._num_channels == 1) {
     // A grayscale image.  Replicate out the channels.
     // A grayscale image.  Replicate out the channels.
-    for (int yi = 0; yi < _bitmap_height; ++yi) {
+    for (int yi = 0; yi < image._height; ++yi) {
       const char *sp = data.data() + yi * row_stride;
       const char *sp = data.data() + yi * row_stride;
       char *dp = new_data + yi * new_row_stride;
       char *dp = new_data + yi * new_row_stride;
-      for (int xi = 0; xi < _bitmap_width; ++xi) {
+      for (int xi = 0; xi < image._width; ++xi) {
         dp[0] = sp[0];
         dp[0] = sp[0];
         dp[1] = sp[0];
         dp[1] = sp[0];
         dp[2] = sp[0];
         dp[2] = sp[0];
-        sp += num_channels;
-        dp += 3;
+        dp[3] = (char)0xff;
+        sp += 1;
+        dp += 4;
       }
       }
     }
     }
   }
   }
@@ -525,10 +565,10 @@ update_image_filename(const string &image_filename) {
   // Now load the image.
   // Now load the image.
   BITMAPINFOHEADER bmih;
   BITMAPINFOHEADER bmih;
   bmih.biSize = sizeof(bmih);
   bmih.biSize = sizeof(bmih);
-  bmih.biWidth = _bitmap_width;
-  bmih.biHeight = -_bitmap_height;
+  bmih.biWidth = image._width;
+  bmih.biHeight = -image._height;
   bmih.biPlanes = 1;
   bmih.biPlanes = 1;
-  bmih.biBitCount = 24;
+  bmih.biBitCount = 32;
   bmih.biCompression = BI_RGB;
   bmih.biCompression = BI_RGB;
   bmih.biSizeImage = 0;
   bmih.biSizeImage = 0;
   bmih.biXPelsPerMeter = 0;
   bmih.biXPelsPerMeter = 0;
@@ -540,12 +580,12 @@ update_image_filename(const string &image_filename) {
   memcpy(&bmi, &bmih, sizeof(bmih));
   memcpy(&bmi, &bmih, sizeof(bmih));
 
 
   HDC dc = GetDC(_hwnd);
   HDC dc = GetDC(_hwnd);
-  _bitmap = CreateDIBitmap(dc, &bmih, CBM_INIT, new_data, &bmi, 0);
+  image._bitmap = CreateDIBitmap(dc, &bmih, CBM_INIT, new_data, &bmi, 0);
   ReleaseDC(_hwnd, dc);
   ReleaseDC(_hwnd, dc);
 
 
   delete[] new_data;
   delete[] new_data;
 
 
-  nout << "Loaded splash file image: " << image_filename << "\n";
+  nout << "Loaded image: " << image._filename << "\n";
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -562,10 +602,10 @@ close_window() {
     _hwnd = NULL;
     _hwnd = NULL;
   }
   }
 
 
-  if (_bitmap != NULL) {
-    DeleteObject(_bitmap);
-    _bitmap = NULL;
-  }
+  _background_image.dump_image();
+  _button_ready_image.dump_image();
+  _button_rollover_image.dump_image();
+  _button_click_image.dump_image();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -578,57 +618,110 @@ void P3DWinSplashWindow::
 paint_window(HDC dc) {
 paint_window(HDC dc) {
   RECT rect;
   RECT rect;
   GetClientRect(_hwnd, &rect);
   GetClientRect(_hwnd, &rect);
-  _win_width = rect.right - rect.left;
-  _win_height = rect.bottom - rect.top;
+
+  int width = rect.right - rect.left;
+  int height = rect.bottom - rect.top;
+  if (width != _win_width || height != _win_height) {
+    _win_width = width;
+    _win_height = height;
+    set_button_range(_button_ready_image);
+  }
+
+  // Double-buffer with an offscreen bitmap first.
+  HDC bdc = CreateCompatibleDC(dc);
+  HBITMAP buffer = CreateCompatibleBitmap(dc, _win_width, _win_height);
+  SelectObject(bdc, buffer);
+
+  // Start by painting the background color.
+  FillRect(bdc, &rect, WHITE_BRUSH);
+
+  // Then paint the background image on top of that.
+  paint_image(bdc, _background_image);
+
+  // And then, paint the button, if any, on top of *that*.
+  switch (_drawn_bstate) {
+  case BS_hidden:
+    break;
+  case BS_ready:
+    paint_image(bdc, _button_ready_image);
+    break;
+  case BS_rollover:
+    if (!paint_image(bdc, _button_rollover_image)) {
+      paint_image(bdc, _button_ready_image);
+    }
+    break;
+  case BS_click:
+    if (!paint_image(bdc, _button_click_image)) {
+      paint_image(bdc, _button_ready_image);
+    }
+    break;
+  }
+
+  // Now blit the buffer to the window.
+  BitBlt(dc, 0, 0, _win_width, _win_height, bdc, 0, 0, SRCCOPY);
+
+  DeleteObject(bdc);
+  DeleteObject(buffer);
+}
   
   
-  if (_bitmap != NULL) {
-    // Paint the background splash image.
-    HDC mem_dc = CreateCompatibleDC(dc);
-    SelectObject(mem_dc, _bitmap);
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinSplashWindow::paint_image
+//       Access: Private
+//  Description: Draws the indicated image, centered within the
+//               window.  Returns true on success, false if the image
+//               is not defined.
+////////////////////////////////////////////////////////////////////
+bool P3DWinSplashWindow::
+paint_image(HDC dc, const WinImageData &image) {
+  if (image._bitmap == NULL) {
+    return false;
+  }
+
+  // Paint the background splash image.
+  HDC mem_dc = CreateCompatibleDC(dc);
+  SelectObject(mem_dc, image._bitmap);
+  
+  // Determine the relative size of bitmap and window.
+  int win_cx = _win_width / 2;
+  int win_cy = _win_height / 2;
+
+  BLENDFUNCTION bf;
+  bf.BlendOp = AC_SRC_OVER;
+  bf.BlendFlags = 0;
+  bf.SourceConstantAlpha = 0xff;
+  bf.AlphaFormat = AC_SRC_ALPHA;
+  
+  if (image._width <= _win_width && image._height <= _win_height) {
+    // The bitmap fits within the window; center it.
     
     
-    // Determine the relative size of bitmap and window.
-    int bm_width = _bitmap_width;
-    int bm_height = _bitmap_height;
+    // This is the top-left corner of the bitmap in window coordinates.
+    int p_x = win_cx - image._width / 2;
+    int p_y = win_cy - image._height / 2;
     
     
-    int win_cx = _win_width / 2;
-    int win_cy = _win_height / 2;
+    AlphaBlend(dc, p_x, p_y, image._width, image._height,
+               mem_dc, 0, 0, image._width, image._height,
+               bf);
     
     
-    if (bm_width <= _win_width && bm_height <= _win_height) {
-      // The bitmap fits within the window; center it.
-      
-      // This is the top-left corner of the bitmap in window coordinates.
-      int p_x = win_cx - bm_width / 2;
-      int p_y = win_cy - bm_height / 2;
-      
-      BitBlt(dc, p_x, p_y, bm_width, bm_height,
-             mem_dc, 0, 0, SRCCOPY);
-
-      // Now don't paint over this in the below FillRect().
-      ExcludeClipRect(dc, p_x, p_y, p_x + bm_width, p_y + bm_height);
-      
-    } else {
-      // The bitmap is larger than the window; scale it down.
-      double x_scale = (double)_win_width / (double)bm_width;
-      double y_scale = (double)_win_height / (double)bm_height;
-      double scale = min(x_scale, y_scale);
-      int sc_width = (int)(bm_width * scale);
-      int sc_height = (int)(bm_height * scale);
-      
-      int p_x = win_cx - sc_width / 2;
-      int p_y = win_cy - sc_height / 2;
-      StretchBlt(dc, p_x, p_y, sc_width, sc_height,
-                 mem_dc, 0, 0, bm_width, bm_height, SRCCOPY);
-
-      // Now don't paint over this in the below FillRect().
-      ExcludeClipRect(dc, p_x, p_y, p_x + sc_width, p_y + sc_height);
-    }
+  } else {
+    // The bitmap is larger than the window; scale it down.
+    double x_scale = (double)_win_width / (double)image._width;
+    double y_scale = (double)_win_height / (double)image._height;
+    double scale = min(x_scale, y_scale);
+    int sc_width = (int)(image._width * scale);
+    int sc_height = (int)(image._height * scale);
     
     
-    SelectObject(mem_dc, NULL);
-    DeleteDC(mem_dc);
+    int p_x = win_cx - sc_width / 2;
+    int p_y = win_cy - sc_height / 2;
+
+    AlphaBlend(dc, p_x, p_y, sc_width, sc_height,
+               mem_dc, 0, 0, image._width, image._height, 
+               bf);
   }
   }
+  
+  SelectObject(mem_dc, NULL);
+  DeleteDC(mem_dc);
 
 
-  // Paint everything else the background color.
-  FillRect(dc, &rect, WHITE_BRUSH);
+  return true;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -649,7 +742,7 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
 
 
   case WM_ERASEBKGND:
   case WM_ERASEBKGND:
     return true;
     return true;
-
+    
   case WM_PAINT:
   case WM_PAINT:
     {
     {
       PAINTSTRUCT ps;
       PAINTSTRUCT ps;
@@ -676,6 +769,21 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
       DrawText(dis->hDC, text_buffer, -1, &(dis->rcItem), 
       DrawText(dis->hDC, text_buffer, -1, &(dis->rcItem), 
                DT_VCENTER | DT_CENTER | DT_SINGLELINE);
                DT_VCENTER | DT_CENTER | DT_SINGLELINE);
     }
     }
+    return true;
+
+  case WM_MOUSEMOVE: 
+    set_mouse_data(LOWORD(lparam), HIWORD(lparam), _mouse_down);
+    break;
+
+  case WM_LBUTTONDOWN:
+    SetCapture(hwnd);
+    set_mouse_data(_mouse_x, _mouse_y, true);
+    break;
+
+  case WM_LBUTTONUP:
+    set_mouse_data(_mouse_x, _mouse_y, false);
+    ReleaseCapture();
+    break;
   };
   };
 
 
   return DefWindowProc(hwnd, msg, wparam, lparam);
   return DefWindowProc(hwnd, msg, wparam, lparam);
@@ -697,4 +805,17 @@ st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
   return ((P3DWinSplashWindow *)self)->window_proc(hwnd, msg, wparam, lparam);
   return ((P3DWinSplashWindow *)self)->window_proc(hwnd, msg, wparam, lparam);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DWinSplashWindow::WinImageData::dump_image
+//       Access: Public
+//  Description: Frees the previous image data.
+////////////////////////////////////////////////////////////////////
+void P3DWinSplashWindow::WinImageData::
+dump_image() {
+  if (_bitmap != NULL) {
+    DeleteObject(_bitmap);
+    _bitmap = NULL;
+  }
+}
+
 #endif  // _WIN32
 #endif  // _WIN32

+ 22 - 5
direct/src/plugin/p3dWinSplashWindow.h

@@ -48,6 +48,8 @@ private:
   void stop_thread();
   void stop_thread();
 
 
 private:
 private:
+  class WinImageData;
+
   // These methods run only within the window thread.
   // These methods run only within the window thread.
   void thread_run();
   void thread_run();
   static DWORD WINAPI win_thread_run(LPVOID data);
   static DWORD WINAPI win_thread_run(LPVOID data);
@@ -55,20 +57,36 @@ private:
   void make_window();
   void make_window();
   void make_progress_bar();
   void make_progress_bar();
   void update_install_label(const string &install_label);
   void update_install_label(const string &install_label);
-  void update_image_filename(const string &image_filename);
+  void update_image(WinImageData &image);
   void close_window();
   void close_window();
 
 
   void paint_window(HDC dc);
   void paint_window(HDC dc);
+  bool paint_image(HDC dc, const WinImageData &image);
   LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
   LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
   static LONG WINAPI st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
   static LONG WINAPI st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
 
 
 private:
 private:
+  class WinImageData : public ImageData {
+  public:
+    inline WinImageData();
+    inline ~WinImageData();
+    void dump_image();
+
+    string _filename;
+    bool _filename_changed;
+    HBITMAP _bitmap;
+  };
+
+  WinImageData _background_image;
+  WinImageData _button_ready_image;
+  WinImageData _button_rollover_image;
+  WinImageData _button_click_image;
+
   bool _got_install;
   bool _got_install;
-  bool _image_filename_changed;
-  string _image_filename;
   bool _install_label_changed;
   bool _install_label_changed;
   string _install_label;
   string _install_label;
   double _install_progress;
   double _install_progress;
+  ButtonState _drawn_bstate;
   LOCK _install_lock;
   LOCK _install_lock;
 
 
   bool _thread_continue;
   bool _thread_continue;
@@ -76,8 +94,7 @@ private:
   HANDLE _thread;
   HANDLE _thread;
   DWORD _thread_id;
   DWORD _thread_id;
   HWND _hwnd;
   HWND _hwnd;
-  HBITMAP _bitmap;
-  int _bitmap_width, _bitmap_height;
+
   HWND _progress_bar;
   HWND _progress_bar;
   HWND _text_label;
   HWND _text_label;