mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-17 12:12:10 -04:00
412 lines
13 KiB
C++
412 lines
13 KiB
C++
// Filename: p3dOsxSplashWindow.cxx
|
|
// Created by: drose (16Jul09)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
//
|
|
// All use of this software is subject to the terms of the revised BSD
|
|
// license. You should have received a copy of this license along
|
|
// with this source code in a file named "LICENSE."
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "p3dOsxSplashWindow.h"
|
|
|
|
#ifdef __APPLE__
|
|
|
|
#include <Carbon/Carbon.h>
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DOsxSplashWindow::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
P3DOsxSplashWindow::
|
|
P3DOsxSplashWindow(P3DInstance *inst) :
|
|
P3DSplashWindow(inst)
|
|
{
|
|
_image = NULL;
|
|
_image_data = NULL;
|
|
_install_progress = 0;
|
|
_got_wparams = false;
|
|
_toplevel_window = NULL;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DOsxSplashWindow::Destructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
P3DOsxSplashWindow::
|
|
~P3DOsxSplashWindow() {
|
|
if (_toplevel_window != NULL) {
|
|
SetWRefCon(_toplevel_window, 0);
|
|
HideWindow(_toplevel_window);
|
|
DisposeWindow(_toplevel_window);
|
|
_toplevel_window = NULL;
|
|
}
|
|
|
|
if (_image != NULL) {
|
|
DisposeGWorld(_image);
|
|
}
|
|
|
|
if (_image_data != NULL) {
|
|
delete[] _image_data;
|
|
_image_data = NULL;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DOsxSplashWindow::set_wparams
|
|
// Access: Public, Virtual
|
|
// Description: Changes the window parameters, e.g. to resize or
|
|
// reposition the window; or sets the parameters for the
|
|
// first time, creating the initial window.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DOsxSplashWindow::
|
|
set_wparams(const P3DWindowParams &wparams) {
|
|
P3DSplashWindow::set_wparams(wparams);
|
|
_got_wparams = true;
|
|
|
|
if (_wparams.get_window_type() == P3D_WT_toplevel ||
|
|
_wparams.get_window_type() == P3D_WT_fullscreen) {
|
|
// Creating a toplevel splash window.
|
|
if (_toplevel_window == NULL) {
|
|
Rect r;
|
|
r.top = _wparams.get_win_y();
|
|
r.left = _wparams.get_win_x();
|
|
if (r.top == 0 && r.left == 0) {
|
|
// These are the same defaults used by Panda's osxGraphicsWindow.
|
|
r.top = 50;
|
|
r.left = 10;
|
|
}
|
|
|
|
r.right = r.left + _wparams.get_win_width();
|
|
r.bottom = r.top + _wparams.get_win_height();
|
|
WindowAttributes attrib =
|
|
kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute;
|
|
CreateNewWindow(kDocumentWindowClass, attrib, &r, &_toplevel_window);
|
|
|
|
EventHandlerRef application_event_ref_ref1;
|
|
EventTypeSpec list1[] = {
|
|
{ kEventClassWindow, kEventWindowDrawContent },
|
|
//{ kEventClassWindow, kEventWindowUpdate },
|
|
};
|
|
|
|
EventHandlerUPP gEvtHandler = NewEventHandlerUPP(st_event_callback);
|
|
InstallWindowEventHandler(_toplevel_window, gEvtHandler,
|
|
GetEventTypeCount(list1), list1, this, &application_event_ref_ref1);
|
|
|
|
ProcessSerialNumber psn = { 0, kCurrentProcess };
|
|
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
|
|
SetFrontProcess(&psn);
|
|
|
|
ShowWindow(_toplevel_window);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DOsxSplashWindow::set_image_filename
|
|
// Access: Public, Virtual
|
|
// Description: Specifies the name of a JPEG image file that is
|
|
// displayed in the center of the splash window. If
|
|
// image_filename_temp is true, the file is immediately
|
|
// deleted after it has been read.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DOsxSplashWindow::
|
|
set_image_filename(const string &image_filename,
|
|
bool image_filename_temp) {
|
|
int num_channels;
|
|
string data;
|
|
if (!read_image(image_filename, image_filename_temp,
|
|
_image_height, _image_width, num_channels, data)) {
|
|
return;
|
|
}
|
|
|
|
QDErr err;
|
|
Rect src_rect = { 0, 0, _image_height, _image_width };
|
|
|
|
if (_image != NULL) {
|
|
DisposeGWorld(_image);
|
|
_image = NULL;
|
|
}
|
|
|
|
if (_image_data != NULL) {
|
|
delete[] _image_data;
|
|
_image_data = NULL;
|
|
}
|
|
|
|
// Now we need to copy from the RGB source image into the BGRA target image.
|
|
int row_stride = _image_width * num_channels;
|
|
int new_row_stride = _image_width * 4;
|
|
_image_data = new char[new_row_stride * _image_height];
|
|
for (int yi = 0; yi < _image_height; ++yi) {
|
|
char *dest = _image_data + yi * new_row_stride;
|
|
const char *source = data.data() + yi * row_stride;
|
|
for (int xi = 0; xi < _image_width; ++xi) {
|
|
char r = source[0];
|
|
char g = source[1];
|
|
char b = source[2];
|
|
#ifndef __BIG_ENDIAN__
|
|
// Little-endian.
|
|
dest[0] = b;
|
|
dest[1] = g;
|
|
dest[2] = r;
|
|
dest[3] = 0xff;
|
|
#else // __BIG_ENDIAN__
|
|
// Big-endian.
|
|
dest[0] = 0xff;
|
|
dest[1] = r;
|
|
dest[2] = g;
|
|
dest[3] = b;
|
|
#endif // __BIG_ENDIAN__
|
|
source += 3;
|
|
dest += 4;
|
|
}
|
|
}
|
|
|
|
err = NewGWorldFromPtr(&_image, k32BGRAPixelFormat, &src_rect, 0, 0, 0,
|
|
_image_data, new_row_stride);
|
|
if (err != noErr) {
|
|
nout << " error in NewGWorldFromPtr, called from set_image_filename()\n";
|
|
return;
|
|
}
|
|
|
|
refresh();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DOsxSplashWindow::set_install_label
|
|
// Access: Public, Virtual
|
|
// Description: Specifies the text that is displayed above the
|
|
// install progress bar.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DOsxSplashWindow::
|
|
set_install_label(const string &install_label) {
|
|
_install_label = install_label;
|
|
refresh();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DOsxSplashWindow::set_install_progress
|
|
// Access: Public, Virtual
|
|
// Description: Moves the install progress bar from 0.0 to 1.0.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DOsxSplashWindow::
|
|
set_install_progress(double install_progress) {
|
|
if ((int)(install_progress * 500.0) != (int)(_install_progress * 500.0)) {
|
|
// Only request a refresh if we're changing substantially.
|
|
refresh();
|
|
}
|
|
_install_progress = install_progress;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DOsxSplashWindow::handle_event
|
|
// Access: Public, Virtual
|
|
// Description: Deals with the event callback from the OS window
|
|
// system. Returns true if the event is handled, false
|
|
// if ignored.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool P3DOsxSplashWindow::
|
|
handle_event(P3D_event_data event) {
|
|
EventRecord *er = event._event;
|
|
if (er->what == updateEvt) {
|
|
paint_window();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DOsxSplashWindow::refresh
|
|
// Access: Private
|
|
// Description: Requests that the window will be repainted.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DOsxSplashWindow::
|
|
refresh() {
|
|
if (_toplevel_window != NULL) {
|
|
int win_width = _wparams.get_win_width();
|
|
int win_height = _wparams.get_win_height();
|
|
|
|
Rect r = { 0, 0, win_height, win_width };
|
|
InvalWindowRect(_toplevel_window, &r);
|
|
|
|
} else {
|
|
_inst->request_refresh();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DOsxSplashWindow::paint_window
|
|
// Access: Private
|
|
// Description: Redraws the current splash window.
|
|
////////////////////////////////////////////////////////////////////
|
|
void P3DOsxSplashWindow::
|
|
paint_window() {
|
|
if (!_got_wparams) {
|
|
return;
|
|
}
|
|
|
|
GrafPtr out_port = NULL;
|
|
GrafPtr portSave = NULL;
|
|
Boolean portChanged = false;
|
|
|
|
if (_toplevel_window != NULL) {
|
|
GetPort(&out_port);
|
|
|
|
} else {
|
|
out_port = _wparams.get_parent_window()._port;
|
|
portChanged = QDSwapPort(out_port, &portSave);
|
|
}
|
|
|
|
int win_width = _wparams.get_win_width();
|
|
int win_height = _wparams.get_win_height();
|
|
|
|
Rect r = { 0, 0, win_height, win_width };
|
|
ClipRect(&r);
|
|
EraseRect(&r);
|
|
|
|
if (_image != NULL) {
|
|
Rect src_rect = { 0, 0, _image_height, _image_width };
|
|
Rect dest_rect;
|
|
|
|
// Determine the relative size of image and window.
|
|
int win_cx = win_width / 2;
|
|
int win_cy = win_height / 2;
|
|
|
|
if (_image_width <= win_width && _image_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 - _image_width / 2;
|
|
int p_y = win_cy - _image_height / 2;
|
|
|
|
dest_rect.left = p_x;
|
|
dest_rect.top = p_y;
|
|
dest_rect.right = p_x + _image_width;
|
|
dest_rect.bottom = p_y + _image_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);
|
|
|
|
int p_x = win_cx - sc_width / 2;
|
|
int p_y = win_cy - sc_height / 2;
|
|
|
|
dest_rect.left = p_x;
|
|
dest_rect.top = p_y;
|
|
dest_rect.right = p_x + sc_width;
|
|
dest_rect.bottom = p_y + sc_height;
|
|
}
|
|
|
|
CopyBits(GetPortBitMapForCopyBits(_image),
|
|
GetPortBitMapForCopyBits(out_port),
|
|
&src_rect, &dest_rect, srcCopy, 0);
|
|
}
|
|
|
|
// Draw the progress bar. We don't draw this bar at all unless we
|
|
// have nonzero progress.
|
|
int bar_x, bar_y, bar_width, bar_height;
|
|
get_bar_placement(win_width, win_height,
|
|
bar_x, bar_y, bar_width, bar_height);
|
|
|
|
if (_install_progress != 0.0) {
|
|
int progress_width = (int)((bar_width - 2) * _install_progress);
|
|
int progress = bar_x + 1 + progress_width;
|
|
|
|
Rect rbar = { bar_y, bar_x, bar_y + bar_height, bar_x + bar_width };
|
|
Rect rneed = { bar_y + 1, progress, bar_y + bar_height - 1, bar_x + bar_width - 1 };
|
|
Rect rdone = { bar_y + 1, bar_x + 1, bar_y + bar_height - 1, progress };
|
|
FrameRect(&rbar);
|
|
|
|
RGBColor blue = { 27756, 42405, 57568 };
|
|
RGBForeColor(&blue);
|
|
PaintRect(&rdone);
|
|
EraseRect(&rneed);
|
|
|
|
RGBColor black = { 0, 0, 0 };
|
|
RGBForeColor(&black);
|
|
|
|
if (!_install_label.empty()) {
|
|
// Now draw the install_label right above it.
|
|
TextFont(0);
|
|
TextFace(bold);
|
|
TextMode(srcOr);
|
|
TextSize(0);
|
|
|
|
Point numer = { 1, 1 };
|
|
Point denom = { 1, 1 };
|
|
FontInfo font_info;
|
|
StdTxMeas(_install_label.size(), _install_label.data(), &numer, &denom, &font_info);
|
|
int ascent = font_info.ascent * numer.v / denom.v;
|
|
int descent = font_info.descent * numer.v / denom.v;
|
|
|
|
int text_width = TextWidth(_install_label.data(), 0, _install_label.size());
|
|
int text_x = (win_width - text_width) / 2;
|
|
int text_y = bar_y - descent - 8;
|
|
|
|
Rect rtext = { text_y - ascent - 2, text_x - 2,
|
|
text_y + descent + 2, text_x + text_width + 2 };
|
|
EraseRect(&rtext);
|
|
|
|
MoveTo(text_x, text_y);
|
|
DrawText(_install_label.data(), 0, _install_label.size());
|
|
}
|
|
}
|
|
|
|
if (_toplevel_window == NULL) {
|
|
if (portChanged) {
|
|
QDSwapPort(portSave, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DOsxSplashWindow::st_event_callback
|
|
// Access: Private, Static
|
|
// Description: The event callback on the toplevel window.
|
|
////////////////////////////////////////////////////////////////////
|
|
pascal OSStatus P3DOsxSplashWindow::
|
|
st_event_callback(EventHandlerCallRef my_handler, EventRef event,
|
|
void *user_data) {
|
|
return ((P3DOsxSplashWindow *)user_data)->event_callback(my_handler, event);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: P3DOsxSplashWindow::event_callback
|
|
// Access: Private
|
|
// Description: The event callback on the toplevel window.
|
|
////////////////////////////////////////////////////////////////////
|
|
OSStatus P3DOsxSplashWindow::
|
|
event_callback(EventHandlerCallRef my_handler, EventRef event) {
|
|
OSStatus result = eventNotHandledErr;
|
|
|
|
WindowRef window = NULL;
|
|
UInt32 the_class = GetEventClass(event);
|
|
UInt32 kind = GetEventKind(event);
|
|
|
|
GetEventParameter(event, kEventParamWindowRef, typeWindowRef, NULL,
|
|
sizeof(WindowRef), NULL, (void*) &window);
|
|
switch (the_class) {
|
|
case kEventClassWindow:
|
|
switch (kind) {
|
|
case kEventWindowDrawContent:
|
|
paint_window();
|
|
result = noErr;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
#endif // __APPLE__
|