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.
810 lines
30 KiB
810 lines
30 KiB
15 years ago
|
|
||
|
from qt import *
|
||
|
from kdecore import *
|
||
|
from kdeui import *
|
||
|
import os
|
||
|
from displayconfigabstraction import *
|
||
|
|
||
|
# Running as the root user or not?
|
||
|
isroot = os.getuid()==0
|
||
|
|
||
|
############################################################################
|
||
|
class ResizeSlider(QVGroupBox):
|
||
|
""" An abstracted QSlider in a nice box to change the resolution of a screen """
|
||
|
def __init__(self,parent):
|
||
|
# Screen size group
|
||
|
QVGroupBox.__init__(self,parent)
|
||
|
self.updating_gui = True
|
||
|
self._buildGUI()
|
||
|
self.updating_gui = False
|
||
|
|
||
|
def _buildGUI(self):
|
||
|
self.setTitle(i18n("Screen Size"))
|
||
|
self.setInsideSpacing(KDialog.spacingHint())
|
||
|
self.setInsideMargin(KDialog.marginHint())
|
||
|
|
||
|
hbox3 = QHBox(self)
|
||
|
hbox3.setSpacing(KDialog.spacingHint())
|
||
|
label = QLabel(hbox3,"textLabel2_4")
|
||
|
label.setText(i18n("Lower"))
|
||
|
self.screensizeslider = QSlider(hbox3,"slider1")
|
||
|
self.screensizeslider.setMinValue(0)
|
||
|
self.screensizeslider.setMaxValue(4)
|
||
|
self.screensizeslider.setPageStep(1)
|
||
|
self.screensizeslider.setOrientation(QSlider.Horizontal)
|
||
|
self.screensizeslider.setTickmarks(QSlider.Below)
|
||
|
self.connect(self.screensizeslider,SIGNAL("valueChanged(int)"),self.slotResolutionChange)
|
||
|
label = QLabel(hbox3)
|
||
|
label.setText(i18n("Higher"))
|
||
|
|
||
|
self.resolutionlabel = QLabel(self)
|
||
|
self.resolutionlabel.setText("640x400")
|
||
|
|
||
|
def setScreen(self, screen):
|
||
|
self.updating_gui = True
|
||
|
self.screen = screen
|
||
|
self.screensizeslider.setMaxValue(len(screen.getAvailableResolutions())-1)
|
||
|
self.screensizeslider.setValue(screen.getResolutionIndex())
|
||
|
self.updating_gui = False
|
||
|
self.setResolutionIndex(screen.getResolutionIndex())
|
||
|
|
||
|
def slotResolutionChange(self,i):
|
||
|
""" Pass signal from slider through to App """
|
||
|
if self.updating_gui:
|
||
|
return
|
||
|
self.setResolutionIndex(i)
|
||
|
self.emit(PYSIGNAL("resolutionChange(int)"),(i,))
|
||
|
|
||
|
def setMaxValue(self,value):
|
||
|
self.updating_gui = True
|
||
|
self.screensizeslider.setMaxValue(value)
|
||
|
self.updating_gui = False
|
||
|
|
||
|
def setMinValue(self,value):
|
||
|
self.updating_gui = True
|
||
|
self.screensizeslider.setMinValue(value)
|
||
|
self.updating_gui = False
|
||
|
|
||
|
def setValue(self,value):
|
||
|
self.updating_gui = True
|
||
|
self.screensizeslider.setValue(value)
|
||
|
self.updating_gui = False
|
||
|
|
||
|
def value(self):
|
||
|
return self.screensizeslider.value()
|
||
|
|
||
|
def setResolutionLabel(self,text):
|
||
|
self.resolutionlabel.setText(text)
|
||
|
|
||
|
def setResolutionIndex(self,i):
|
||
|
self.updating_gui = True
|
||
|
width,height = self.screen.getAvailableResolutions()[i]
|
||
|
self.setResolutionLabel(i18n("%1 x %2").arg(width).arg(height))
|
||
|
self.updating_gui = False
|
||
|
|
||
|
############################################################################
|
||
|
class MonitorPreview(QWidget):
|
||
|
""" A ResizableMonitor is an Image in a grid which has resizable edges,
|
||
|
fixed-size corners and is thus expandable. """
|
||
|
ROTATE_0 = 0
|
||
|
ROTATE_90 = 1
|
||
|
ROTATE_180 = 2
|
||
|
ROTATE_270 = 3
|
||
|
|
||
|
def __init__(self, parent=None, imagedir="", name=None):
|
||
|
QWidget.__init__(self,parent)
|
||
|
|
||
|
self.rotation = MonitorPreview.ROTATE_0
|
||
|
|
||
|
self.screen_width = 1280
|
||
|
self.screen_height = 1024
|
||
|
|
||
|
self.reflect_x = False
|
||
|
self.reflect_y = False
|
||
|
|
||
|
self.setBackgroundMode(Qt.NoBackground)
|
||
|
|
||
|
self.imagedir = imagedir + "monitor_resizable/"
|
||
|
|
||
|
self.image_monitor = QPixmap(self.imagedir+"monitor.png")
|
||
|
self.image_monitor_wide = QPixmap(self.imagedir+"monitor_wide.png")
|
||
|
self.image_monitor_r90 = QPixmap(self.imagedir+"monitor_r90.png")
|
||
|
self.image_monitor_wide_r90 = QPixmap(self.imagedir+"monitor_wide_r90.png")
|
||
|
|
||
|
self.image_background = QPixmap(self.imagedir+"background.png")
|
||
|
self.image_background_wide = QPixmap(self.imagedir+"background_wide.png")
|
||
|
self.image_background_r90 = QPixmap(self.imagedir+"background_r90.png")
|
||
|
self.image_background_wide_r90 = QPixmap(self.imagedir+"background_wide_r90.png")
|
||
|
|
||
|
self.image_window = QPixmap(self.imagedir+"window_4th.png")
|
||
|
self.image_window_bottom_left = QPixmap(self.imagedir+"window_bottom_left_4th.png")
|
||
|
self.image_window_bottom_right = QPixmap(self.imagedir+"window_bottom_right_4th.png")
|
||
|
|
||
|
def sizeHint(self):
|
||
|
max_width = max(self.image_monitor.width(), self.image_monitor_wide.width(),
|
||
|
self.image_monitor_r90.width(), self.image_monitor_wide_r90.width())
|
||
|
max_height = max(self.image_monitor.height(), self.image_monitor_wide.height(),
|
||
|
self.image_monitor_r90.height(), self.image_monitor_wide_r90.height())
|
||
|
return QSize(max_width, max_height)
|
||
|
|
||
|
def sizePolicy(self):
|
||
|
return QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
||
|
|
||
|
def paintEvent(self,paint_event):
|
||
|
screen_width = self.screen_width
|
||
|
screen_height = self.screen_height
|
||
|
|
||
|
# Widescreen format: preview width: 176, height: 99, 16:9
|
||
|
is_wide = abs(float(screen_width)/float(screen_height)-16.0/9.0) < 0.2
|
||
|
|
||
|
if not is_wide:
|
||
|
preview_screen_width = 152
|
||
|
preview_screen_height = 114
|
||
|
else:
|
||
|
preview_screen_width = 176
|
||
|
preview_screen_height = 99
|
||
|
|
||
|
if self.rotation==MonitorPreview.ROTATE_0 or self.rotation==MonitorPreview.ROTATE_180:
|
||
|
# Normal, landscape orientation.
|
||
|
if not is_wide:
|
||
|
screen_x_offset = 23
|
||
|
screen_y_offset = 15
|
||
|
image_background = self.image_background
|
||
|
else:
|
||
|
screen_x_offset = 23
|
||
|
screen_y_offset = 29
|
||
|
image_background = self.image_background_wide
|
||
|
else:
|
||
|
# Portrait orientation. Swap some values around.
|
||
|
t = preview_screen_width
|
||
|
preview_screen_width = preview_screen_height
|
||
|
preview_screen_height = t
|
||
|
|
||
|
t = screen_width
|
||
|
screen_width = screen_height
|
||
|
screen_height = t
|
||
|
|
||
|
if not is_wide:
|
||
|
screen_x_offset = 42
|
||
|
screen_y_offset = 15
|
||
|
image_background = self.image_background_r90
|
||
|
else:
|
||
|
screen_x_offset = 50
|
||
|
screen_y_offset = 15
|
||
|
image_background = self.image_background_wide_r90
|
||
|
|
||
|
# Draw everything off screen in a buffer
|
||
|
preview_buffer = QPixmap(preview_screen_width,preview_screen_height)
|
||
|
painter = QPainter(preview_buffer)
|
||
|
|
||
|
# Draw the background on the monitor's screen
|
||
|
painter.drawPixmap(0, 0, image_background)
|
||
|
|
||
|
# Work out the scaling factor for the eye candy in the preview winodw.
|
||
|
scale_factor = 4.0*float(preview_screen_width) / float(screen_width)
|
||
|
transform_matrix = QWMatrix().scale(scale_factor,scale_factor)
|
||
|
|
||
|
# Draw the little window on the background
|
||
|
scaled_window = self.image_window.xForm(transform_matrix)
|
||
|
|
||
|
sx = (preview_screen_width-scaled_window.width())/2
|
||
|
sy = (preview_screen_height-scaled_window.height())/2
|
||
|
if sx < 0:
|
||
|
sx = 0
|
||
|
if sy < 0:
|
||
|
sy = 0
|
||
|
sw = scaled_window.width()
|
||
|
if sw>preview_screen_width:
|
||
|
sw = preview_screen_width
|
||
|
|
||
|
sh = scaled_window.height()
|
||
|
if sh>preview_screen_height:
|
||
|
sh = preview_screen_height
|
||
|
|
||
|
painter.drawPixmap(sx, sy, scaled_window, 0, 0, sw, sh)
|
||
|
|
||
|
# Now draw the clock in the lower right corner
|
||
|
scaled_window = self.image_window_bottom_right.xForm(transform_matrix)
|
||
|
|
||
|
sx = preview_screen_width - scaled_window.width()
|
||
|
sy = preview_screen_height - scaled_window.height()
|
||
|
sw = scaled_window.width()#preview_screen_width/2
|
||
|
sh = scaled_window.height()
|
||
|
|
||
|
sx_offset = 0
|
||
|
if sx<0: # Some simple clipping for the left edge
|
||
|
sx_offset = -sx
|
||
|
sw = preview_screen_width
|
||
|
sx = 0
|
||
|
|
||
|
painter.drawPixmap(sx, sy, scaled_window, sx_offset, 0, sw, sh)
|
||
|
|
||
|
# Now draw the k menu in the lower left corner
|
||
|
scaled_window = self.image_window_bottom_left.xForm(transform_matrix)
|
||
|
|
||
|
sx = 0
|
||
|
sy = preview_screen_height - scaled_window.height()
|
||
|
sw = preview_screen_width/2 # Just draw on the left side of the preview.
|
||
|
sh = scaled_window.height()
|
||
|
painter.drawPixmap(sx, sy, scaled_window, 0, 0, sw, sh)
|
||
|
painter.end()
|
||
|
|
||
|
# Transform the preview image. Do reflections.
|
||
|
reflect_x = 1
|
||
|
if self.reflect_x:
|
||
|
reflect_x = -1
|
||
|
reflect_y = 1
|
||
|
if self.reflect_y:
|
||
|
reflect_y = -1
|
||
|
|
||
|
preview_buffer = preview_buffer.xForm(QWMatrix().scale(reflect_x,reflect_y))
|
||
|
|
||
|
# Draw the monitor on another buffer.
|
||
|
off_screen_buffer = QPixmap(self.width(),self.height())
|
||
|
off_screen_painter = QPainter(off_screen_buffer)
|
||
|
|
||
|
# Erase the buffer first
|
||
|
off_screen_painter.setBackgroundColor(self.paletteBackgroundColor())
|
||
|
off_screen_painter.eraseRect(0, 0, off_screen_buffer.width(), off_screen_buffer.height())
|
||
|
|
||
|
if self.rotation==MonitorPreview.ROTATE_0 or self.rotation==MonitorPreview.ROTATE_180:
|
||
|
if not is_wide:
|
||
|
image_monitor = self.image_monitor
|
||
|
else:
|
||
|
image_monitor = self.image_monitor_wide
|
||
|
else:
|
||
|
if not is_wide:
|
||
|
image_monitor = self.image_monitor_r90
|
||
|
else:
|
||
|
image_monitor = self.image_monitor_wide_r90
|
||
|
|
||
|
top_edge = self.height()-image_monitor.height()
|
||
|
left_edge = (self.width()-image_monitor.width())/2
|
||
|
|
||
|
# Draw the monitor
|
||
|
off_screen_painter.drawPixmap(left_edge, top_edge, image_monitor)
|
||
|
off_screen_painter.end()
|
||
|
|
||
|
# Copy the preview onto the off screen buffer with the monitor.
|
||
|
bitBlt(off_screen_buffer, left_edge+screen_x_offset, top_edge+screen_y_offset, preview_buffer,
|
||
|
0, 0, preview_buffer.width(), preview_buffer.height(),Qt.CopyROP, False)
|
||
|
|
||
|
# Update the widget
|
||
|
bitBlt(self, 0, 0, off_screen_buffer, 0, 0, self.width(), self.height(), Qt.CopyROP, False)
|
||
|
|
||
|
def setResolution(self,width,height):
|
||
|
self.screen_width = width
|
||
|
self.screen_height = height
|
||
|
self.update()
|
||
|
|
||
|
def setRotation(self, rotation):
|
||
|
self.rotation = rotation
|
||
|
self.update()
|
||
|
|
||
|
def setReflectX(self, enable):
|
||
|
self.reflect_x = enable
|
||
|
self.update()
|
||
|
|
||
|
def setReflectY(self, enable):
|
||
|
self.reflect_y = enable
|
||
|
self.update()
|
||
|
|
||
|
############################################################################
|
||
|
class DualMonitorPreview(QWidget):
|
||
|
""" This is the Widget to use elsewhere. It consists of a canvas and an
|
||
|
arbitrary number of gizmos on the canvas. The gizmos can be dragged and
|
||
|
dropped around. Painting is double-buffered so flickering should not occur.
|
||
|
"""
|
||
|
def __init__(self, parent, size, imagedir):
|
||
|
QWidget.__init__(self,parent)
|
||
|
self.setBackgroundMode(Qt.NoBackground)
|
||
|
|
||
|
self.imagedir = imagedir + "dualhead/"
|
||
|
self.snap_distance = 25
|
||
|
self.snapping = True
|
||
|
self.size = size
|
||
|
self.position = XSetup.POSITION_LEFTOF
|
||
|
|
||
|
self.current_screen = 0
|
||
|
|
||
|
self.resize(size,size)
|
||
|
self.setMouseTracking(True)
|
||
|
|
||
|
self.gizmos = []
|
||
|
self.gizmos.append(MovingGizmo("Monitor 1","monitor_1.png",QPoint(20,50),self.imagedir))
|
||
|
self.gizmos.append(MovingGizmo("Monitor 2","monitor_2.png",QPoint(180,50),self.imagedir))
|
||
|
|
||
|
self.gizmos[0].setWidth(1280)
|
||
|
self.gizmos[0].setHeight(1024)
|
||
|
self.gizmos[0].setHighlightColor(self.colorGroup().highlight())
|
||
|
self.gizmos[1].setWidth(1280)
|
||
|
self.gizmos[1].setHeight(1024)
|
||
|
self.gizmos[1].setHighlightColor(self.colorGroup().highlight())
|
||
|
|
||
|
self.dragging = False
|
||
|
self.dragging_gizmo = 0
|
||
|
self.drag_handle = None
|
||
|
|
||
|
self._positionGizmos()
|
||
|
self.setCurrentScreen(0)
|
||
|
|
||
|
def minimumSizeHint(self):
|
||
|
return QSize(self.size,self.size)
|
||
|
|
||
|
def setCurrentScreen(self,screen):
|
||
|
self.current_screen = screen
|
||
|
self.gizmos[0].setHighlight(screen==0)
|
||
|
self.gizmos[1].setHighlight(screen==1)
|
||
|
self.update()
|
||
|
|
||
|
def getCurrentScreen(self):
|
||
|
return self.current_screen
|
||
|
|
||
|
def setPosition(self,position):
|
||
|
self.position = position
|
||
|
self._positionGizmos()
|
||
|
self.update()
|
||
|
|
||
|
def getPosition(self):
|
||
|
"""Returns one of XSetup.POSITION_LEFTOF, XSetup.POSITION_RIGHTOF,
|
||
|
XSetup.POSITION_ABOVE or XSetup.POSITION_BELOW.
|
||
|
"""
|
||
|
return self.position
|
||
|
|
||
|
def setScreenResolution(self,screenNumber,width,height):
|
||
|
self.gizmos[screenNumber].setWidth(width)
|
||
|
self.gizmos[screenNumber].setHeight(height)
|
||
|
self.setPosition(self.position) # Reposition and force update.
|
||
|
|
||
|
def _positionGizmos(self):
|
||
|
g1 = self.gizmos[0]
|
||
|
g2 = self.gizmos[1]
|
||
|
|
||
|
# Treat POSITION_RIGHTOF and POSITION_BELOW as LEFTOF and ABOVE with the
|
||
|
# gizmos swapped around.
|
||
|
if self.position==XSetup.POSITION_RIGHTOF or self.position==XSetup.POSITION_BELOW:
|
||
|
tmp = g1
|
||
|
g1 = g2
|
||
|
g2 = tmp
|
||
|
|
||
|
if self.position==XSetup.POSITION_LEFTOF or self.position==XSetup.POSITION_RIGHTOF:
|
||
|
x = -g1.getWidth()
|
||
|
y = -max(g1.getHeight(), g2.getHeight())/2
|
||
|
g1.setPosition(QPoint(x,y))
|
||
|
|
||
|
x = 0
|
||
|
g2.setPosition(QPoint(x,y))
|
||
|
|
||
|
else:
|
||
|
x = -max(g1.getWidth(), g2.getWidth())/2
|
||
|
y = -g1.getHeight()
|
||
|
g1.setPosition(QPoint(x,y))
|
||
|
|
||
|
y = 0
|
||
|
g2.setPosition(QPoint(x,y))
|
||
|
|
||
|
def mousePressEvent(self,event):
|
||
|
# Translate the point in the window into our gizmo space.
|
||
|
world_point = self._getGizmoMatrix().invert()[0].map(event.pos())
|
||
|
|
||
|
# If the mouse is in the air space of a gizmo, then we change the cursor to
|
||
|
# indicate that the gizmo can be dragged.
|
||
|
for giz in self.gizmos:
|
||
|
if giz.getRect().contains(world_point):
|
||
|
self.setCurrentScreen(self.gizmos.index(giz))
|
||
|
break
|
||
|
else:
|
||
|
return
|
||
|
|
||
|
# Pressing down the mouse button on a gizmo also starts a drag operation.
|
||
|
self.dragging = True
|
||
|
self.dragging_gizmo = self.getCurrentScreen()
|
||
|
self.drag_handle = world_point - self.gizmos[self.dragging_gizmo].getPosition()
|
||
|
|
||
|
# Let other people know that a gizmo has been selected.
|
||
|
self.emit(PYSIGNAL("pressed()"), (self.current_screen,) )
|
||
|
|
||
|
def mouseReleaseEvent(self,event):
|
||
|
if not self.dragging:
|
||
|
return
|
||
|
|
||
|
# Translate the point in the window into our gizmo space.
|
||
|
world_point = self._getGizmoMatrix().invert()[0].map(event.pos())
|
||
|
|
||
|
if self._moveGizmo(world_point):
|
||
|
self.setPosition(self.drag_position)
|
||
|
self.emit(PYSIGNAL("positionChanged()"), (self.position,) )
|
||
|
else:
|
||
|
self.setPosition(self.position)
|
||
|
self.dragging = False
|
||
|
|
||
|
def mouseMoveEvent(self,event):
|
||
|
# Translate the point in the window into our gizmo space.
|
||
|
world_point = self._getGizmoMatrix().invert()[0].map(event.pos())
|
||
|
|
||
|
# If the mouse is in the air space of a gizmo, then we change the cursor to
|
||
|
# indicate that the gizmo can be dragged.
|
||
|
for giz in self.gizmos:
|
||
|
if giz.getRect().contains(world_point):
|
||
|
self.setCursor(QCursor(Qt.SizeAllCursor))
|
||
|
break
|
||
|
else:
|
||
|
self.unsetCursor()
|
||
|
|
||
|
if self.dragging:
|
||
|
self._moveGizmo(world_point)
|
||
|
self.update()
|
||
|
|
||
|
return
|
||
|
|
||
|
def _moveGizmo(self,worldPoint):
|
||
|
new_drag_position = worldPoint-self.drag_handle
|
||
|
|
||
|
# Drag gizmo is simply the thing being dragged.
|
||
|
drag_gizmo = self.gizmos[self.dragging_gizmo]
|
||
|
drag_x = new_drag_position.x()
|
||
|
drag_y = new_drag_position.y()
|
||
|
|
||
|
# Snap gizmo is other (stationary) thing that we "snap" against.
|
||
|
snap_gizmo = self.gizmos[1-self.dragging_gizmo]
|
||
|
snap_x = snap_gizmo.getPosition().x()
|
||
|
snap_y = snap_gizmo.getPosition().y()
|
||
|
|
||
|
# Calculate the list of "snap points".
|
||
|
snap_points = [
|
||
|
(snap_x-drag_gizmo.getWidth(), snap_y), # Left of
|
||
|
(snap_x+snap_gizmo.getWidth(), snap_y), # Right of
|
||
|
(snap_x, snap_y-drag_gizmo.getHeight()), # Above
|
||
|
(snap_x, snap_y+snap_gizmo.getHeight())] # Below
|
||
|
|
||
|
# Find the snap point that the drag gizmo is closest to.
|
||
|
best_index = -1
|
||
|
best_distance = 0
|
||
|
i = 0
|
||
|
for snap_point in snap_points:
|
||
|
dx = snap_point[0] - drag_x
|
||
|
dy = snap_point[1] - drag_y
|
||
|
distance_squared = dx*dx + dy*dy
|
||
|
if best_index==-1 or distance_squared < best_distance:
|
||
|
best_index = i
|
||
|
best_distance = distance_squared
|
||
|
i += 1
|
||
|
|
||
|
# Lookup the best dualhead position that this configuration matches.
|
||
|
if self.dragging_gizmo==0:
|
||
|
self.drag_position = [
|
||
|
XSetup.POSITION_LEFTOF,
|
||
|
XSetup.POSITION_RIGHTOF,
|
||
|
XSetup.POSITION_ABOVE,
|
||
|
XSetup.POSITION_BELOW][best_index]
|
||
|
else:
|
||
|
self.drag_position = [
|
||
|
XSetup.POSITION_RIGHTOF,
|
||
|
XSetup.POSITION_LEFTOF,
|
||
|
XSetup.POSITION_BELOW,
|
||
|
XSetup.POSITION_ABOVE][best_index]
|
||
|
|
||
|
# Convert the auto-snap distance in pixels into a distance in the gizmo coordinate system.
|
||
|
world_snap_distance = self.snap_distance / self._getGizmoToPixelsScaleFactor()
|
||
|
|
||
|
# Should this drag gizmo visually snap?
|
||
|
snapped = False
|
||
|
if best_distance <= (world_snap_distance*world_snap_distance):
|
||
|
new_drag_position = QPoint(snap_points[best_index][0],snap_points[best_index][1])
|
||
|
snapped = True
|
||
|
|
||
|
# Move the gizmo
|
||
|
self.gizmos[self.dragging_gizmo].setPosition(new_drag_position)
|
||
|
|
||
|
return snapped
|
||
|
|
||
|
def paintEvent(self,event=None):
|
||
|
QWidget.paintEvent(self,event)
|
||
|
|
||
|
# Paint to an off screen buffer first. Later we copy it to widget => flicker free.
|
||
|
off_screen_buffer = QPixmap(self.width(),self.height())
|
||
|
off_screen_painter = QPainter(off_screen_buffer)
|
||
|
|
||
|
# Erase the buffer first
|
||
|
off_screen_painter.setBackgroundColor(self.colorGroup().mid() )
|
||
|
off_screen_painter.eraseRect(0, 0, off_screen_buffer.width(), off_screen_buffer.height())
|
||
|
|
||
|
#
|
||
|
off_screen_painter.setWorldMatrix(self._getGizmoMatrix())
|
||
|
|
||
|
# Paint the non-selected gizmo first.
|
||
|
self.gizmos[ 1-self.current_screen ].paint(off_screen_painter)
|
||
|
|
||
|
# Now paint the selected gizmo
|
||
|
self.gizmos[self.current_screen].paint(off_screen_painter)
|
||
|
|
||
|
# Turn off the world matrix transform.
|
||
|
off_screen_painter.setWorldXForm(False)
|
||
|
|
||
|
# Draw the rounded border
|
||
|
off_screen_painter.setPen(QPen(self.colorGroup().dark(),1))
|
||
|
off_screen_painter.drawRoundRect(0,0,self.width(),self.height(),2,2)
|
||
|
|
||
|
off_screen_painter.end()
|
||
|
|
||
|
# Update the widget
|
||
|
bitBlt(self, 0, 0, off_screen_buffer, 0, 0, self.width(), self.height(), Qt.CopyROP, False)
|
||
|
|
||
|
def _getGizmoMatrix(self):
|
||
|
matrix = QWMatrix()
|
||
|
matrix.translate(self.width()/2,self.height()/2)
|
||
|
|
||
|
scale_factor = self._getGizmoToPixelsScaleFactor()
|
||
|
matrix.scale(scale_factor,scale_factor)
|
||
|
return matrix
|
||
|
|
||
|
def _getGizmoToPixelsScaleFactor(self):
|
||
|
g1 = self.gizmos[0]
|
||
|
g2 = self.gizmos[1]
|
||
|
size = min(self.width(),self.height())
|
||
|
vscale = float(self.height()) / (2.1 * (g1.getHeight()+g2.getHeight()))
|
||
|
hscale = float(self.width()) / (2.1 * (g1.getWidth()+g2.getWidth()))
|
||
|
return min(vscale,hscale)
|
||
|
|
||
|
############################################################################
|
||
|
class MovingGizmo(object):
|
||
|
"""A gizmo represents a screen/monitor. It also has a width and height that
|
||
|
correspond to the resolution of screen."""
|
||
|
|
||
|
def __init__(self,label,filename,initial_pos=QPoint(0,0),imagedir="."):
|
||
|
self.width = 100
|
||
|
self.height = 100
|
||
|
self.pixmap = QPixmap(imagedir+filename)
|
||
|
|
||
|
self.highlight = False
|
||
|
self.highlight_color = QColor(255,0,0)
|
||
|
|
||
|
self.setPosition(initial_pos)
|
||
|
|
||
|
# Used for caching the scaled pixmap.
|
||
|
self.scaled_width = -1
|
||
|
self.scaled_height = -1
|
||
|
|
||
|
def setHighlight(self,enable):
|
||
|
self.highlight = enable
|
||
|
|
||
|
def setHighlightColor(self,color):
|
||
|
self.highlight_color = color
|
||
|
|
||
|
def setPosition(self,position):
|
||
|
self.position = position
|
||
|
|
||
|
def getSize(self):
|
||
|
return QSize(self.width,self.height)
|
||
|
|
||
|
def getPosition(self):
|
||
|
return self.position
|
||
|
|
||
|
def getRect(self):
|
||
|
return QRect(self.position,self.getSize())
|
||
|
|
||
|
def setWidth(self,width):
|
||
|
self.width = width
|
||
|
|
||
|
def getWidth(self):
|
||
|
return self.width
|
||
|
|
||
|
def setHeight(self,height):
|
||
|
self.height = height
|
||
|
|
||
|
def getHeight(self):
|
||
|
return self.height
|
||
|
|
||
|
def paint(self,painter):
|
||
|
painter.save()
|
||
|
if self.highlight:
|
||
|
pen = QPen(self.highlight_color,6)
|
||
|
painter.setPen(pen)
|
||
|
|
||
|
painter.drawRect(self.position.x(), self.position.y(), self.width, self.height)
|
||
|
|
||
|
to_pixels_matrix = painter.worldMatrix()
|
||
|
top_left_pixels = to_pixels_matrix.map(self.position)
|
||
|
bottom_right_pixels = to_pixels_matrix.map( QPoint(self.position.x()+self.width, self.position.y()+self.height) )
|
||
|
|
||
|
# Scale the pixmap.
|
||
|
scaled_width = bottom_right_pixels.x() - top_left_pixels.x()
|
||
|
scaled_height = bottom_right_pixels.y() - top_left_pixels.y()
|
||
|
|
||
|
if (scaled_width,scaled_height) != (self.scaled_width,self.scaled_height):
|
||
|
scale_matrix = QWMatrix()
|
||
|
scale_matrix.scale(
|
||
|
float(scaled_width)/float(self.pixmap.width()),
|
||
|
float(scaled_height)/float(self.pixmap.height()) )
|
||
|
|
||
|
self.scaled_pixmap = self.pixmap.xForm(scale_matrix)
|
||
|
(self.scaled_width,self.scaled_height) = (scaled_width,scaled_height)
|
||
|
|
||
|
# Paste in the scaled pixmap.
|
||
|
bitBlt(painter.device(), top_left_pixels.x(), top_left_pixels.y(), self.scaled_pixmap, 0, 0,
|
||
|
self.scaled_pixmap.width(), self.scaled_pixmap.height(),Qt.CopyROP, False)
|
||
|
|
||
|
painter.restore()
|
||
|
|
||
|
############################################################################
|
||
|
class GfxCardWidget(QVGroupBox):
|
||
|
def __init__(self, parent, xsetup, gfxcard, gfxcarddialog, monitordialog):
|
||
|
global imagedir
|
||
|
QVGroupBox.__init__(self,parent)
|
||
|
|
||
|
self.xsetup = xsetup
|
||
|
self.gfxcard = gfxcard
|
||
|
self.gfxcarddialog = gfxcarddialog
|
||
|
self.monitordialog = monitordialog
|
||
|
self._buildGUI()
|
||
|
self._syncGUI()
|
||
|
|
||
|
def _buildGUI(self):
|
||
|
# Create the GUI
|
||
|
|
||
|
gridwidget = QWidget(self)
|
||
|
grid = QGridLayout(gridwidget,2+3*len(self.gfxcard.getScreens()))
|
||
|
grid.setSpacing(KDialog.spacingHint())
|
||
|
grid.setColStretch(0,0)
|
||
|
grid.setColStretch(1,0)
|
||
|
grid.setColStretch(2,0)
|
||
|
grid.setColStretch(3,1)
|
||
|
grid.setColStretch(4,0)
|
||
|
|
||
|
gfxcardpic = QLabel(gridwidget)
|
||
|
gfxcardpic.setPixmap(UserIcon('hi32-gfxcard'))
|
||
|
grid.addMultiCellWidget(gfxcardpic,0,1,0,0)
|
||
|
|
||
|
label = QLabel(gridwidget)
|
||
|
label.setText(i18n("Graphics card:"))
|
||
|
grid.addWidget(label,0,1)
|
||
|
|
||
|
self.gfxcardlabel = QLabel(gridwidget)
|
||
|
grid.addWidget(self.gfxcardlabel,0,2)
|
||
|
|
||
|
label = QLabel(gridwidget)
|
||
|
label.setText(i18n("Driver:"))
|
||
|
grid.addWidget(label,1,1)
|
||
|
|
||
|
self.driverlabel = QLabel(gridwidget)
|
||
|
grid.addMultiCellWidget(self.driverlabel,1,1,2,3)
|
||
|
|
||
|
gfxbutton = QPushButton(gridwidget)
|
||
|
gfxbutton.setText(i18n("Configure..."))
|
||
|
self.connect(gfxbutton,SIGNAL("clicked()"),self.slotGfxCardConfigureClicked)
|
||
|
grid.addWidget(gfxbutton,0,4)
|
||
|
gfxbutton.setEnabled(self.xsetup.mayModifyXorgConfig())
|
||
|
|
||
|
# Add all of the screens
|
||
|
row = 2
|
||
|
count = 1
|
||
|
self.monitorlabels = []
|
||
|
self.monitor_buttons = []
|
||
|
self.monitor_roles = []
|
||
|
for screen in self.gfxcard.getScreens():
|
||
|
frame = QFrame(gridwidget)
|
||
|
frame.setFrameShape(QFrame.HLine)
|
||
|
frame.setFrameShadow(QFrame.Sunken)
|
||
|
grid.addMultiCellWidget(frame,row,row,0,4)
|
||
|
row += 1
|
||
|
|
||
|
monitorpic = QLabel(gridwidget)
|
||
|
monitorpic.setPixmap(UserIcon('hi32-display'))
|
||
|
grid.addMultiCellWidget(monitorpic,row,row+1,0,0)
|
||
|
|
||
|
# Monitor label
|
||
|
label = QLabel(gridwidget)
|
||
|
if len(self.gfxcard.getScreens())==1:
|
||
|
label.setText(i18n("Monitor:"))
|
||
|
else:
|
||
|
label.setText(i18n("Monitor #%1:").arg(count))
|
||
|
grid.addWidget(label,row,1)
|
||
|
|
||
|
self.monitorlabels.append(QLabel(gridwidget))
|
||
|
grid.addMultiCellWidget(self.monitorlabels[-1],row,row,2,3)
|
||
|
|
||
|
# Role pulldown
|
||
|
if len(self.xsetup.getAllScreens())!=1:
|
||
|
label = QLabel(gridwidget)
|
||
|
label.setText(i18n("Role:"))
|
||
|
grid.addWidget(label,row+1,1)
|
||
|
|
||
|
role_combo = KComboBox(False,gridwidget)
|
||
|
role_combo.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
|
||
|
self.monitor_roles.append(role_combo)
|
||
|
role_combo.insertItem(i18n("Primary (1)"))
|
||
|
role_combo.insertItem(i18n("Secondary (2)"))
|
||
|
if len(self.xsetup.getAllScreens())>=3:
|
||
|
role_combo.insertItem(i18n("Unused"))
|
||
|
self.connect(role_combo,SIGNAL("activated(int)"),self.slotRoleSelected)
|
||
|
grid.addWidget(role_combo,row+1,2)
|
||
|
role_combo.setEnabled(self.xsetup.mayModifyXorgConfig())
|
||
|
|
||
|
monitorbutton = QPushButton(gridwidget)
|
||
|
self.monitor_buttons.append(monitorbutton)
|
||
|
monitorbutton.setText(i18n("Configure..."))
|
||
|
self.connect(monitorbutton,SIGNAL("clicked()"),self.slotMonitorConfigureClicked)
|
||
|
grid.addWidget(monitorbutton,row,4)
|
||
|
monitorbutton.setEnabled(self.xsetup.mayModifyXorgConfig())
|
||
|
row += 2
|
||
|
count += 1
|
||
|
|
||
|
def syncConfig(self):
|
||
|
self._syncGUI()
|
||
|
|
||
|
def _syncGUI(self):
|
||
|
if self.gfxcard.getGfxCardModel() is not None:
|
||
|
self.setTitle(self.gfxcard.getGfxCardModel().getName())
|
||
|
self.gfxcardlabel.setText(self.gfxcard.getGfxCardModel().getName())
|
||
|
|
||
|
if self.gfxcard.isProprietaryDriver():
|
||
|
try:
|
||
|
# Displayconfig thinks there is a proprietary driver
|
||
|
self.driverlabel.setText(self.gfxcard.getGfxCardModel().getProprietaryDriver())
|
||
|
except TypeError, errormsg:
|
||
|
# If there isn't it dies, so try again LP: #198269
|
||
|
self.driverlabel.setText(self.gfxcard.getGfxCardModel().getDriver())
|
||
|
else:
|
||
|
self.driverlabel.setText(self.gfxcard.getGfxCardModel().getDriver())
|
||
|
else:
|
||
|
self.setTitle(i18n("<Unknown>"))
|
||
|
self.gfxcardlabel.setText(i18n("<Unknown>"))
|
||
|
self.driverlabel.setText(i18n("<none>"))
|
||
|
|
||
|
# Sync the screens and monitors.
|
||
|
for i in range(len(self.gfxcard.getScreens())):
|
||
|
screen = self.gfxcard.getScreens()[i]
|
||
|
|
||
|
if screen.getMonitorModel() is None:
|
||
|
monitor_name = i18n("<unknown>")
|
||
|
else:
|
||
|
monitor_name = QString(screen.getMonitorModel().getName())
|
||
|
if screen.getMonitorAspect()==ModeLine.ASPECT_16_9:
|
||
|
monitor_name.append(i18n(" (widescreen)"))
|
||
|
self.monitorlabels[i].setText(monitor_name)
|
||
|
|
||
|
if len(self.xsetup.getAllScreens())!=1:
|
||
|
self.monitor_roles[i].setCurrentItem(
|
||
|
{XSetup.ROLE_PRIMARY: 0,
|
||
|
XSetup.ROLE_SECONDARY: 1,
|
||
|
XSetup.ROLE_UNUSED: 2}
|
||
|
[self.xsetup.getScreenRole(screen)])
|
||
|
|
||
|
def slotGfxCardConfigureClicked(self):
|
||
|
result = self.gfxcarddialog.do(self.gfxcard.getGfxCardModel(), \
|
||
|
self.gfxcard.isProprietaryDriver(), self.gfxcard.getDetectedGfxCardModel(),
|
||
|
self.gfxcard.getVideoRam())
|
||
|
|
||
|
(new_card_model, new_proprietary_driver, new_video_ram) = result
|
||
|
|
||
|
if new_card_model is self.gfxcard.getGfxCardModel() and \
|
||
|
new_proprietary_driver==self.gfxcard.isProprietaryDriver() and \
|
||
|
new_video_ram==self.gfxcard.getVideoRam():
|
||
|
return
|
||
|
self.gfxcard.setGfxCardModel(new_card_model)
|
||
|
self.gfxcard.setProprietaryDriver(new_proprietary_driver)
|
||
|
self.gfxcard.setVideoRam(new_video_ram)
|
||
|
self._syncGUI()
|
||
|
self.emit(PYSIGNAL("configChanged"), () )
|
||
|
|
||
|
def slotMonitorConfigureClicked(self):
|
||
|
screen_index = self.monitor_buttons.index(self.sender())
|
||
|
screen_obj = self.gfxcard.getScreens()[screen_index]
|
||
|
|
||
|
(new_monitor_model,new_aspect) = self.monitordialog.do(screen_obj.getMonitorModel(),
|
||
|
screen_obj.getMonitorAspect(),
|
||
|
self.xsetup.getGfxCards()[0].getScreens()[0] is screen_obj)
|
||
|
|
||
|
screen_obj.setMonitorModel(new_monitor_model)
|
||
|
screen_obj.setMonitorAspect(new_aspect)
|
||
|
self._syncGUI()
|
||
|
self.emit(PYSIGNAL("configChanged"), () )
|
||
|
|
||
|
def slotRoleSelected(self,index):
|
||
|
screen_index = self.monitor_roles.index(self.sender())
|
||
|
screen_obj = self.gfxcard.getScreens()[screen_index]
|
||
|
self.xsetup.setScreenRole(screen_obj,[XSetup.ROLE_PRIMARY,XSetup.ROLE_SECONDARY,XSetup.ROLE_UNUSED][index])
|
||
|
|
||
|
self._syncGUI()
|
||
|
self.emit(PYSIGNAL("configChanged"), () )
|